摘要:但實(shí)際上就是在上點(diǎn)擊時(shí)對其子集進(jìn)行隱藏或顯示通過縮進(jìn)的距離來表現(xiàn)層級關(guān)系在代碼里很東西其實(shí)都是偽裝出來的,例如我們要實(shí)現(xiàn)的這個(gè)可無限折疊的。
前言
如何在table上實(shí)現(xiàn)一個(gè)可折疊展開子節(jié)點(diǎn)的table?先看下最終實(shí)現(xiàn)效果圖:
其實(shí)這個(gè)項(xiàng)目在兩個(gè)月以前就以上上傳在github了,但當(dāng)時(shí)沒有寫詳細(xì)的實(shí)現(xiàn)過程。自己前幾天發(fā)表的一篇技術(shù)貼當(dāng)下拉列表數(shù)據(jù)過大時(shí),該如何應(yīng)對?得到大家的不少支持,猶如歌曲《紅日》里的歌詞像紅日之火 點(diǎn)燃真的我~ 所以繼續(xù)為掘金社區(qū)做奉獻(xiàn)自己微不足道的力量啦 ~~在周末聽著嗨歌寫文還是很nice的~ 嗨起來 ~ ~
項(xiàng)目地址:: 源碼傳送門
demo: demo傳送門
順便推一下:為何要再封裝 AJAX?
技術(shù)棧:
vue
javascript
動手實(shí)現(xiàn)為有興趣的同學(xué)先準(zhǔn)備一下大綱目錄預(yù)覽,為了不讓同學(xué)們看入迷,讓大綱為你指明前行的道路!
大綱預(yù)覽明確需求
樹形結(jié)構(gòu)數(shù)據(jù)準(zhǔn)備
數(shù)據(jù)扁平化(重點(diǎn))
層級展示
折疊展開功能實(shí)現(xiàn)
1. 明確需求實(shí)現(xiàn)一個(gè)可折疊展開的table,看上去很迷茫的樣子。但實(shí)際上就是:
在table上點(diǎn)擊時(shí)對其子集進(jìn)行隱藏或顯示
通過縮進(jìn)的距離來表現(xiàn)層級關(guān)系
在代碼里很東西其實(shí)都是偽裝出來的,例如我們要實(shí)現(xiàn)的這個(gè)可無限折疊的table。但在用戶操作的時(shí)候看來就是那么回事咯 ~ ~
2. 樹形結(jié)構(gòu)數(shù)據(jù)準(zhǔn)備這里已經(jīng)準(zhǔn)備好了樹形結(jié)構(gòu)的數(shù)據(jù),存放于data.js的文件中,節(jié)點(diǎn)通過Children連接。如標(biāo)題所說,可無限折疊,無論這里的樹形數(shù)據(jù)有多少層級,都能給它辦妥當(dāng)了。先把牛吹在這,接下來看看如何實(shí)現(xiàn)。
3. 數(shù)據(jù)扁平化 條件梳理樹形結(jié)構(gòu)數(shù)據(jù)扁平化并不難,難點(diǎn)在于在扁平化的時(shí)候要做的處理。這里深入梳理一下:
數(shù)據(jù)扁平化我們將一個(gè)樹節(jié)點(diǎn)的所有父節(jié)點(diǎn)稱為family,好比我們要知道的自己的大領(lǐng)導(dǎo)、二領(lǐng)導(dǎo)、直系領(lǐng)導(dǎo)...因?yàn)樗麄兊拿钤蹅兌嫉脠?zhí)行。在這個(gè)表單中就是當(dāng)父節(jié)點(diǎn)或更高的祖輩節(jié)點(diǎn)發(fā)命令時(shí),做一個(gè)懂事的子節(jié)點(diǎn)當(dāng)然要聽話辦事。__family字段就是用來存放所有所有的父節(jié)點(diǎn)的數(shù)組。在扁平化數(shù)據(jù)是通過數(shù)組字段__family收集其所有父節(jié)點(diǎn)。這樣一來,就像族譜一樣,就能清晰知道該節(jié)點(diǎn)的所有父節(jié)點(diǎn)。至于如和折疊收縮呢?我們通過一個(gè)foldList數(shù)組來記錄要折疊的節(jié)點(diǎn),也稱為死亡名單。如此一來,只要包含父節(jié)點(diǎn)標(biāo)識的節(jié)點(diǎn)就乖乖的隱藏吧。
每個(gè)成員都因該是唯一的,那么我們在遍歷時(shí)都應(yīng)該為每個(gè)成員添加一個(gè)唯一標(biāo)識__identity。正是上一個(gè)步驟中說的節(jié)點(diǎn)標(biāo)志。
為了明確知道各個(gè)節(jié)點(diǎn)之間的層級關(guān)系,通過__level明確層級關(guān)系。那么我們規(guī)定__level的值越小等級越高。__level=0代表首層節(jié)點(diǎn)。
既然是無限層級,肯定是用遞歸來實(shí)現(xiàn)了。formatConversion()方法實(shí)現(xiàn)遞歸。那何時(shí)跳出當(dāng)前遍歷的遞歸呢?當(dāng)前節(jié)點(diǎn)沒有子集時(shí)Children.length = 0的時(shí)候跳出本次遞歸,進(jìn)行下一次遞歸。該方法可能需要花點(diǎn)時(shí)間理解,代碼里注釋已寫的比較詳細(xì),有問題歡迎留言溝通~~
/********************************* ** Fn: formatConversion ** Intro: 將樹形接口數(shù)據(jù)扁平化 ** @params: parent 為當(dāng)前累計(jì)的數(shù)組 也是最后返回的數(shù)組 ** @params: children 為當(dāng)前節(jié)點(diǎn)仍需繼續(xù)扁平子節(jié)點(diǎn)的數(shù)據(jù) ** @params: index 默認(rèn)等于0, 用于在遞歸中進(jìn)行累計(jì)疊加 用于層級標(biāo)識 ** @params: family 裝有當(dāng)前包含元素自身的所有父級 身份標(biāo)識 ** @params: elderIdentity 父級的 唯一身份標(biāo)識 ** Author: zyx *********************************/ formatConversion (parent, children, index = 0, family = [], elderIdentity = "x") { // children如果長度等于0,則代表已經(jīng)到了最低層 // let page = (this.startPage - 1) * 10 if (children.length > 0) { children.map((x, i) => { // 設(shè)置 __level 標(biāo)志位 用于展示區(qū)分層級 Vue.set(x, "__level", index) // 設(shè)置 __family 為家族關(guān)系 為所有父級,包含本身在內(nèi) Vue.set(x, "__family", [...family, elderIdentity + "_" + i]) // 本身的唯一標(biāo)識 可以理解為個(gè)人的身份證咯 一定唯一。 Vue.set(x, "__identity", elderIdentity + "_" + i) parent.push(x) // 如果仍有子集,則進(jìn)行遞歸 if (x.Children.length > 0) this.formatConversion(parent, x.Children, index + 1, [...family, elderIdentity + "_" + i], elderIdentity + "_" + i) }) } return parent }
我們來對比一下扁平話的數(shù)據(jù)
原數(shù)據(jù)
扁平化后的數(shù)據(jù)
對比數(shù)據(jù)的前后,先明確(父節(jié)點(diǎn): Name: "App"), (子節(jié)點(diǎn):Name: "企業(yè)查詢")。我們先看看__level字段,分別對應(yīng)0和1,沒問題。__family包含了本身節(jié)點(diǎn)。__identity的個(gè)格式就是前綴 x加上在數(shù)據(jù)中的位置。例如節(jié)點(diǎn)App在數(shù)據(jù)中的位置是第一個(gè)節(jié)點(diǎn),那對應(yīng)的__identity即是x_0。企業(yè)查詢位于App節(jié)點(diǎn)下的第一個(gè)元素,則在父節(jié)點(diǎn)的標(biāo)識的基礎(chǔ)上追加一位0,那對應(yīng)的__identity即是x_0_0。其他依次類推。一切已準(zhǔn)備妥當(dāng)~~4. 層級展示
如圖所示:
如果展示層級呢?利用css即可實(shí)現(xiàn)
字體圖標(biāo)準(zhǔn)備: 這里先補(bǔ)充一點(diǎn),這里涉及兩個(gè)字體圖標(biāo),圖中紅色框標(biāo)注的,資源存放于src目錄下的iconfont目錄下中。層級最低的字段時(shí)不需要展示該圖標(biāo)呢,該如何判斷呢? 通過判斷當(dāng)前節(jié)點(diǎn)是否還有子集params.Children.length === 0即可判斷。若沒有子集則不設(shè)置字體圖標(biāo)即可。點(diǎn)擊時(shí)還需要對圖標(biāo)進(jìn)行切換,這又如何實(shí)現(xiàn)呢?前臺提到過的死亡名單foldList,如果該存在該名單中,代表該數(shù)據(jù)已經(jīng)被折疊,那返回折疊圖標(biāo)。否則返回展開圖標(biāo)。如代碼:
// html // js methods: /********************************* ** Fn: toggleFoldingClass ** Intro: 如果子集長度為0,則不返回字體圖標(biāo)。 ** Intro: 如果子集長度為不為0,根據(jù)foldList是否存在當(dāng)前節(jié)點(diǎn)的標(biāo)識返回相應(yīng)的折疊或展開圖標(biāo) ** Intro: 關(guān)于class說明:permission_placeholder返回一個(gè)占位符,具體查看class ** @params: params 當(dāng)前行的數(shù)據(jù)對象 ** Author: zyx *********************************/ toggleFoldingClass (params) { return params.Children.length === 0 ? "permission_placeholder" : (this.foldList.indexOf(params.__identity) === -1 ? "iconfont icon-minus-square-o" : "iconfont icon-plussquareo") },
層級展示: __level字段就是這時(shí)候發(fā)揮用處。__level值越大,則將margin-left值增大。如代碼:
...
基本的樣子已經(jīng)有了,那接下來實(shí)現(xiàn)點(diǎn)擊功能。
5. 折疊展開功能實(shí)現(xiàn) 記錄點(diǎn)擊的節(jié)點(diǎn)標(biāo)識通過死亡名單foldList來記錄點(diǎn)擊。點(diǎn)擊事件在點(diǎn)擊折疊展開圖標(biāo)時(shí)觸發(fā)toggleFoldingStatus(scope.row)事件,前面也說過,foldList存在的標(biāo)識,對于所有的子節(jié)點(diǎn)都要隱藏起來。如果foldList沒有數(shù)據(jù),則全部展開,萬事大吉。代碼如圖所示,就是那么簡單。
// html // js methods /********************************* ** Fn: toggleFoldingStatus ** Intro: 切換展開 還是折疊 ** @params: params 當(dāng)前點(diǎn)擊行的數(shù)據(jù) ** Author: zyx *********************************/ toggleFoldingStatus (params) { this.foldList.includes(params.__identity) ? this.foldList.splice(this.foldList.indexOf(params.__identity), 1) : this.foldList.push(params.__identity) },折疊展開功能實(shí)現(xiàn)
萬事俱備,只欠東風(fēng)。最后一件要做的大事就是根據(jù)死亡名單foldList來進(jìn)行顯示和隱藏?cái)?shù)據(jù)。
這里借助el-table中的row-style實(shí)現(xiàn)。同學(xué)們也可以自己實(shí)現(xiàn)。來看下官方的說明
該方法就是為table中的每一行數(shù)據(jù)設(shè)置樣式。
/********************************* ** Fn: toggleDisplayTr ** Intro: 該方法會對每一行數(shù)據(jù)都做判斷 如果foldList 列表中的元素 也存在與當(dāng)前行的 __family列表中 則該行不展示 ** @params: ** Author: zyx *********************************/ toggleDisplayTr ({row, index}) { for (let i = 0; i < this.foldList.length; i++) { let item = this.foldList[i] // 如果foldList中元素存在于 row.__family中,則該行隱藏。 如果該行的自身標(biāo)識等于隱藏元素,則代表該元素就是折疊點(diǎn) if (row.__family.includes(item) && row.__identity !== item) return "display:none;" } return "" },
在來看看效果
錦上添花如果數(shù)據(jù)太多的話,一個(gè)層級層級的去搜索確實(shí)也麻煩,所以那么我們再來添加兩個(gè)按鈕全部折疊和全部展開好了。
咨詢分析一下,其實(shí)這個(gè)功能很簡單。還是關(guān)于前面提到過的死亡名單foldList。
全部展開: 如果foldList為空,則萬事大吉,數(shù)據(jù)全部展開。
全部折疊:我們的設(shè)計(jì)是只要存在于死亡名單的所有包含該標(biāo)識的節(jié)點(diǎn)都要隱藏。那么只要將所有的首層節(jié)點(diǎn)添加進(jìn)去就可以了。this.foldList = this.tableListData.map(x => x.__identity)即取出首層節(jié)點(diǎn)的標(biāo)識。
結(jié)語更復(fù)雜的需求是結(jié)合分頁,當(dāng)從其他頁回到之前頁時(shí),之前頁的折疊狀態(tài)要依舊保持。這里就不在說明了,因?yàn)閼?yīng)用場景很少。
點(diǎn)贊給個(gè)鼓勵(lì)喲~
又是下午3點(diǎn)了,該回去吃午飯了。
版權(quán)說明:本文首發(fā)于掘金,如需轉(zhuǎn)載請注明出處。
掘金專欄地址:https://juejin.im/post/5be797...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108617.html
摘要:塊級格式化上下文。其優(yōu)點(diǎn)為自適應(yīng)內(nèi)容由于封閉而更健壯,容錯(cuò)性更強(qiáng)。兩個(gè)相鄰的外邊距都是負(fù)數(shù)時(shí),折疊結(jié)果是兩者絕對值的較大值。兩個(gè)外邊距一正一負(fù)時(shí),折疊結(jié)果是兩者的相加的和。這可能是因?yàn)闉g覽器四舍五入了列寬從而所有列的總寬度會超出容器。 BFC(block formatting context)塊級格式化上下文。 如果一個(gè)元素具有 BFC,內(nèi)部子元素?zé)o論如何都不會影響外部的元素。所以,B...
摘要:效果圖表結(jié)構(gòu)形式數(shù)據(jù)數(shù)據(jù)第一級是第二級是廣東第二級是廣西第三級是玉林第三級是北流廣東廣州天河白云廣西玉林北流深圳東莞松山湖部分獲取省一級遞歸結(jié)構(gòu)形式數(shù)據(jù)數(shù)據(jù)廣東廣州天河白云深圳東莞松山湖廣西玉林北流部分獲取省一級遞歸兩者區(qū)別數(shù)據(jù)表形式數(shù)據(jù)遞 效果圖 showImg(https://segmentfault.com/img/bVbi519?w=883&h=437); mysql表結(jié)構(gòu)形式...
摘要:盒的類型會影響其在視覺格式化模型中的表現(xiàn)。浮動元素絕對定位元素根元素都被稱為脫離文檔流其他元素被稱為文檔流內(nèi)。 視覺格式化模型 Visual Formatting Model URL:http://www.w3.org/TR/CSS2/visuren.html Translator: HaoyCn Date: 14th of Aug, 2015 本文并未全部翻譯,譯者在原文基礎(chǔ)上...
閱讀 3239·2021-11-24 09:39
閱讀 3177·2021-10-21 09:38
閱讀 2405·2019-08-29 15:28
閱讀 3748·2019-08-26 12:23
閱讀 2623·2019-08-26 12:19
閱讀 1367·2019-08-23 12:44
閱讀 2134·2019-08-23 12:02
閱讀 1006·2019-08-22 17:05