實(shí)現(xiàn)一個(gè)可無限折疊的table

如何在table上實(shí)現(xiàn)一個(gè)可折疊展開子節(jié)點(diǎn)的table舷手?先看下最終實(shí)現(xiàn)效果圖:

技術(shù)棧:

  • vue
  • javascript

動手實(shí)現(xiàn)

為有興趣的同學(xué)先準(zhǔn)備一下大綱目錄預(yù)覽担巩,為了不讓同學(xué)們看入迷佳头,讓大綱為你 指明前行的道路 竖瘾!

大綱預(yù)覽

  1. 明確需求
  2. 樹形結(jié)構(gòu)數(shù)據(jù)準(zhǔn)備
  3. 數(shù)據(jù)扁平化 (重點(diǎn))
  4. 層級展示
  5. 折疊展開功能實(shí)現(xiàn)

1. 明確需求

實(shí)現(xiàn)一個(gè)可折疊展開的table桃煎,看上去很迷茫的樣子醋拧。但實(shí)際上就是:

  1. table 上點(diǎn)擊時(shí)對其 子集 進(jìn)行 隱藏顯示
  2. 通過縮進(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í)候要做的處理。這里深入梳理一下:

  1. 我們將一個(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) 就乖乖的隱藏吧唁盏。

  2. 每個(gè)成員都因該是唯一的内狸,那么我們在遍歷時(shí)都應(yīng)該為每個(gè)成員添加一個(gè)唯一標(biāo)識 __identity 。正是上一個(gè)步驟中說的 節(jié)點(diǎn)標(biāo)志 厘擂。

  3. 為了明確知道各個(gè)節(jié)點(diǎn)之間的層級關(guān)系昆淡,通過 __level 明確層級關(guān)系。那么我們規(guī)定 __level 的值越小等級越高刽严。 __level=0 代表首層節(jié)點(diǎn)昂灵。

  4. 既然是無限層級,肯定是用遞歸來實(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ì)崎弃,有問題歡迎留言溝通~~

數(shù)據(jù)扁平化

/*********************************
 ** 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
<i :class="toggleFoldingClass(scope.row)"></i>

//    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 值增大邮弹。如代碼:
<p :style="`margin-left: ${scope.row.__level * 20}px;`">...

基本的樣子已經(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
<i  @click="toggleFoldingStatus(scope.row)" class="permission_toggleFold" :class="toggleFoldingClass(scope.row)"></i>
//    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)矛双。來看下官方的說明

![](http://upload-images.jianshu.io/upload_images/13661853-aeb3373889e7cc00.png!web?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

該方法就是為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ì)喲~

文章出處:https://juejin.im/post/5be797456fb9a04a0378bb91皂冰。歡迎大家前去點(diǎn)贊支持~店展!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秃流,隨后出現(xiàn)的幾起案子赂蕴,更是在濱河造成了極大的恐慌,老刑警劉巖舶胀,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件概说,死亡現(xiàn)場離奇詭異,居然都是意外死亡峻贮,警方通過查閱死者的電腦和手機(jī)席怪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門应闯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纤控,“玉大人,你說我怎么就攤上這事碉纺〈颍” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵骨田,是天一觀的道長耿导。 經(jīng)常有香客問我,道長态贤,這世上最難降的妖魔是什么舱呻? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮悠汽,結(jié)果婚禮上箱吕,老公的妹妹穿的比我還像新娘。我一直安慰自己柿冲,他們只是感情好茬高,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著假抄,像睡著了一般怎栽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宿饱,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天熏瞄,我揣著相機(jī)與錄音,去河邊找鬼谬以。 笑死强饮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛉签。 我是一名探鬼主播胡陪,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼沥寥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了柠座?” 一聲冷哼從身側(cè)響起邑雅,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妈经,沒想到半個(gè)月后淮野,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吹泡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年骤星,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爆哑。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洞难,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出揭朝,到底是詐尸還是另有隱情队贱,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布潭袱,位于F島的核電站柱嫌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屯换。R本人自食惡果不足惜编丘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望彤悔。 院中可真熱鬧嘉抓,春花似錦、人聲如沸蜗巧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幕屹。三九已至蓝丙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間望拖,已是汗流浹背渺尘。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留说敏,地道東北人鸥跟。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親医咨。 傳聞我的和親對象是個(gè)殘疾皇子枫匾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容