關(guān)于Vue-extend和VueComponent問(wèn)題小結(jié)
在一個(gè)非單文件組件中(一個(gè)文件中包含n個(gè)組件,最常見(jiàn)的就是單個(gè)html文件中存在多個(gè)組件),如果我們需要在這個(gè)文件中創(chuàng)建n個(gè)組件,然后再頁(yè)面上展示,這時(shí)候我們就需要先定義組件,然后注冊(cè)組件,最后使用組件。在定義組件這一步,我們就需要使用到 extend 這個(gè)方法。當(dāng)然,也可以在一個(gè)html文件中使用多個(gè) new Vue () 來(lái)注冊(cè)組件,但是這么做有問(wèn)題,下面再說(shuō)。
Vue.extend(option)
官方文檔解釋:使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個(gè)“子類”。參數(shù)是一個(gè)包含組件選項(xiàng)的對(duì)象。
組件選項(xiàng):templete模板(el屬性只能在 new Vue() 時(shí)使用)、data數(shù)據(jù)、methods方法、computed計(jì)算屬性等等正常組件擁有的。
我的理解:首先 extend 是 Vue 自帶的一個(gè)全局方法,該方法接收一個(gè)對(duì)象作為參數(shù),在實(shí)例化的時(shí)候,通過(guò)傳遞的參數(shù)將一個(gè)空的 Vue實(shí)例 進(jìn)行擴(kuò)展,并以此來(lái)創(chuàng)造出一個(gè) Vue 子類,也就是我們說(shuō)的 Vue 組件。
使用方法:
1、非單文件組件內(nèi)部所有組件全部使用 Vue.extend() 方式注冊(cè)(未指定根組件,無(wú)法渲染)
2、非單文件組件中使用 new Vue() 注冊(cè)根組件,其余子組件則使用 Vue.extend() 方式注冊(cè)。
3、全部使用 new Vue() 注冊(cè)組件(若是存在組件嵌套,則子組件內(nèi)部雙向綁定的的數(shù)據(jù)失效)
1、全部使用 Vue.extend() 方式注冊(cè)組件
const vm2 = Vue.extend({
template:
`<div id='root2'>
{{msg}}
</div>`,
data() {
return {
msg: 'root2',
count: 2,
pets: 'dog'
}
}
})
const vm1 = Vue.extend({
template:
`<div id='root1'>
{{msg}}
<!-- 使用 root2 組件 -->
<vm2 />
</div>`,
data() {
return {
msg: 'root1',
count: 1,
pets: 'dog'
}
},
components: {
// 注冊(cè)子組件
vm2
}
})無(wú)法展示,頁(yè)面也不會(huì)報(bào)錯(cuò),因?yàn)楦緵](méi)有指定根組件進(jìn)行渲染

2、使用第二種方式分別注冊(cè)子組件和根組件
注冊(cè)子組件
const vm1 = Vue.extend({
template:
`<div id='root2'>
{{msg}}
<input v-model="count" />
</div>
`,
data() {
return {
msg: 'root2',
count: 2,
pets: 'dog'
}
}
})注冊(cè)根組件
// 注冊(cè)根組件
const vm = new Vue({
el: '#root1',
data() {
return {
msg: 'root1',
count: 1,
pets: 'dog'
}
},
components: {
// 注冊(cè)子組件
vm1
}
})根組件以及子組件使用
<div id='root1'>
{{msg}}
<input v-model="count" />
<!-- 使用 root2 組件 -->
<vm1 />
</div>頁(yè)面展示效果正常,且雙向綁定數(shù)據(jù)正常

