Vue.js中怎么實(shí)現(xiàn)一個(gè)可復(fù)用組件,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
為賓川等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及賓川網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、賓川網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
構(gòu)成組件
組件,是一個(gè)具有一定功能,且不同組件間功能相對(duì)獨(dú)立的模塊。組件可以是一個(gè)按鈕、一個(gè)輸入框、一個(gè)視頻播放器等等。
可復(fù)用組件,高內(nèi)聚、低耦合。
那么,什么構(gòu)成了組件呢。以瀏覽器的原生組件 video 為例,分析一下組件的組成部分。
<video src="example.mp4" width="320" height="240" onload="loadHandler" onerror="errorHandler"> Your browser does not support the video tag. </video>
實(shí)例中能看出,組件由狀態(tài)、事件和嵌套的片斷組成。狀態(tài),是組件當(dāng)前的某些數(shù)據(jù)或?qū)傩?,?video 中的 src、width 和 height。事件,是組件在特定時(shí)機(jī)觸發(fā)一些操作的行為,如 video 在視頻資源加載成果或失敗時(shí)會(huì)觸發(fā)對(duì)應(yīng)的事件來執(zhí)行處理。片段,指的是嵌套在組件標(biāo)簽中的內(nèi)容,該內(nèi)容會(huì)在某些條件下展現(xiàn)出來,如在瀏覽器不支持 video 標(biāo)簽時(shí)顯示提示信息。
在 Vue 組件中,狀態(tài)稱為 props,事件稱為 events,片段稱為 slots。組件的構(gòu)成部分也可以理解為組件對(duì)外的接口。良好的可復(fù)用組件應(yīng)當(dāng)定義一個(gè)清晰的公開接口。
Props 允許外部環(huán)境傳遞數(shù)據(jù)給組件
Events 允許組件觸發(fā)外部環(huán)境的副作用
Slots 允許外部環(huán)境將額外的內(nèi)容組合在組件中。
使用 vue 對(duì) video 組件做拓展,構(gòu)造出一個(gè)支持播放列表的組件 myVideo:
<my-video :playlist="playlist" width="320" height="240" @load="loadHandler" @error="errorHandler" @playnext="nextHandler" @playprev="prevHandler"> <div slot="endpage"></div> </my-video>
myVideo 組件有著清晰的接口,接收播放列表、播放器寬高等狀態(tài),能夠觸發(fā)加載成功或失敗、播放上一個(gè)或下一個(gè)的事件,并且能自定義播放結(jié)束時(shí)的尾頁,可用于插入廣告或顯示下一個(gè)視頻信息。
組件間通信
在 Vue.js 中,父子組件的關(guān)系可以總結(jié)為 props down, events up 。父組件通過 props 向下傳遞數(shù)據(jù)給子組件,子組件通過 events 給父組件發(fā)送消息??纯此鼈兪窃趺垂ぷ鞯?。
業(yè)務(wù)無關(guān)
命名
組件的命名應(yīng)該跟業(yè)務(wù)無關(guān)。應(yīng)該依據(jù)組件的功能為組件命名。
例如,一個(gè)展示公司部門的列表,把每一項(xiàng)作為一個(gè)組件,并命名為 DepartmentItem。這時(shí),有一個(gè)需求要展示團(tuán)隊(duì)人員列表,樣式跟剛剛的部門列表一樣。顯然,DepartmentItem 這個(gè)名字就不適合了。
因此,可復(fù)用組件在命名上應(yīng)避免跟業(yè)務(wù)扯上關(guān)系,以組件的角色、功能對(duì)其命名。Item、ListItem、Cell??梢詤⒖?Bootstrap、ElementUI 等一些 UI 框架的命名。
業(yè)務(wù)數(shù)據(jù)無關(guān)
可復(fù)用組件只負(fù)責(zé) UI 上的展示和一些交互以及動(dòng)畫,如何獲取數(shù)據(jù)跟它無關(guān),因此不要在組件內(nèi)部去獲取數(shù)據(jù),以及任何與服務(wù)端打交道的操作??蓮?fù)用組件只實(shí)現(xiàn) UI 相關(guān)的功能。
組件職責(zé)
約束好組件的職責(zé),能讓組件更好地解耦,知道什么功能是組件實(shí)現(xiàn)的,什么功能不需要實(shí)現(xiàn)。
組件可以分為通用組件(可復(fù)用組件)和業(yè)務(wù)組件(一次性組件)。
可復(fù)用組件實(shí)現(xiàn)通用的功能(不會(huì)因組件使用的位置、場景而變化):
UI 的展示
與用戶的交互(事件)
動(dòng)畫效果
業(yè)務(wù)組件實(shí)現(xiàn)偏業(yè)務(wù)化的功能:
獲取數(shù)據(jù)
和 vuex 相關(guān)的操作
埋點(diǎn)
引用可復(fù)用組件
可復(fù)用組件應(yīng)盡量減少對(duì)外部條件的依賴,所有與 vuex 相關(guān)的操作都不應(yīng)在可復(fù)用組件中出現(xiàn)。
組件應(yīng)當(dāng)避免對(duì)其父組件的依賴,不要通過 this.$parent 來操作父組件的示例。父組件也不要通過 this.$children 來引用子組件的示例,而是通過子組件的接口與之交互。
命名空間
可復(fù)用組件除了定義一個(gè)清晰的公開接口外,還需要有命名空間。命名空間可以避免與瀏覽器保留標(biāo)簽和其他組件的沖突。特別是當(dāng)項(xiàng)目引用外部 UI 組件或組件遷移到其他項(xiàng)目時(shí),命名空間可以避免很多命名沖突的問題。
<xl-button></xl-button> <xl-table></xl-table> <xl-dialog></xl-dialog> ...
業(yè)務(wù)組件也可以有命令空間,跟通用組件區(qū)分開。這里用 st (section) 來代表業(yè)務(wù)組件。
<st-recommend></st-recommend> <st-qq-movie></st-qq-movie> <st-sohu-series></st-sohu-series>
上下文無關(guān)
還是上面那句話,可復(fù)用組件應(yīng)盡量減少對(duì)外部條件的依賴。沒有特別需求且單個(gè)組件不至于過重的的前提下,不要把一個(gè)有獨(dú)立功能的組件拆分成若干個(gè)小組件。
<table-wrapper> <table-header slot="header" :headers="exampleHeader"></table-header> <table-body slot="body" :body-content="exampleContents"></table-body> </table-wrapper>
TableHeader 組件和 TableBody 組件依賴當(dāng)前的上下文,即 TableWrapper 組件嵌套的環(huán)境下。你可以有更好的解決辦法:
<xl-table :headers="exampleHeader" :body-content="exampleContents"></xl-table>
上下文無關(guān)原則能夠降低組件使用的門檻。
數(shù)據(jù)扁平化
定義組件接口時(shí),盡量不要將整個(gè)對(duì)象作為一個(gè) prop 傳進(jìn)來。
<!-- 反例 --> <card :item="{ title: item.name, description: item.desc, poster: item.img }></card>
每個(gè) prop 應(yīng)該是一個(gè)簡單類型的數(shù)據(jù)。這樣做有下列幾點(diǎn)好處:
組件接口清晰
props 校驗(yàn)方便
當(dāng)服務(wù)端返回的對(duì)象中的 key 名稱與組件接口不一樣時(shí),不需要重新構(gòu)造一個(gè)對(duì)象
<card :title="item.name" :description="item.desc" :poster="item.img"> </card>
扁平化的 props 能讓我們更直觀地理解組件的接口。
使用自定義事件實(shí)現(xiàn)數(shù)據(jù)的雙向綁定
有時(shí)候,對(duì)于一個(gè)狀態(tài),需要同時(shí)從組件內(nèi)部和組件外部去改變它。
例如,模態(tài)框的顯示和隱藏,父組件可以初始化模態(tài)框的顯示,模態(tài)框組件內(nèi)部的關(guān)閉按鈕可以讓其隱藏。一個(gè)好的辦法是,使用自定義事件改變父組件中的值:
<modal :show="show" @showchange="show = argument[0]"></modal>
<!-- Modal.vue --> <template> <div v-show="show"> <h4>標(biāo)題</h4> <p>內(nèi)容</p> <a href="javascript:;" rel="external nofollow" rel="external nofollow" @click="close">關(guān)閉</a> </div> </template> <script> export default { props: { show: String }, methods: { close () { this.$emit('input', false) } } } </script>
用戶點(diǎn)擊關(guān)閉按鈕時(shí),Modal 組件發(fā)送一個(gè) input 自定義事件給父組件。父組件監(jiān)聽到 input 事件時(shí),把 show 設(shè)置為事件回調(diào)的第一個(gè)參數(shù)。
特別地,當(dāng)狀態(tài)名稱為 value,事件名稱為 input 時(shí),可以使用 v-model 指令語法糖:
<modal :value="show" @input="show = argument[0]"></modal>
等價(jià)于
<modal v-model="show"></model>
要讓組件的 v-model 生效,它必須:
接受一個(gè) value 屬性
在有新的 value 時(shí)觸發(fā) input 事件
注意:由于每個(gè)組件的 input 事件只能用來對(duì)一個(gè)數(shù)據(jù)進(jìn)行雙向綁定,所以當(dāng)存在多個(gè)需要向上同步的數(shù)據(jù)時(shí),請(qǐng)不要使用 v-model,請(qǐng)使用多個(gè)自定義事件,并在父組件中同步新的值。
<modal :show="show" @showchange="show = argument[0]" :content="content" @contentchange="content = argument[0]"> </model>
使用自定義 watcher 優(yōu)化 DOM 操作
在開發(fā)中,有些邏輯無法使用數(shù)據(jù)綁定,無法避免需要對(duì) DOM 的操作。例如,視頻的播放需要同步 Video 對(duì)象的播放操作及組件內(nèi)的播放狀態(tài)??梢允褂米远x watcher 來優(yōu)化 DOM 的操作。
<!-- MyVideo.vue --> <template> <div> <video ref="video" src="src"></video> <a href="javascript:;" rel="external nofollow" rel="external nofollow" @click="togglePlay">{{ playing ? '暫停' : '播放' }}</a> </div> </template> <script> export default { props: { src: String // 播放地址 }, data () { return { playing: false // 是否正在播放 } }, watch: { // 播放狀態(tài)變化時(shí),執(zhí)行對(duì)應(yīng)操作 playing (val) { let video = this.$refs.video if (val) { video.play(); } else { video.pause(); } } }, method: { // 切換播放狀態(tài) togglePlay () { this.playing = !this.playing } } } </script>
示例中,自定義 watcher 在監(jiān)聽到 playing 狀態(tài)變化時(shí),會(huì)執(zhí)行播放或暫停操作。遇到對(duì)視頻播放狀態(tài)的處理時(shí),只需要關(guān)注 playing 狀態(tài)即可。
項(xiàng)目骨架
單組件不異過重,組件在功能獨(dú)立的前提下應(yīng)該盡量簡單,越簡單的組件可復(fù)用性越強(qiáng)。當(dāng)你實(shí)現(xiàn)組件的代碼,不包括CSS,有好幾百行了(這個(gè)大小視業(yè)務(wù)而定),那么就要考慮拆分成更小的組件。
當(dāng)組件足夠簡單時(shí),就可以在一個(gè)更大的業(yè)務(wù)組件中去自由組合這些組件,實(shí)現(xiàn)我們的業(yè)務(wù)功能。因此,理想情況下,組件的引用層級(jí),只有兩級(jí)。業(yè)務(wù)組件引用通用組件。
我們可以得到一個(gè)扁平化的結(jié)構(gòu)。
在一個(gè)龐大的項(xiàng)目當(dāng)中,組件間的引用關(guān)系會(huì)更復(fù)雜一些。當(dāng)單頁應(yīng)用有多個(gè)路由,每個(gè)路由組件過重,需要拆分模塊時(shí)。組件結(jié)構(gòu)會(huì)變成下圖這樣。
按照這個(gè)思路構(gòu)建我們的項(xiàng)目,最后的源代碼目錄結(jié)構(gòu)(不包括構(gòu)建流程文件):
│ App.vue # 頂級(jí)組件 │ client-entry.js # 前端入口文件 │ config.js # 配置文件 │ main.js # 主入口文件 │ ├─api # 接口 API ├─assets # 靜態(tài)資源 ├─components # 通用組件 ├─directives # 自定義指令 ├─mock # Mock 數(shù)據(jù) ├─plugins # 自定義插件 ├─router # 路由配置 ├─sections # 業(yè)務(wù)組件 ├─store # Vuex Store ├─utils # 工具模塊 └─views # 路由頁面組件
看完上述內(nèi)容,你們掌握Vue.js中怎么實(shí)現(xiàn)一個(gè)可復(fù)用組件的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
分享文章:Vue.js中怎么實(shí)現(xiàn)一個(gè)可復(fù)用組件
文章地址:http://chinadenli.net/article24/jhhjce.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、動(dòng)態(tài)網(wǎng)站、小程序開發(fā)、品牌網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)公司、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)