深入理解vue元件
在 html
語法中, table
標籤內就必須是 tr
標籤, tr
標籤下就必須是 td
標籤, ul
標籤下就必須是li標籤 等等 標籤間的巢狀規則
在運用元件的時候,會出現想在這個標籤內使用元件,但這個標籤內並不支援的情況,如下
<div id="app"> <table> <tbody> <tr> <td>thisis a row</td> </tr> <tr> <td>thisis a row</td> </tr> <tr> <td>thisis a row</td> </tr> </tbody> </table> </div> 複製程式碼
我們看到 tr
標籤這一部分重複了幾次,我們可以試著用元件的方式,寫出它,如下
<div id="app"> <table> <tbody> <row></row> <row></row> <row></row> </tbody> </table> </div> <script> Vue.component("row", { template:"<tr><td>this is a row</td></tr>" }); var app = new Vue({ el: "#app" }); </script> 複製程式碼
然後,我們開啟瀏覽器測試下,

雖然展示結果一樣,但我們可以看待 tr
這部分標籤出現在了 table
標籤外部,這就是 table
標籤不支援內部巢狀 不是 tr
標籤的情況
這時候,我們就可以使用is了
<table> <tbody> <tr is="row"></tr>//採用table內支援的標籤,is後面接元件的名字 </tbody> </table> 複製程式碼
這裡就不貼圖了,這時,table標籤的巢狀就正常了
元件中data的使用
在子元件中,data必須是一個函式,並且該函式要返回一個物件
這是因為子元件會重複使用,而他們之間需要有獨立資料儲存記憶體,這樣資料才不會互相影響,如果在元件中data是一個物件,那麼,所有元件的資料都指向同一塊記憶體。
需要操作dom例項時,$refs出現了
如果你需要在父元件中,直接訪問子元件的例項
可以通過 ref
給子元件加個id
ref="one"
然後父元件中,這樣訪問
this.$refs.one
現在我們用 ref
來做個小例子