3、全部使用 new Vue 定義組件。其實(shí)在正常的開(kāi)發(fā)中,這個(gè)方法用的極少,因?yàn)槲覀兊拈_(kāi)發(fā)一般都是單文件組件,在工程中每個(gè)組件都是通過(guò) new Vue() 創(chuàng)建的,直接掛載到 根組件 app上。但是在單文件組件中,我們一般不使用多個(gè) new Vue() 來(lái)創(chuàng)建組件,這是因?yàn)樵谑褂?new Vue() 時(shí),必須要傳入一個(gè) el 屬性,這樣會(huì)導(dǎo)致html頁(yè)面上存在多個(gè)根節(jié)點(diǎn),如果你的根節(jié)點(diǎn)嵌套了,那嵌套的根節(jié)點(diǎn)中綁定的數(shù)據(jù)會(huì)失效,不會(huì)展示。例如:
<div id='root1'>
{{msg}}
<input v-model="count" />
<select name="pets" id="pet-select" v-model="pets">
<option value="">--Please choose an option--</option>
<option value="dog">Dog</option>
</select>
<div id='root2'>
{{msg}}
<input v-model="count" />
<select name="pets" id="pet-select" v-model="pets">
<option value="">--Please choose an option--</option>
<option value="dog">Dog</option>
</select>
</div>
</div>在這個(gè) html 文件中,存在兩個(gè)根節(jié)點(diǎn) ,root1、root2,兩個(gè)跟節(jié)點(diǎn)內(nèi)部的子節(jié)點(diǎn)完全一樣,綁定的數(shù)據(jù)也完全一樣,但是 root1根節(jié)點(diǎn)包裹住了 root2根節(jié)點(diǎn)。
const vm = new Vue({
el: '#root1',
data() {
return {
msg: 'root1',
count: 1,
pets: 'dog'
}
},
})
const vm1 = new Vue({
el: '#root2',
data() {
return {
msg: 'root2',
count: 2,
pets: 'dog'
}
}
})按照原本的想法,兩個(gè)節(jié)點(diǎn)展示的數(shù)據(jù)應(yīng)該完全一樣,但是在頁(yè)面上的效果是這樣的。

可以看到,只有外部的root1根節(jié)點(diǎn)展示了對(duì)的數(shù)據(jù), root2的根節(jié)點(diǎn)數(shù)據(jù)要么為空不展示,要么展示的是錯(cuò)誤數(shù)據(jù)。
如果我們使用 Vue.extend() 來(lái)注冊(cè)子組件又會(huì)是什么情況呢?
首先,注冊(cè)root2組件,其實(shí)就是將root2的所有節(jié)點(diǎn)放在了 templete 屬性內(nèi)部,用字符串模板包裹
const vm1 = Vue.extend({
template:
`<div id='root2'>
{{msg}}
<input v-model="count" />
<select name="pets" id="pet-select" v-model="pets">
<option value="">--Please choose an option--</option>
<option value="dog">Dog</option>
</select>
</div>`,
data() {
return {
msg: 'root2',
count: 2,
pets: 'dog'
}
}
})2、在父組件中注冊(cè) root2 組件
const vm = new Vue({
el: '#root1',
data() {
return {
msg: 'root1',
count: 1,
pets: 'dog'
}
},
components: {
vm1
}
})3、使用 root2 組件
<div id='root1'>
{{msg}}
<input v-model="count" />
<select name="pets" id="pet-select" v-model="pets">
<option value="">--Please choose an option--</option>
<option value="dog">Dog</option>
</select>
<!-- 使用 root2 組件 -->
<vm1 />
</div>4、頁(yè)面效果

結(jié)論:如果是在非單組件文件(或者是html頁(yè)面),最好是只用 一個(gè)new Vue()注冊(cè)一個(gè)根組件,其余子組件則是用 Vue.extend() 注冊(cè)。否則如果使用 new Vue() 注冊(cè)所有組件的話,若是存在組件包裹的情況,則被包裹的組件內(nèi)部雙向數(shù)據(jù)綁定會(huì)失效。
VueComponent
在組件定義之后,我們其實(shí)還沒(méi)有去理解這個(gè)過(guò)程和內(nèi)部操作,下面我們就來(lái)剖析一下,看看在 Vue.extend() 之后,發(fā)生了什么。
首先,我們來(lái)看看 Vue.extend() 之后,返回的是一個(gè)什么東西。
樣例代碼就不貼了,就是上面的 vm1 實(shí)例。打印 vm1 之后,看看是個(gè)啥

