1.組件使用的細節點1
- is屬性在tbody中應用
<div id="root">
<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 vm = new Vue({
// el限制一個vue實例的管理范圍。
el:"#root",
});
</script>
-
看似上面代碼書寫沒有什么問題,但是打開頁面你會看到,如下圖:
所有的tr標簽都跑到了tbody外面,這是不符合規范的。
-
那么如何解決這個問題,通過is屬性,只需要在原來代碼改一下:
<div id="root"> <table> <tbody> <tr is="row"></tr> <tr is="row"></tr> <tr is="row"></tr> </tbody> </table> </div>
原有的html實例不變,這樣就可以避免tr標簽上升到tbody標簽外頭了。
-
同樣像ul(li),select(option)
<ul> <li is="row"></li> <li is="row"></li> <li is="row"></li> </ul> <select> <option is="row"></option> <option is="row"></option> <option is="row"></option> </select>
2.組件使用的細節點2
-
data在子組件中,必須為一個函數,同時函數有返回數據。
Vue.component('row',{ data:function(){ return { content:"this is content" } }, template:`<tr><td>{{content}}</td></tr>` });
3.在Vue中操作DOM
-
Vue不建議在代碼中操作DOM,但是在復雜動畫效果,不操作DOM,光靠數據的綁定,是無法實現的。
<div id="app"> <div ref="hw" @click="handleClick">hello world</div> </div> var app = new Vue({ el:"#app", methods:{ handleClick:function () { //指的是ref="hw"的DOM divDom = this.$refs.hw; console.log(divDom.innerHTML) } } })
-
那么在組件中是如何應用ref,咱們定義一個計數功能:
<div id="root"> <!-- 父組件監聽change變化並交給 handleChange處理--> <counter @change="handleChange" ref="one"></counter> <counter @change="handleChange" ref="two"></counter> <div>{{total}}</div> </div>
Vue.component("counter",{ template:`<div @click="handleClick">{{number}}</div>`, data:function () { return { number:0 } }, methods:{ handleClick:function () { this.number ++; //子組件需要向父組件傳遞事件,當當前組件數據發生變化時。 this.$emit('change') } } }); var vm = new Vue({ // el限制一個vue實例的管理范圍。 el:"#root", //total用來計算兩個counter組件內數據的和 data:{ total:0 }, methods:{ handleChange:function () { //total求和 this.total = this.$refs.one.number + this.$refs.two.number } } });
4.父子組件的數據傳遞
-
父組件可以向子組件傳遞參數,但是子組件不能修改傳遞到子組件的參數,這就是單向數據流。
- 方式1:子組件通過復制參數,從而只更改復制過來的參數
<div id="root"> <!--1.父組件向子組件傳遞名字為count的值--> <counter :count="0"></counter> <counter :count="5"></counter> </div> var counter = { // 2.子組件定義props接收count data:function(){ return { // 3.既然子組件無法修改父組件傳來的參數 // 那么number為復制傳過來的參數,咱們使用number number:this.count } }, props:['count'], // 4.子組件使用復制過來的number, template:`<div @click="handleClick">{{number}}</div>`, methods:{ handleClick:function () { // 並且還可以更改復制的number this.number ++ } } }; var vm = new Vue({ // el限制一個vue實例的管理范圍。 el:"#root", components:{ counter:counter } });
- 方式2:子組件向父組件傳遞事件
<div id="root"> <!--1.父組件向子組件傳遞名字為count的值--> <!--監聽inc事件,一旦觸發執行父組件handleIncrease函數--> <counter :count="0" @inc="handleIncrease"></counter> <counter :count="5" @inc="handleIncrease"></counter> <div>{{total}}</div> </div> var counter = { // 2.子組件定義props接收count data:function(){ return { // 3.既然子組件無法修改父組件傳來的參數 // 那么number為復制傳過來的參數,咱們使用number number:this.count } }, props:['count'], // 4.子組件使用復制過來的number, template:`<div @click="handleClick">{{number}}</div>`, methods:{ handleClick:function () { // 並且還可以更改復制的number this.number ++; // 5.子組件通過觸發事件,將觸發的inc事件傳遞給父組件 this.$emit('inc',1) } } }; var vm = new Vue({ // el限制一個vue實例的管理范圍。 el:"#root", data:{ total:5, }, components:{ counter:counter }, methods:{ // 父組件定義函數 handleIncrease:function (step) { // step 為子組件 $emit的第二個參數。 this.total += step } } });
5.組件參數校驗與非props特性
-
首先需要了解的是什么是props特性
props特性其實就是,在父組件中傳入了參數,恰巧子組件在props也定義了該參數的校驗規則。並且子組件能使用該參數在template進行渲染
<child content="hell world"></child> Vue.component('child',{ // 子組件接收props props:{ // 傳入content的類型 // 方式1:content:[String,Number] // 方式2: content:{ type:String,//要求傳入值類型 required:false,//是否必填 defaule:"default value",//默認值 validator:function (value) { // 傳入數據長度大於5 return (value.length > 5) } } }, template:`<div>Child</div>` }); var vm = new Vue({ el:"#root", });
-
非props特性
父組件向子組件傳遞的是一個屬性,子組件並沒有聲明該屬性定義的內容。 1.這樣子組件就不能使用該屬性在子組件template渲染。 2.那么該屬性會在template定義的最外層標簽的標簽里,顯示.e.g.: <div content="hello">hello</div>
6.如何給組件綁定原生事件
-
當給一個組件標簽綁定一個事件其實是自定義事件,不會觸發原生事件
<div id="root"> <!--當給一個組件標簽綁定一個事件其實是自定義事件,不會觸發原生事件--> <child @click="handleClick"></child> </div> Vue.component("child",{ // 在標簽綁定事件時原生的事件 template:"<div @click='handleClick'>Child</div>", methods:{ //會觸發 handleClick:function () { alert("click click") } } }); var vm = new Vue({ el:"#root", methods:{ // 不會觸發 handleClick:function () { alert("click") } } });
-
那么如何觸發自定義事件?$emit
Vue.component("child",{ // 在標簽綁定事件時原生的事件 template:"<div @click='handleClick'>Child</div>", methods:{ //會觸發 handleClick:function () { //通過$emit觸發自定義事件 this.$emit("click") } } });
-
但是這樣寫代碼冗余,過於繁瑣?通過添加事件修飾符.native
<div id="root"> <!--當給一個組件標簽綁定一個事件其實是自定義事件,不會觸發原生事件--> <!--通過添加.native將該事件轉為原生click事件--> <child @click.native="handleClick"></child> </div> </body> <script> Vue.component("child",{ // 在標簽綁定事件時原生的事件 template:"<div>Child</div>", }); var vm = new Vue({ el:"#root", methods:{ // 不會觸發 handleClick:function () { alert("click") } } }); </script>
7.非父子組件傳值
- 當把一個網頁拆分成多個部分,每個部分是一個組件
-
如圖紅線,第二層的組件要跟第一層組件傳值可以通過
父組件通過props向子組件傳值,子組件通過事件觸發,向父組件傳值
-
如果第三層組件想傳值給第一層組件呢?
如果直接傳值是不行了,只能通過第一層組件向第二層,第二層向第三層傳值,返回來也是一樣。
-
但是這樣傳值相對比較復雜,比如出現如下圖③的情況就相當復雜了:
- 那么如何解決呢?一般有2種方式解決非父子組件傳值,一種是vue官方提供的框架vuex,另一種使用發布訂閱模式(總線機制)。
- 示例:兄弟組件傳值
<div id="exp">
<!--實現點擊第一個子組件,里面值變成第二子組件值-->
<!--實現點擊第二個子組件,里面值變成第一子組件值-->
<!--這兩個child子組件是兄弟關系-->
<child content="James"></child>
<child content="Lucy"></child>
</div>
// 1.將bus屬性掛載到 Vue()實例里,以后創建的Vue()實例都有bus屬性
Vue.prototype.bus = new Vue();
Vue.component("child",{
props:{
content:String
},
// 1.1.在vue當中單向數據流,子組件不能改變父組件傳遞的內容
// 所以定義一個data 返回復制后父組件傳的內容
data:function(){
return {
selfContent:this.content
}
},
//2.給子組件綁定一個點擊事件
template:`<div @click="handleClick">{{selfContent}}</div>`,
methods:{
handleClick:function () {
// 3.通過之前掛載的bus屬性,
// 這個bus又是vue實例,所以也有$emit方法。
// 通過$emit觸發change事件,同時攜帶當前標簽的內容
this.bus.$emit('change',this.selfContent)
}
},
// 4.mounted為一個生命周期鈎子,頁面渲染完執行周期函數mounted
// 監聽這個bus.的改變(change事件)
mounted:function () {
// 5.底下function使this作用域發生,需要保存當前this
var this_ = this;
this.bus.$on('change',function (msg) {
this_.selfContent = msg
})
}
});
var vm = new Vue({
// el限制一個vue實例的管理范圍。
el:"#exp",
});
8.Vue中的插槽
- 插槽使用場景:當子組件內容是根據父組件傳遞過來的DOM內容進行顯示,可以使用插槽。
<div id="exp">
<child>
<p>Dell</p>
</child>
</div>
<script>
//當父組件child標簽內沒有內容,則會顯示<slot>默認內容</slot>
Vue.component('child',{
template:`
<div>
<p>Hello</p>
<slot>默認內容</slot>
</div>`
});
var vm = new Vue({
el:"#exp",
});
</script>
-
具名插槽
- 給插槽取一個名字。每個插槽能按照你的要求插入具體位置。
<div id="exp"> <body-content> <div class="header" slot="header">header</div> <div class="footer" slot="footer">footer</div> </body-content> </div> //當父組件child標簽內沒有內容,則會顯示<slot>默認內容</slot> Vue.component('body-content',{ // 插槽設置默認值 template:` <div> <slot name="header"><h1>default header</h1></slot> <div class="content">content</div> <slot name="footer"></slot> </div>` }); var vm = new Vue({ el:"#exp", });
9.Vue中的作用域插槽
-
應用場景,當子組件做循環,其DOM結構由外部傳遞給子組件,子組件可以向插槽傳遞數據,父組件可以通過slot-scope接收數據並渲染。
<div id="exp"> <child> <!--父組件調用子組件給子組件傳入一個插槽--> <!--此插槽為作用域插槽,必須是template標簽--> <!--聲明slot-scope表示從子組件接收的數據都放在myData里--> <template slot-scope="myData"> <!--通過myData調用每一項數據--> <li>{{myData.item}}</li> </template> </child> </div> <script> Vue.component('child',{ data:function(){ return { list:[1,2,3,4,5] } }, // 通過v-for形成插槽,並給每個插槽綁定數據 也就是item template:` <div> <ul> <slot v-for="item of list" :item=item ></slot> </ul> </div>` }); var vm = new Vue({ // el限制一個vue實例的管理范圍。 el:"#exp", }); </script>
10.動態組件與v-once指令
-
動態組件
<div id="exp"> <!--根據type動態顯示相應組件--> <component :is="type"></component> <!--監聽點擊事件更改type數據--> <button @click="handleClick">change</button> </div> <script> Vue.component("child-one",{ template:`<div>child one</div>` }); Vue.component("child-two",{ template:`<div>child two</div>` }); var vm = new Vue({ // el限制一個vue實例的管理范圍。 el:"#exp", data:{ type:'child-one' }, methods:{ handleClick:function () { this.type = this.type === "child-one" ? "child-two":"child-one" } } }); </script>
-
v-once
看下面代碼,會有什么問題
<div id="exp"> <child-one v-if="type === 'child-one'"></child-one> <child-two v-if="type === 'child-two'"></child-two> <button @click="handleClick">change</button> </div> Vue.component("child-one",{ template:`<div>child one</div>` }); Vue.component("child-two",{ template:`<div>child two</div>` }); var vm = new Vue({ // el限制一個vue實例的管理范圍。 el:"#exp", data:{ type:'child-one' }, methods:{ handleClick:function () { this.type = this.type === "child-one" ? "child-two":"child-one" } } });
每次點擊button按鈕其實相當於銷毀當前組件創建另一個組件,這樣頻繁的切換導致創建銷毀,挺耗費性能的,如果說我們定義的要切換的組件的內容相似,可以加一個v-once指令。通過v-once會將渲染的頁面放在內存中,這樣如果再切換回來直接從內存取,會提高靜態內容展示效率,只需在子組件template里添加v-once
Vue.component("child-one",{ template:`<div v-once>child one</div>` }); Vue.component("child-two",{ template:`<div v-once>child two</div>` });
-