關於 Vue 模板的語法,官方文檔作了比較詳細的介紹,建議讀者先閱讀完官網文檔再繼續閱讀本文後續內容。html
下面介紹一些比較特殊的或者說須要注意的點。vue
經過 v-bind
能夠給組件傳遞 prop
數據,好比有組件 A :node
<template> <div>...</div> </template> <script> export default { props: { name: String, age: Number, anotherProp: String } }; </script>
那麼給該組件傳遞 name
和 age
屬性就能夠寫成這樣:git
<A name="yibuyisheng" :age="27" :another-prop="'test'"></A>
注意,在傳遞 prop
數據的時候,模板裏面的鍵名和聲明處的鍵名對應是有講究的:在模板裏面,要麼嚴格按照聲明處的大小寫,要麼按照聲明處的鍵名通過相似於 lodash
中 snakeCase 轉換以後的形式書寫。github
好比對於聲明處的 anotherProp
屬性,在模板裏面對應寫上 <A :anotherProp="'test'"></A>
或者 <A :another-prop="'test'"></A>
,是沒有問題的。算法
若是寫成 <A :another-Prop="'test'"></A>
或者 <A another-Prop="test"></A>
,就會對應失敗。(後面一種寫法會在 DOM 樹中看到 another-prop attribute
)typescript
雖然,大部分時候,都不用太去關心模板標籤和屬性的大小寫問題(畢竟絕大多數時候寫的都是 HTML
模板),可是有的屬性,仍是要當心處理大小寫問題的,好比 svg
的 viewBox
屬性: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-bind
的 prop
修飾符,能夠直接給相應的 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 邏輯有不少文章都作了介紹,能夠參看這篇文章。
此處主要強調因爲 diff 算法,而形成的寫模板必須注意的點。
官方有一些關於 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
就是子組件狀態。
基本全部未受 Vue prop
控制的,可是自身又能隨交互變化的狀態,都算做臨時 DOM 狀態。好比不受控制的 input.value
、 input.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--
若是去掉 KeyComponent
中 Item
的 key
屬性設置,而後刷新頁面,第一次點擊 KeyCOmponent
組件中的按鈕,輸出結果爲:
123 --1-- 789 --2-- 456 --3--
能夠看出,只有加了正確的 key
,新插入的 768
組件纔會對應到新建立的組件。
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 的文章參見此處。