打印之后發(fā)現(xiàn),這玩意是個(gè)函數(shù),而且還是個(gè)構(gòu)造函數(shù)。在這個(gè)函數(shù)里面啥操作也沒(méi)做,只不過(guò)調(diào)用了 _init() 方法。
Vue.extend = function (extendOptions) {
/*****其余操作***/
var Sub = function VueComponent(options) {
console.log("VueComponent被調(diào)用了");
this._init(options);
};
/*****其余操作***/
return Sub;
};
}所以說(shuō),
1、組件的本質(zhì)就是一個(gè) 【VueComponent 的構(gòu)造函數(shù)】,且這個(gè)函數(shù)是 Vue.extend() 生成的。
2、在使用組件時(shí),我們只需要寫上組件標(biāo)簽,Vue 會(huì)自動(dòng)幫我們生成 組件的實(shí)例對(duì)象( 因?yàn)榻M件的本質(zhì)就是一個(gè)構(gòu)造函數(shù),構(gòu)造函數(shù)被調(diào)用之后,當(dāng)然會(huì)產(chǎn)生實(shí)例對(duì)象),即 Vue 幫我們執(zhí)行的 new VueCopmonennt(options)
3、特別注意,每次調(diào)用 Vue.extend(),返回的都是一個(gè)新的組件,因?yàn)槭峭ㄟ^(guò)函數(shù)返回的。這個(gè)地方我們看看上面的源碼就能知道,因?yàn)?每次調(diào)用之后返回的 Sub 都是不一樣的。
4、關(guān)于this指向,
a、通過(guò) Vue.extend() 配置的組件,在data,methods,component,watch等可能用到 this 的地方,this 指向的是 【VueComponent 的實(shí)例對(duì)象】
b、通過(guò)new Vue() 配置的組件,在data,methods,component,watch等可能用到 this 的地方,this 指向的是 【Vue 的實(shí)例對(duì)象】
驗(yàn)證一下:
分別在上面的實(shí)例 vm,vm1上配置 show 方法,在方法內(nèi)部打印當(dāng)前this

點(diǎn)擊按鈕之后,查看 this 指向

展開(kāi)的地方太大了,就不展開(kāi)了,但是在控制臺(tái)上對(duì)比發(fā)現(xiàn),除了 一個(gè)是 Vue {} 一個(gè)是 VueComponent {} 之外,內(nèi)部的所有屬性全部一致,包括數(shù)據(jù)劫持,數(shù)據(jù)代理,底層方法等等。
組件管理
之前說(shuō)的Vue.extend(option) 這個(gè)模塊時(shí),說(shuō)到了非單文件組件內(nèi)部,最好是使用Vue.extend(option) 來(lái)定義子組件,然后使用 new Vue(option) 來(lái)注冊(cè)根組件,從而使得 根組件好方便管理子組件,那么從那里能看出來(lái)管理狀態(tài)呢?
看看上面的this 指向問(wèn)題,展開(kāi)之后,發(fā)現(xiàn) 一個(gè) $children屬性,這是一個(gè)數(shù)組
在 new Vue() 配置的組件中,發(fā)現(xiàn)存在一個(gè) VueComponent {} 實(shí)例對(duì)象,這個(gè)對(duì)象指向的就是 vm1實(shí)例對(duì)象

而在 Vue.extend() 配置的組件中,發(fā)現(xiàn)這是一個(gè)空數(shù)組,這就是因?yàn)椋?根組件調(diào)用了 vm1子組件,而 vm1子組件,內(nèi)部是沒(méi)有調(diào)用別的子組件的。