當我們點選上面的兩個小數,會自增,最下的數字是兩個小數是總回
子元件程式碼
Vue.component("count",{ data:function(){ return { number:0, } }, template:"<div @click='add'>{{number}}</div>", methods:{ add:function(){ this.number++; this.$emit("change")//當被點選時,會觸發父元件的change事件 } } }) 複製程式碼
html程式碼
<div id="app"> <count ref="one" @change="allNum"></count>//用ref給子元件設定一個id,one <count ref="two" @change="allNum"></count> <div>{{all}}</div> </div> 複製程式碼
父元件程式碼
var app = new Vue({ el:"#app", data:{ all:0 }, methods:{ allNum:function(){ this.all=this.$refs.one.number+this.$refs.two.number; //在父元件中,可以通過this.$refs.ref來獲取子元件的例項, } } }) 複製程式碼
二、父子元件間的傳值
父元件想要給子元件傳值,必須在呼叫子元件的html上寫上要傳值的屬性名和值,如下
<count :count="3"></count>
這裡要注意 :屬性名
後面接的都是一個js表示式,所以這裡的3是一個數值型別
而在子元件中,要接受父元件的傳值,則必須在 propps:[]
中加一個同樣的屬性名, props:["count"]
重點,在這裡要注意vue的單向資料流概念,就是父元件可以給子元件傳值, 但子元件不能隨意直接修改父元件傳過來的值,必須先將父元件傳過來的值複製一份,放在子元件的data中後,然後對data中的值進行修改
如下
Vue.component("count",{ props:['count'], data:function(){ return { number:this.count } } }) 複製程式碼
如上,只能對父元件傳過來的值的 副本 進行操作,這是因為,傳進的是 基礎資料型別 還好,如果父元件傳遞的是一個 引用型 的資料,那麼子元件直接改動這個資料,就有可能對其他引用該資料的元件造成干擾
子元件給父元件傳值,要藉助$emit去觸發父元件自定義的事件,
this.$emit("change",1)
;change是父元件自定義的事件,而1,就是我們要傳遞的值了,
現在我們來利用父子元件的傳值,做一個簡單的計數器
<div id="app"> <count :count="one" @change="allNum"></count> //@change是父元件自定義的事件,觸發了change//就會去執行allNum函式 <count :count="two" @change="allNum"></count> //:count 是要傳遞的屬性名,two是要傳遞的值,在data中,two對應0; {{all}} </div> <script> var count = { props:['count'],//用count來接受父元件傳遞過來的值 data:function(){ return { number:this.count,//記得單項資料流,要將父元件的傳值,複製一份,放在子元件data中 } }, template:'<div @click="add">{{number}}</div>', methods:{ add:function(){ this.number++; this.$emit("change",1);//觸發change事件,傳值是1; } } } var app = new Vue({ el:"#app", data:{ all:0, one:0, two:0 }, components:{ count:count, }, methods:{ allNum:function(value){//value來接受$emit的傳值 this.all+=value; } } }) 複製程式碼
效果如下:

三、元件引數校驗與非Props特性
元件引數校驗
當父元件給子元件傳值時,我們希望對該值進行約束,如下
props:{ content:{ type:String,//限制傳過來的值必須是字串, required:false,//是否必須傳遞該值 default:'default value',//預設值 validator:function(value){// return (value.length>5);//該值的長度必須大於5 } } } 複製程式碼
props特性
父元件給子元件傳值時,切好子元件的props中有對應的prop進行接收,那麼這就是props特性,,父元件給子元件傳遞的值,不會顯示在html中,
向相反,非props特性,則會顯示在html中
四、給元件繫結原生事件
父元件在子元件上綁定了一個事件,想要觸發該事件,只能通過 觸發自定義事件的方式 去觸發,或者在加上事件修飾符.native
先看第一種,不加修飾符,不觸發自定義事件
<div id="app"> <child @click="onClick"></child> </div> <script> Vue.component('child',{ template:'<div>child</div>', }) var app = new Vue({ el:"#app", methods:{ onClick:function(){ alert('click'); } } }) </script> 複製程式碼
在瀏覽器中,我們發現,點選child並沒有任何效果,

這就是想要觸發父元件在子元件上繫結的事件,只能通過觸發自定義事件的方式去觸發,現在改程式碼如下:
<div id="app"> <child @click="onClick"></child> </div> <script> Vue.component('child',{ template:'<div @click="childClick">child</div>', methods:{ childClick:function(){ this.$emit("click");//觸發父元件的自定義事件,click } } }) var app = new Vue({ el:"#app", methods:{ onClick:function(){ alert('click'); } } }) </script> 複製程式碼

或者給加上一個事件修飾符.native也可以達到相同的效果
<child @click.native="onClikc"></child> 複製程式碼
五、非父子元件間的傳值
這裡先介紹一種匯流排的模式。
<div id="app"> <child content="胡"></child> <child content="志武"></child> </div> <script> Vue.prototype.bus = new Vue(); Vue.component("child",{ props:['content'], data:function(){ return { name:this.content, } }, template:'<div @click="exchange">{{name}}</div>', methods:{ exchange:function(){ this.bus.$emit("change",this.name) } }, //元件被掛載時, mounted:function(){ var that = this; this.bus.$on("change",function(msg){ that.name=msg; }) } }) var app = new Vue({ el:"#app", }) </script> 複製程式碼
我們在 Vue
的 prototype
上掛載了一個 bus
,這個bus是一個 vue
的例項,子元件要互相傳值時,就可以用這個共同的祖先bus來監聽和觸發相應的事件,並藉助這個共同的祖先來傳值

六、使用插槽
slot可以讓我們在元件的某個位置插入想要的內容
Vue.component("child",{ template:`<div> <slot name="header">預設內容</slot> <div>content</div> <slot name="footer">預設內容</slot> </div>` })V 複製程式碼
<div id="app"> <child> <div slot="header">我是頭部</div> <div slot="footer">我是尾部</div> </child> </div> 複製程式碼
如果在插槽位置沒有插入內容,則會顯示預設內容
作用域插槽
當子元件在做遍歷,而希望這個遍歷的dom結構由外部決定時,可以使用作用域插槽
<div id="app"> <child > <template slot-scope="props">//template是必須寫的 <h1>{{props.item}}</h1>//props可以任意寫,而item必須和template中的`:item`一致 </template> </child> </div> <script> Vue.component("child",{ data:function(){ return { list:[1,2,3,4,5] } }, template:` <ul> <slot v-for="item of list" :item=item>//這裡的:item是要傳值給html實際插槽部分的 </slot> </ul> ` }) new Vue({ el:"#app", }) </script> 複製程式碼
動態元件和v-once
<component>
是vue自帶標籤,
<component :is="元件名">
component會根據is後面元件名的不同而動態載入不同的元件
v-once可以把元件放在記憶體中,可以有效提高效能
template:`<div v-once>child ONE</div>` 複製程式碼