Vue 模板書寫注意點

關於 Vue 模板的語法,官方文檔作了比較詳細的介紹,建議讀者先閱讀完官網文檔再繼續閱讀本文後續內容。html

下面介紹一些比較特殊的或者說須要注意的點。vue

v-bind 綁定對象

經過 v-bind 能夠給組件傳遞 prop 數據,好比有組件 A :node

<template>
    <div>...</div>
</template>
<script>
export default {
    props: {
        name: String,
        age: Number,
        anotherProp: String
    }
};
</script>

那麼給該組件傳遞 nameage 屬性就能夠寫成這樣:git

<A name="yibuyisheng" :age="27" :another-prop="'test'"></A>

注意,在傳遞 prop 數據的時候,模板裏面的鍵名和聲明處的鍵名對應是有講究的:在模板裏面,要麼嚴格按照聲明處的大小寫,要麼按照聲明處的鍵名通過相似於 lodashsnakeCase 轉換以後的形式書寫。github

好比對於聲明處的 anotherProp 屬性,在模板裏面對應寫上 <A :anotherProp="'test'"></A> 或者 <A :another-prop="'test'"></A> ,是沒有問題的。算法

若是寫成 <A :another-Prop="'test'"></A> 或者 <A another-Prop="test"></A>,就會對應失敗。(後面一種寫法會在 DOM 樹中看到 another-prop attributetypescript

雖然,大部分時候,都不用太去關心模板標籤和屬性的大小寫問題(畢竟絕大多數時候寫的都是 HTML 模板),可是有的屬性,仍是要當心處理大小寫問題的,好比 svgviewBox 屬性:api

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
     width="150" height="100" viewBox="0 0 3 2">

  <rect width="1" height="2" x="0" fill="#008d46" />
  <rect width="1" height="2" x="1" fill="#ffffff" />
  <rect width="1" height="2" x="2" fill="#d2232c" />
</svg>

默認狀況下,對於傳遞的未聲明的屬性,都會採用 setAttribute 設置到相應 DOM 元素上面去,好比:app

<A some-prop="some value"></A>

這個 some-prop 會經過 setAttribute 設置到 A 組件根元素的屬性上面去。dom

而對於一些特殊屬性,是須要設置到 DOM 元素對象上去的,好比 input[type="checked"]checked 屬性。對於這些屬性, Vue 內部作了默認配置,固然也能夠經過全局的 Vue.config.mustUseProp 配置覆蓋默認配置。

另外,經過 v-bindprop 修飾符,能夠直接給相應的 DOM 節點對象設置屬性,好比:

<div v-bind:name-attr.prop="'haha'"></div>
<!-- 縮寫形式 -->
<div :name-attr.prop="'haha'"></div>

會被轉換成大體以下代碼:

// 屬性名作駝峯轉換
divElement.nameAttr = 'haha';

注意,以下形式寫法:

<div name-attr.prop="haha"></div>

會被轉換成大體以下代碼:

divElement.setAttribute('name-attr.prop', 'haha');

若是 div 換成 A 組件,那麼相應的屬性操做就會發生在 A 組件的根元素上面。

最後,經過 v-bind 能夠批量動態地設置屬性:

<div v-bind="{id: 'list', name: 'yibuyisheng'}"></div>
<!-- 等同於,可是上述優點在於「大量屬性」、「動態屬性鍵」 -->
<div id="list" name="yibuyisheng"></div>

Vue diff

Vue diff 邏輯有不少文章都作了介紹,能夠參看這篇文章

此處主要強調因爲 diff 算法,而形成的寫模板必須注意的點。

key

官方有一些關於 key介紹

在實際開發中, key 主要用於解決同級 DOM 元素複用引發的 bug ,以及作列表渲染優化。

在列表渲染中, Vue 會盡可能複用已有 DOM 節點元素。默認狀況下,對於被循環元素,會有 :key="index" 的設置,對於這中默認渲染模式,官網有一句很是很是重要的描述:

這個默認的模式是高效的,可是隻適用於不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。

有兩個須要搞清楚的點:

  • 什麼是子組件狀態?

    子組件狀態就是不受 prop 屬性控制的狀態。好比組件 B :

    <template>
        <div>{{ instanceCounter }}</div>
    </template>
    <script>
    let counter = 1;
    export default {
        data() {
            return {
                instanceCounter: counter++
            };
        }
    };
    </script>

    對於組件 B 來講, instanceCounter 就是子組件狀態。

  • 什麼是臨時 DOM 狀態?

    基本全部未受 Vue prop 控制的,可是自身又能隨交互變化的狀態,都算做臨時 DOM 狀態。好比不受控制的 input.valueinput.checked 等等。

從根本原理上來說,全部沒在 VNode 中的 data 屬性上表達的狀態,都算是相應組件或 DOM 節點的內部狀態,都會存在 key 風險

明確了上面兩個概念以後,咱們看一個例子:

import Vue from 'vue';
import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options';

let counter = 1;
const Item: ThisTypedComponentOptionsWithRecordProps<Vue, {instanceCounter: number;}, {}, {}, {}> = {
    template: '<div class="item"><slot></slot> --{{ instanceCounter }}--</div>',
    data() {
        return {
            instanceCounter: counter++
        };
    }
};
Vue.component('Item', Item);

const KeyComponent: ThisTypedComponentOptionsWithRecordProps<Vue, {items: Array<{id: string;}>;}, {}, {}, {}> = {
    template: `
        <div>
            <Item v-for="item in items" @click="handle1" :key="item.id">{{ item.id }}</Item>
            <button @click="add">+</button>
        </div>
    `,
    data() {
        return {
            items: [
                {
                    id: '123'
                },
                {
                    id: '456'
                }
            ]
        };
    },
    methods: {
        add() {
            this.items.splice(1, 0, {
                id: '789'
            });
        }
    }
};

Vue.component('KeyComponent', KeyComponent);

new Vue({
    el: '#app',
    template: '<KeyComponent />'
});

在第一次點擊 KeyComponent 組件中的按鈕以後,輸出結果爲:

123 --1--
789 --3--
456 --2--

若是去掉 KeyComponentItemkey 屬性設置,而後刷新頁面,第一次點擊 KeyCOmponent 組件中的按鈕,輸出結果爲:

123 --1--
789 --2--
456 --3--

能夠看出,只有加了正確的 key ,新插入的 768 組件纔會對應到新建立的組件。

render

render 方法必需要返回一個 VNode 實例。

若是想返回一個文本節點怎麼辦呢?

能夠藉助於 createElement() 實現:

import Vue from 'vue';
import { ThisTypedComponentOptionsWithRecordProps } from 'vue/types/options';

const Test: ThisTypedComponentOptionsWithRecordProps<Vue, {}, {}, {}, {}> = {
    render(createElement) {
        const nodes = createElement('div', '文本內容').children;
        if (!nodes) {
            throw new Error('error');
        }
        return nodes[0];
    }
};
Vue.component('Test', Test);

更多關於 Vue 的文章參見此處

相關文章
相關標籤/搜索