這就是 Vue 的組件管理模式
總結(jié)
如何使用 Vue.extend() 定義一個(gè)組件:
1、Vue.extend(option) 和 new Vue(option) 創(chuàng)建組件時(shí)所傳入的 option 配置項(xiàng)幾乎一樣.
區(qū)別在于:
(a)、el不能指定:所有的組件最終只會(huì)由一個(gè)vm管理,由這個(gè)vm中的 el 指定掛載容器
(b)、data必須寫成函數(shù):避免組件復(fù)用時(shí),數(shù)據(jù)存在引用關(guān)系。
Vue.extend() 定義組件的本質(zhì):
本質(zhì)上是 調(diào)用了 VueComponent () 這個(gè)構(gòu)造函數(shù),去返回了一個(gè) 【VueComponent 實(shí)例對(duì)象】,且每次在Vue.extend() 調(diào)用時(shí),返回的組件實(shí)例對(duì)象都不一樣
非單文件組件中定義根組件和子組件
原則上,默認(rèn)一個(gè)非單文件組件中 只存在一個(gè) new Vue() 定義的根組件,可以有無(wú)數(shù)個(gè) Vue.extend() 定義的子組件,這是因?yàn)?,如果所有組件都用 new Vue() 定義,那么如果存在組件包裹的情況,子組件內(nèi)部雙向綁定的數(shù)據(jù)不會(huì)生效。如果都用 Vue.extend() 定義組件,那么則沒(méi)有指定根組件,無(wú)法渲染。
this指向問(wèn)題
使用 new Vue() 定義的組件,在組件內(nèi)部能用到 this 的地方,this指向?yàn)?strong>【Vue實(shí)例對(duì)象】
使用 Vue.extend() 定義的組件,~~~~~~~~~~~~~this指向?yàn)?strong>【VueComponent實(shí)例對(duì)象】
官網(wǎng)補(bǔ)充

這里說(shuō)明了,使用 VueComponent 和 new Vue 的異同。但是其實(shí)還有一點(diǎn):在 new Vue 中,傳遞的 data 屬性,可以是對(duì)象,也可以是函數(shù)( 當(dāng)然,我們還是推薦函數(shù)寫法 ),但是在VueComponent 中傳遞的 data 屬性,則只能是函數(shù),因?yàn)?new Vue 注冊(cè)的是 根組件,不存在復(fù)用情況,data中的屬性不存在引用關(guān)系,不會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)亂,但是VueComponent 則不同
相關(guān)文章
詳解element-ui設(shè)置下拉選擇切換必填和非必填
這篇文章主要介紹了詳解element-ui設(shè)置下拉選擇切換必填和非必填,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
Vuex中的getter和mutation的區(qū)別詳解
在現(xiàn)代前端開(kāi)發(fā)中,狀態(tài)管理是一個(gè)不可忽視的話題,而Vuex作為Vue.js的官方狀態(tài)管理庫(kù),在大型應(yīng)用中扮演著至關(guān)重要的角色,當(dāng)我們使用Vuex進(jìn)行狀態(tài)管理時(shí),getter和mutation是兩個(gè)重要的概念,在本文中,我們將詳細(xì)探討getter和mutation的區(qū)別,需要的朋友可以參考下2024-12-12
Vue鼠標(biāo)滾輪滾動(dòng)切換路由效果的實(shí)現(xiàn)方法
這篇文章主要介紹了Vue鼠標(biāo)滾輪滾動(dòng)切換路由效果的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08
vue 簡(jiǎn)單自動(dòng)補(bǔ)全的輸入框的示例
這篇文章主要介紹了vue 簡(jiǎn)單自動(dòng)補(bǔ)全的輸入框的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
Vue3.0使用ref和reactive來(lái)創(chuàng)建響應(yīng)式數(shù)據(jù)
ref?和?reactive?是?Composition?API?中用來(lái)創(chuàng)建響應(yīng)式數(shù)據(jù)的兩個(gè)核心函數(shù),在本篇文章中,我們將詳細(xì)講解如何使用?ref?和?reactive?來(lái)創(chuàng)建響應(yīng)式數(shù)據(jù),并展示它們之間的區(qū)別和使用場(chǎng)景,需要的朋友可以參考下2024-11-11

