? ? ? 其實最開始并沒有采用Vuex茬末,因為Vuex相對于$emit這類事件監(jiān)聽需要多寫很多代碼厂榛,而且步驟也是比較繁瑣,如果你想保持一個狀態(tài)管理庫,那么你就按照Vue指定的套路出牌击奶,需要提交mutations來統(tǒng)一改變狀態(tài)辈双。最開始采用$emit事件監(jiān)聽的方式,因為會有增刪改的操作柜砾,就由父組件監(jiān)聽湃望,然后將data數(shù)據(jù)源逐級傳遞,但當層級變大的時候局义,數(shù)據(jù)變得難以維護喜爷,大量的監(jiān)聽操作,相對于不可控性萄唇,還是選擇了Vuex穩(wěn)妥的作為統(tǒng)一倉庫管理檩帐。
Vuex設(shè)計
? ? ? ?Vuex不做詳細介紹了,可以搜索文章自己去理解另萤,總之你如果使用Vuex就要遵循一個原則湃密,你如果需要修改store中的某個狀態(tài),一定要通過commit-mutations的形式或者異步提交dispatch的形式四敞,這樣你可以跟蹤一些狀態(tài)的變化泛源,這是一個行為上的約束,你也可以直接修改state忿危,那么當數(shù)據(jù)狀態(tài)出錯的時候并不能定位到原因所在达箍。
store下新建index.js
我的項目中目前維護了兩種狀態(tài)一種是Tree數(shù)據(jù),一種是公共的loading的狀態(tài)铺厨,為了可拓展性缎玫,將index.js分離成modules的形式,每新增一個狀態(tài)庫只需要增加一條解滓,而不需要頻繁修改index.js的代碼赃磨。
data_store.js是本文主要講的數(shù)據(jù)的倉庫如下:
很簡單,修改data與提交的操作洼裤。
倉庫寫好了邻辉,那么現(xiàn)在就開始交互的部分。
需求是腮鞍,每點擊一層值骇,那么就去請求后臺獲取他下一層的數(shù)據(jù),有數(shù)據(jù)則展開下拉缕减。并且每一個node節(jié)點都有增刪改的功能雷客。好一樣樣來寫
開發(fā)前先寫一個公共類庫,集中一些axios請求和工具函數(shù)桥狡。首先搅裙,想一下交互的思路皱卓,已知后臺會返回每一節(jié)點的唯一id,點擊這個節(jié)點的時候根據(jù)id向后臺發(fā)送請求獲取當前id下一層數(shù)據(jù)部逮,當?shù)玫揭粋€節(jié)點的數(shù)組的時候如何插入store中的data倉庫娜汁?換句話說插入到data中的哪一層?刪除也是一樣兄朋,得到點擊id了掐禁,那么刪除data的哪一層節(jié)點?因為是數(shù)據(jù)驅(qū)動視圖颅和,所以我們只增刪改data倉庫傅事,那么Dom就會觸發(fā)相應的更新。因此需要一些遞歸函數(shù)來輔助操作峡扩。
新建api.js
1.封裝后臺Post請求
2.封裝接口:
3.遞歸添加與刪除公共方法
遞歸:傳入id和對比的對象數(shù)組蹭越,首先對比根層級,如果id匹配執(zhí)行相應的增刪教届,如果不匹配則向下nodes[]中去查找响鹃,還不存在則遞歸查找。上面兩個函數(shù)封裝了后臺獲取數(shù)據(jù)增加與刪除的函數(shù)案训,還需要封裝自定義添加的函數(shù)买置,可以自定義添加數(shù)據(jù),而不是后臺獲取的數(shù)據(jù)强霎,原理相同忿项,只是增加一個數(shù)據(jù)模板。
函數(shù)比較簡單就是一個遞歸函數(shù)城舞,封裝好那么就在TreeMenu.vue進行調(diào)用了 倦卖,引入(后邊還會添加一些公共函數(shù),這里就先引入了椿争,就不逐步截圖了)
添加loadTreeNode后臺獲取節(jié)點的函數(shù):
? ? ? ?首先會傳遞一個id,根據(jù)id向后臺發(fā)送請求熟嫩,然后獲取到數(shù)據(jù)按照定義好的格式push進一個臨時的對象dataCache秦踪。這里要說明一下為什么沒有直接push進store中的data倉庫,而是先全部push進一個臨時對象呢掸茅?我對Vuex的理解是椅邓,他是一個倉庫,你去取東西或者存東西昧狮,你是一樣樣的去放景馁,還是等這次的數(shù)據(jù)都準備好了再去一次性的去放?為了便于跟蹤狀態(tài)變化(store的debugger模式或者VueTools)逗鸣,我選擇將這次請求的數(shù)據(jù)作為一次狀態(tài)變化去改變合住。下面的遞歸插入也是一樣绰精,都是臨時設(shè)置一個數(shù)組,只操作這個臨時的數(shù)組而不去頻繁去修改store中的數(shù)據(jù)透葛,最后一次修改笨使,這樣的結(jié)果會更準確定位狀態(tài)變化,也不會頻繁修改倉庫造成不可控的后果僚害,唯一的影響可能會有幾十ms的循環(huán)延遲硫椰,相比較于安全性,這幾十ms的性能不考慮萨蚕。
在上篇文章預先寫好的toggleChildren方法插入如下代碼:
這樣就為每一層node節(jié)點綁定了點擊事件靶草,點擊獲取數(shù)據(jù)顯示。但是這只是點擊事件岳遥,那么第一次加載頁面的時候是沒有根數(shù)據(jù)的啊奕翔,所以要在Tree.vue中寫一個初始化的函數(shù),初始加載根節(jié)點:
這樣一個樹狀菜單點擊加載就做好了
自定義添加與刪除
TreeMenu.vue新建兩個按鈕:
綁定方法:
dataTemplate是一個添加的數(shù)據(jù)模板糠悯,可自定義添加,this.count是定義的一個變量妻往,保證每次id都不同互艾。實際上添加和刪除是要走后臺的,上面寫的這種是前端頁面的添加與刪除讯泣,因為需求變了纫普,所以沒有繼續(xù)往下寫,但是思路和上面后臺獲取添加是一樣的好渠,點擊傳遞id給后臺昨稼,如果后臺返回成功那么就執(zhí)行自定義添加或者刪除的代碼就是了。現(xiàn)在是這樣的效果:
一個基本的樹狀菜單就開發(fā)完成了拳锚,改這個操作也很簡單假栓,說一下就不寫了,點擊修改將當前標題標簽切換成input標簽霍掺,輸入完成再賦值給當前元素即可匾荆,也是要向后臺傳遞的。還有一些可以優(yōu)化的地方杆烁,現(xiàn)在每次點擊都會發(fā)送axios請求牙丽,需要優(yōu)化一下:
在loadTreeNode這個方法中,給data新增一條屬性兔魂,來標記是否加載:
在api.js添加公共函數(shù)
然后在每次點擊的時候判斷當前id的isLoad是否為true烤芦,為真則return
現(xiàn)在樹形插件已經(jīng)開發(fā)完成了,需要根據(jù)上一篇來一起實現(xiàn)析校,鏈接:Vue遞歸組件+Vuex開發(fā)樹形組件Tree?构罗。
因為當時使用element-ui組件樹铜涉,各種bug,無奈自己手寫一個組件樹插件绰播,時間比較倉促骄噪,有些優(yōu)化和封裝的地方?jīng)]有去考慮,找個時間封裝個組件蠢箩。
謝謝链蕊!