世界上有太多孤獨(dú)的人害怕先踏出第一步庶橱。 ---綠皮書
書接上回娃闲,上篇介紹了vue組件通信比較有代表性的幾種方法厘擂,本篇主要講述一下組件的高級用法和最佳實(shí)踐程腹,爭取用最少的篇幅占領(lǐng)高地C惩啊(多說一句焕数,后續(xù)這個系列會有vue最佳實(shí)踐和源碼解讀
,我總有辦法能讓大家看懂刨啸,所以點(diǎn)贊關(guān)注堡赔,不迷路啊,小老弟
本篇主要內(nèi)容
- 遞歸組件
- 動態(tài)組件
- 異步組件
- 內(nèi)聯(lián)模板 inline-template的使用
- 全局組件批量自動注冊
- Vue 的構(gòu)造器——extend
- vue 修飾符sync深入解析
正文開始
遞歸組件
函數(shù)的遞歸是自己調(diào)用自己设联,這個過程有兩個必要條件:
- 這個函數(shù)必須有函數(shù)名稱
- 這個遞歸函數(shù)必須有結(jié)束條件,不然就會報
Maximum call stack size exceeded
,內(nèi)存溢出
本質(zhì)上講善已,組件也是一個函數(shù),遞歸組件自然也是自己調(diào)用自己离例,所以也要滿足兩個條件:
- 這個組件必須有確定的name,也就是要給組件設(shè)置name
- 必須要有一個結(jié)束條件换团,告訴組件什么時候遞歸結(jié)束
上代碼
非常簡單的功能,讓你看懂遞歸宫蛆,A.vue中引入B.vue,B組件是遞歸的核心所在
<template>
// 要將treeData通過prop進(jìn)行傳遞
<B :propTreeData="treeData"/>
</template>
<script>
import B from './B'
export default {
name: "Tree",
data() {
return {
treeData: [
{
id: "1",
menuName: "笑傲江湖",
menuCode: "1",
children: [
{
menuName: "令狐沖",
menuCode: "10"
},
{
menuName: "東方不敗",
menuCode: "11"
}
]
},
{
id: "2",
menuName: "射雕英雄",
menuCode: "2",
children: [
{
menuName: "蓉兒",
menuCode: "20"
},
{
menuName: "郭靖",
menuCode: "21"
}
]
}
]
};
},
components:{B}
};
</script>
B組件艘包,遞歸的核心,由于是遞歸耀盗,必須結(jié)構(gòu)一致想虎,因此就必須將A中的treeData通過Props傳給B才能實(shí)現(xiàn)遞歸,這就是為啥A和B必須分離叛拷,而絕不可能通過一個組件來實(shí)現(xiàn)遞歸
舌厨,不知道你懂了沒?體會一下
<template>
<ul>
<li v-for="item in propTreeData" :key="item.menuCode">
{{item.menuName}}
// 要有一個結(jié)束條件
<tree v-if="item.children&&item.children.length" :propTreeData="item.children"></tree>
</li>
</ul>
</template>
<script>
export default {
name: "Tree",
props:{
propTreeData:Array,
default:()=>([])
},
};
</script>
看下實(shí)現(xiàn)效果忿薇,這是一個最最簡單的遞歸裙椭,但是后續(xù)的所有的復(fù)雜功能,折疊署浩,選中揉燃,拖拽哪一個又不是基于這個來進(jìn)行的呢?復(fù)雜功能大家可以繼續(xù)擴(kuò)展筋栋,都不難
<figcaption style="box-sizing: border-box; outline: 0px; display: block; text-align: center; margin: 8px; color: rgb(153, 153, 153); font-size: 14px; overflow-wrap: break-word;"></figcaption>
動態(tài)組件
讓多個組件使用同一個掛載點(diǎn)炊汤,并動態(tài)切換,這就是動態(tài)組件。
通過使用保留的
<component>
元素婿崭,動態(tài)地綁定到它的is
特性拨拓,可以實(shí)現(xiàn)動態(tài)組件
<template>
<div id="example">
<button @click="change">切換頁面</button>
<component :is="currentView"></component>
</div>
</template>
<script>
var LZL = { template: "<div>林志玲</div>" };
var GYY = { template: "<div>高圓圓</div>" };
var JJW = { template: "<div>賈靜雯</div>" };
export default {
name: "App",
components: {
LZL,
GYY,
JJW
},
data() {
return {
index:0,
arr:['LZL','GYY','JJW'],
};
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
this.index = (++this.index)%3;
}
}
};
</script>
動態(tài)組件的緩存,會將不活動的組件實(shí)例緩存起來氓栈,而不是銷毀它們渣磷,比如切換tab后,還能保持切換之前的狀態(tài)授瘦,如果有多個條件性的子元素醋界,
<keep-alive>
要求同時只有一個子元素被渲染
<keep-alive>
<component :is="currentView"></component>
</keep-alive>
-----------------------------------------------
<keep-alive>` 要求同時只有一個子元素被渲染
<keep-alive>
<LZL v-if="index===0"></LZL>
<GYY v-else-if="index===1"></GYY>
<JJW v-else></JJW>
</keep-alive>
使用的時候,比如keep-alive下有A,B,C三個組件提完,但是我只想緩存A和B,這時候該怎么辦形纺,就要用到【
include和exclude
】來進(jìn)行篩選過濾,根據(jù)你的過濾 條件確定緩存哪個組件
include會匹配首先檢查組件自身的 name
選項(xiàng)徒欣,如果 name
選項(xiàng)不可用逐样,則匹配它的局部注冊名稱(父組件 components
選項(xiàng)的鍵值)。匿名組件不能被匹配
<!-- 逗號分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正則表達(dá)式 (使用 v-bind) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- Array (use v-bind) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
異步組件
異步組件說白了就是按需加載打肝,使用時才裝入需要的組件脂新,可以有效的提高首次裝入頁面的速度。比如在路由切換時粗梭。
{
path: '/promisedemo',
name: 'PromiseDemo',
component: resolve => require(['../components/PromiseDemo'], resolve)
}
利用此特性争便,我們便能做很多針對前端的優(yōu)化。 比如:將頁面核心功能(音断医、視頻播放滞乙、文章、商品等等)打包成一個核心模塊鉴嗤,通過框架優(yōu)先加載斩启。 其他的一些周邊功能打包后,通過服務(wù)器異步加載躬窜,從而解決業(yè)務(wù)需求越來越多導(dǎo)致的系統(tǒng)難維護(hù)浇垦、訪問慢問題。
既然是異步加載荣挨,就會存在加載過程(正在加載中)、以及加載失敗等異常情況,看下圖一目了然朴摊。默垄。。
<figcaption style="box-sizing: border-box; outline: 0px; display: block; text-align: center; margin: 8px; color: rgb(153, 153, 153); font-size: 14px; overflow-wrap: break-word;"></figcaption>
內(nèi)聯(lián)模板 inline-template的使用
Vue提供了一種內(nèi)聯(lián)模板的功能甚纲,在使用組件時口锭,給標(biāo)簽加上inline-complate特性,組件就會把它的內(nèi)容當(dāng)作模板,而不是當(dāng)內(nèi)容分發(fā)鹃操。其實(shí)也就是說韭寸,不在創(chuàng)建一個組件時定義它的模板,而是在聲明的外部創(chuàng)建荆隘。
父組件
<child-component inline-template>
<div>
<h2>在父組件中定義子組件的模板</h2>
<p>{{msg}}</p>
</div>
</child-component>
子組件
export default{
name:'ChildComponent',
data(){
return{
msg:'張不慫'
}
}
}
最終顯示
<div data-v-763db97b="">
<h2 data-v-763db97b="">在父組件中定義子組件的模板</h2>
<p data-v-763db97b="">張不慫</p>
</div>
inline-template使得各個組件的結(jié)構(gòu)混亂恩伺,建議不要輕易使用內(nèi)聯(lián)模板
全局組件批量自動注冊
我們vue組件中引入組件的一般方式是這樣的
<template>
<A v-model="searchText" @keydown.enter="search"/>
<B @click="search">
<C name="search"/>
</B>
</template>
<script>
import B from './B'
import C from './C'
import A from './A'
export default {
components: { B, C, A }
}
</script>
有沒有辦法可以自動全局進(jìn)行注冊呢?答案是肯定的,在你要引入的包含所有組件的文件夾components的同級目錄下建register.js,寫入下邊的代碼
const requireComponent = require.context(
'./components', // 其組件目錄的相對路徑
false, // 是否查詢其子目錄
/base_[A-Z]\w+\.(vue|js)$/ // 匹配基礎(chǔ)組件文件名的正則表達(dá)式
)
requireComponent.keys().forEach(fileName => {
// 獲取組件配置
const componentConfig = requireComponent(fileName)
// 獲取組件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 剝?nèi)ノ募_頭的 `./` 和結(jié)尾的擴(kuò)展名
fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
)
)
// 全局注冊組件
Vue.component(
componentName,
componentConfig.default || componentConfig
)
})
然后在你的vue項(xiàng)目的main.js中進(jìn)行引入,就直接可以使用
import @/register.js;
Vue 的構(gòu)造器——extend
Vue.extend(options)
用法:使用Vue構(gòu)造器椰拒,創(chuàng)建一個“子類”晶渠,參數(shù)是一個包含組件選項(xiàng)的對象,其中,data選項(xiàng)中必須是函數(shù)
描述:Vue.extend返回的是一個“擴(kuò)展實(shí)例構(gòu)造器”燃观,也就是預(yù)設(shè)了部分選項(xiàng)的Vue的實(shí)例構(gòu)造器
自定義一個無參數(shù)標(biāo)簽
var foo = Vue.extend({
template: "<p><a :href='url'>{{foo}}</a></p>",
data : function() {
return {
foo : 'vamous',
url : 'https://juejin.im/editor/drafts/5cd2da7a5188253e8c23baf6'
}
}
});
對應(yīng)的html
<foo></foo>
此時的頁面必然是沒有任何效果的褒脯,因?yàn)閿U(kuò)展實(shí)例構(gòu)造器還需要掛載,如下:
new foo().$mount('#app');
可以利用propsData傳遞參數(shù)
var author = Vue.extend({
template: "<p><a :href='url'>{{bar}} & {{name}}</a></p>",
data : function() {
return {
bar : 'vamous',
url : 'https://juejin.im/editor/drafts/5cd2da7a5188253e8c23baf6'
}
},
props : ['name']
});
new author({propsData: {name : 'foo'}}).$mount('#author');
vue 修飾符sync深入解析
實(shí)現(xiàn)子組件與父組件雙向綁定的【sync】修飾符:其實(shí)sync這個修飾符是vue1.0就有的缆毁,它可以實(shí)現(xiàn)父子組件的雙向綁定番川,但是Vue2.0被移除了,直到2.3.0版本發(fā)布后脊框,又重新開始啟用颁督,【.sync】可以很輕松的實(shí)現(xiàn)子組件同步修改父組件的值
如果子組件想修改父組件的值,推薦以update:my-prop-name 的模式觸發(fā)事件取而代之缚陷,也就是這樣:
父組件
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
---------------------------------------------------------------
子組件
this.$emit("update:title".newTitle)
而上邊的 v-on:update:title="doc.title = $event"适篙,本質(zhì)上就可以用sync這個語法糖來表示,.sync后面緊接的就是父組件中需要被改變的值箫爷,看下邊的例子體會一下
父組件
<template>
<div>
<child-com :value.sync="text" ></child-com>
</div>
</template>
<script>
export default{
data(){
return {
text:"父組件的值",
}
},
}
</script>
==================================================================================
//子組件中修改父組件的值
<template>
<div @click="post"></div>
</template>
<script>
export default{
methods:{
post(){
this.$emit('update:value',"子組件的值")
}
}
}
</script>
本篇基本就是這些嚷节,這三篇概述了vue的一些知識點(diǎn),更多的vue實(shí)踐還需要在工作中自己總結(jié)和挖掘虎锚,道阻且長,行則將至~
覺得對你有幫助硫痰,不妨點(diǎn)個
贊
,后續(xù)持續(xù)輸出這種簡短有效的文章窜护,幫助你用最短的時間內(nèi)掌握最多的內(nèi)容效斑,畢竟誰不喜歡一勞永逸不是? ?(^_-) thank you ~