摘要:從零開始實現一個級聯組件本文實現級聯組件需要用到自定義指令和組件通信相關知識,最好先閱讀以下兩篇文章自定義指令組件基礎與通信一組件簡介本文實現的是一個省市縣多級聯動組件,當組件渲染完成后默認會加載出所有的省名稱,當用戶點擊某個省的名稱后,右
從零開始實現一個Vue級聯組件
本文實現級聯組件需要用到自定義指令和組件通信相關知識,最好先閱讀以下兩篇文章:
Vue自定義指令
Vue組件基礎與通信
一、組件簡介本文實現的是一個省、市、縣...多級聯動組件,當組件渲染完成后默認會加載出所有的省名稱,當用戶點擊某個省的名稱后,右邊會自動添加一列顯示該省下對應的市名稱列表,當用戶點擊某個市后,右邊又會自動添加一列顯示該市下對應的縣名稱列表,同時支持級聯列表的打開和關閉。
① 組件所需要的數據,數據結構非常簡單,對象里面只有兩個屬性,一個是label(標簽名),如果當前標簽下還有子標簽,則會多一個children屬性,children屬性值為一個數組,每個數組元素為其下的一個子標簽。
// data.json, 為避免數據占用太多篇幅,這里只列舉了一條數據
[ { "label": "江西", "children": [ { "label": "贛州", "children": [ { "label": "全南縣" }, { "label": "龍南縣" } ] } ] } ]
② 我們的級聯組件分為上下兩部分組件,上部分顯示用戶選擇的路徑,下部分顯示用戶選擇列表,同時支持點擊級聯組件的上部分可以實現下半部分的打開和關閉,點擊組件外面關閉組件的下半部分,這里需要用到v-click-outside指令,這里自定義指令的代碼就不再重復,請參考Vue自定義指令
// Cascader.vue 新建一個Cascader.vue組件
{{resultPath}}
注意到組件中有一個selectedItems數據,這是一個數組,默認值為空數組,因為當級聯組件渲染完成后,默認用戶是沒有點擊選擇其中任何一項的,只有當用戶點擊了某一項后,才會將點擊的這一項添加到selectedItems數組中,其就是記錄用戶的選擇項。這里需要理解清楚選擇項的概念:
比如我們的級聯組件有三列,省、市、縣三列,結合上面的數據結構,整個省是一個大對象,即省對象,省對象中有children屬性,里面包括多個子對象,即市對象,市對象中又包括children屬性,里面包括多個子對象,即縣對象,縣對象中不再有children了,具體表示就是:
省對象:
{ "label": "江西", children: [省略...]}
市對象:
{ "label": "贛州", children: [省略...]}
縣對象:
{ "label": "全南縣"}
當用戶點擊第一列,那么就將整個省對象添加到selectedItems數組中的第一項位置,當用戶接著點擊了第二列,如省對象中的label為"贛州"的市對象,則將整個市對象添加到selectedItems數組中的第二項位置,當用戶又點擊了第三列,如"贛州"市對象下的label為"全南縣"的縣對象,則將整個縣對象添加到selectedItems數組中的第三項位置,這樣selectedItems數組中就保存了用戶選擇的三列數據了,然后將三列數據中的label取出通過"/"連接起來,即用戶的選擇路徑"江西/贛州/全南縣"。
③ 接下來就是考慮組件拿到數據后,如何渲染的問題了?
這里需要用到組件內遞歸組件,我們可以左右兩列抽象成一個多帶帶的組件CascaderItem.vue,但是右邊這一列會不會顯示,得看用戶有沒有選擇左邊的項,如果點擊了左邊的項則顯示右邊的列,如果沒有點擊左邊的項則不顯示右邊的列。
還是以省、市、縣三列為例,中間的市這一列,既是省的右列,也是縣的左列,我們已經將左右兩列抽象了一個多帶帶的CascaderItem組件,關鍵是理解省這一列的右邊部分到底是什么?,從表面上看,省這一列的右邊就是一個市列,但是如果右邊僅僅是市這一列的話,那么當用戶點擊市這一列中的某項的時候,就無法顯示市右邊的縣列了,所以省這一列的右邊其實又是一個CascaderItem組件,只有這樣點擊市列中的某一項的時候,其右邊的縣列才會顯示出來。所以我們需要在CascaderItem組件內遞歸自己,而組件內遞歸自己,那么必須給組件添加name屬性,即給組件取一個名字,如:
// CascaderItem.vue
{{item.label}}
CascaderItem組件組件的渲染數據來自于頂層父組件Cascader中的selectedItems數據,因為用戶點擊了左側列中的項后,會將點擊的item項添加到selectedItems中,selectedItems中數據變化之后才會顯示右側的列。
CascaderItem組件需要接收一個level屬性,用來記錄當前CascaderItem組件所屬層級,即第幾列,為了方便,我們從0開始表示第一列,即第一層所以Cascader.vue中level傳入0,后面沒加一層level會加1,如:
// 補全上面的Cascader.vue,渲染出下半部分
{{resultPath}}
CascaderItem組件的左邊部分都監聽了一個click事件,當用戶點擊左邊的列選項后,需要將當前所在level和item對象數據傳遞到Cascader父組件中的selectedItems數組中,以便獲取用戶的選擇路徑,因為單向數據流,子組件不能直接修改父組件傳遞過來的數據,所以需要去父組件中修改數據,這里以事件的方式通知頂層父組件自己更新數據。
// CascaderItem.vue給CascaderItem組件添加一個select()方法
export default { methods: { select(item) { // 處理CascaderItem組件內左側列點擊事件,item為當前點擊的對象 // 向上一級發射一個change事件,通知上層進行修改,并將當前點擊的層級level和item傳遞過去 this.$emit("change", {level: this.level, item: item}); } } }
由于CascaderItem是遞歸調用的,所以現在的組件調用關系為: Cascader --> CascaderItem --> CascaderItem --> CascaderItem --> ......
頂層父組件為Cascader,所以CascaderItem也可能是CascaderItem的父組件,CascaderItem組件自身也需要監聽change事件,主要就是負責將數據改變信號傳遞到Cascader頂層父組件上,如:
// CascaderItem.vue給CascaderItem組件添加一個change事件處理方法
export default { methods: { change(newValue) { // 向頂層傳遞數據改變信息 this.$emit("change", newValue); } } }
頂層父組件Cascader接收到數據改變信號后,就需要改變selectedItems數據了,即將用戶的選擇項添加到對應的位置,如:
// Cascader.vue 添加change事件處理函數
export default { methods: { change(newValue) { this.selectedItems.splice(newValue.level, 1, newValue.item); // 替換當前點擊位置信息 this.selectedItems.splice(newValue.level + 1); // 刪除當前點擊位置之后的數據 } } }
Cascader組件除了替換掉指定level中的數據外,還需要將當前level之后的數據刪除掉,否則當前level之后的數據還在,導致右側路徑仍然保留而顯示不一致。
至此,一個簡單的級聯組件就實現了,可以在App.vue中直接使用,如:
// App.vue
三、總結
整個Cascader組件設計思路就是: 在頂層父組件Cascader中添加一個selectedItems數組,用于保存用戶點擊的level層級(列序號)和對應的item對象,同時用于生成用戶的選擇路徑,當用戶點擊了CascaderItem組件的左側列中某項后,通過層層傳遞事件的方式通知頂層父組件Cascader對其數據進行更新,頂層父組件Cascader更新數據后,CascaderItem組件從selectedItems中取出對應level的item對象,然后獲取item的children并遍歷顯示右側列
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/110003.html
摘要:第十集從零開始實現計數器組件本集定位聽到計數器這個名字很多人是不是一瞬間沒有什么印象畢竟這個組件用的比較少就是那種左邊一個右邊一個控制某些數量的時候才會用到比如我之前做的商城小程序只有下單頁面的規格彈出框里面才有他的身影如果是涉及到處理商 第十集: 從零開始實現( 計數器組件 ) 本集定位: 聽到計數器這個名字很多人是不是一瞬間沒有什么印象, 畢竟這個組件用的比較少,就是那種左邊...
摘要:第十集從零開始實現計數器組件本集定位聽到計數器這個名字很多人是不是一瞬間沒有什么印象畢竟這個組件用的比較少就是那種左邊一個右邊一個控制某些數量的時候才會用到比如我之前做的商城小程序只有下單頁面的規格彈出框里面才有他的身影如果是涉及到處理商 第十集: 從零開始實現( 計數器組件 ) 本集定位: 聽到計數器這個名字很多人是不是一瞬間沒有什么印象, 畢竟這個組件用的比較少,就是那種左邊...
摘要:第二集從零開始實現組件本集定位這套組件我本來是先從做的但是我發現每個組件都要用到這個組件如果沒有他很多組件沒法擴展而且本身不依賴其他組件所以還是先把它作為本篇文章的重點吧組件讀過源碼的同學都知道他們選擇的是字體圖標的方式來做組件的而我的這 第二集: 從零開始實現(icon組件) 本集定位: 這套ui組件我本來是先從button做的, 但是我發現每個組件都要用到icon這個組件, 如...
摘要:第二集從零開始實現組件本集定位這套組件我本來是先從做的但是我發現每個組件都要用到這個組件如果沒有他很多組件沒法擴展而且本身不依賴其他組件所以還是先把它作為本篇文章的重點吧組件讀過源碼的同學都知道他們選擇的是字體圖標的方式來做組件的而我的這 第二集: 從零開始實現(icon組件) 本集定位: 這套ui組件我本來是先從button做的, 但是我發現每個組件都要用到icon這個組件, 如...
閱讀 2716·2021-09-24 09:47
閱讀 4366·2021-08-27 13:10
閱讀 2981·2019-08-30 15:44
閱讀 1281·2019-08-29 12:56
閱讀 2593·2019-08-28 18:07
閱讀 2614·2019-08-26 14:05
閱讀 2551·2019-08-26 13:41
閱讀 1265·2019-08-26 13:33