一、元件中的細節點
is的使用
在html
語法中,table
標籤內就必須是tr
標籤,tr
標籤下就必須是td
標籤,ul
標籤下就必須是li標籤 等等 標籤間的巢狀規則
在運用元件的時候,會出現想在這個標籤內使用元件,但這個標籤內並不支援的情況,如下
<div id="app">
<table>
<tbody>
<tr>
<td>this is a row</td>
</tr>
<tr>
<td>this is a row</td>
</tr>
<tr>
<td>this is 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>`
複製程式碼
結語
因為本人水平有限,如果有錯漏的地方,還請看官多多指正
本文作者胡志武,寫於2019/5/13,如果要轉載,請註明出處,
如果覺得寫的不錯, 請點個贊吧