el-tree check-strictly但父子關(guān)聯(lián)+虛擬滾動(dòng)

1. 設(shè)置check-strictly可選擇各層級(jí)且父子數(shù)關(guān)聯(lián)

<!-- child.vue -->
<template>
  <div class="select-tree-container">
    <el-popover
      placement="bottom-start"
      popper-class="select-tree-popper"
      v-model="isShowSelect"
      @hide="closePopver"
    >
      <el-tree
        ref="tree"
        :data="treeData"
        node-key="id"
        default-expand-all
        :expand-on-click-node="false"
        check-strictly
        check-on-click-node
        show-checkbox
        :default-expanded-keys="defaultKey"
        @check="nodeClick"
      ></el-tree>

      <el-select
        slot="reference"
        ref="select"
        v-model="selectVal"
        multiple
        @remove-tag="removeTag"
      >
        <el-option
          v-for="item in options"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        ></el-option>
      </el-select>
    </el-popover>
  </div>
</template>
 
<script>
export default {
  name: 'SelectTree',
  props: {
    // 樹(shù)結(jié)構(gòu)數(shù)據(jù)
    treeData: {
      type: Array,
      default() {
        return [];
      },
    },
    // 默認(rèn)選中的節(jié)點(diǎn)key
    defaultKey: {
      type: Array,
      default() {
        return [];
      },
    }
  },
  data() {
    return {
      isShowSelect: false, // 是否顯示樹(shù)狀選擇器
      options: [],
      returnDatas: [], // 返回給父組件數(shù)組對(duì)象
      selectVal: []
    }
  },
  created () {
  },
  watch: {
    // 隱藏select自帶的下拉框
    isShowSelect() {
      this.$refs.select.blur();
    }
  },
  methods: {
    // 節(jié)點(diǎn)被點(diǎn)擊
    nodeClick(v) {
      const anode = this.$refs.tree.getNode(v)
      if (anode.checked) {
        this.setParentChecked(anode.parent)
        this.setChildChecked(anode.childNodes)
      } else {
        this.deleteParentChecked(anode.parent)
        this.deleteChildChecked(anode.childNodes)
      }

      var checkedKeys = this.$refs.tree.getCheckedKeys() // 所有被選中的節(jié)點(diǎn)的 key 所組成的數(shù)組數(shù)據(jù)

      this.options = checkedKeys.map(item => {
        const node = this.$refs.tree.getNode(item) // 所有被選中的節(jié)點(diǎn)對(duì)應(yīng)的node

        if (node.level === 1) { // 第一層
          node.hide = false
        } else {
          node.hide = !node.parent.indeterminate &&  node.parent.checked
        }

        // 設(shè)置option選項(xiàng)
        return {
          ...node,
          label: node.label,
          value: node.key
        }
      })

      this.returnDatas = this.selectVal = this.options.filter(o => !o.indeterminate && !o.hide).map(item => item.value)
      this.closePopver()
    },
    // 如果不是全選中為父級(jí)添加半選狀態(tài)憔晒,如果子集全選后锣尉,父級(jí)也要全選
    setParentChecked(parent) {
      const fnode = this.$refs.tree.getNode(parent)
      // 子集是否是全選
      const isAllChecked = fnode.childNodes.every(k => k.checked && k.indeterminate === false)
      if (!fnode.isLeaf) {
        fnode.indeterminate = !isAllChecked // 子集是否是全選卿城,如果子集全選粮彤,則半選狀態(tài)為假
        fnode.checked = true
      }
      if (fnode.parent) {
        this.setParentChecked(fnode.parent)
      }
    },
    // 將子節(jié)點(diǎn)全選中
    setChildChecked(childNodes) {
      if (childNodes && childNodes.length > 0) {
        childNodes.map(k => {
          k.checked = true
          this.setChildChecked(this.$refs.tree.getNode(k).childNodes)
        })
      }
    },
    // 如果取消子節(jié)點(diǎn)的選中,設(shè)置父級(jí)節(jié)點(diǎn)選中狀態(tài)
    deleteParentChecked(parent, d = false) {
      const fnode = this.$refs.tree.getNode(parent)
      const isAllChecked = fnode.childNodes.some(k => d ? (k.checked || k.indeterminate) : k.checked) // 子集是否是全選
      if (!fnode.isLeaf) {
        fnode.indeterminate = isAllChecked // 子集是否是全選,如果子集全選黎侈,則半選狀態(tài)為假
        fnode.checked = isAllChecked
        if (fnode.parent) { // 如果有父節(jié)點(diǎn)筹陵,則需要去判斷父節(jié)點(diǎn)是否選中
          this.deleteParentChecked(fnode.parent, true)
        }
      }
    },
    // 刪除子節(jié)點(diǎn)的勾選狀態(tài)
    deleteChildChecked(childNodes) {
      if (childNodes && childNodes.length > 0) {
        childNodes.map(k => {
          k.indeterminate = false
          k.checked = false
          this.deleteChildChecked(this.$refs.tree.getNode(k).childNodes)
        })
      }
    },
    // 刪除任一 select 選項(xiàng)
    removeTag(val) {
      this.$refs.tree.setChecked(val, false); // 設(shè)置節(jié)點(diǎn)的勾選狀態(tài)為未選中
      this.nodeClick(val)
    },
    // 清空所有勾選
    clearSelectedNodes() {
      this.selectVal = this.returnDatas = []
      this.$refs.tree.setCheckedKeys([])
    },
    // 下拉框關(guān)閉
    closePopver() {
      this.$emit("get:value", this.selectVal, this.returnDatas);
    }
  }
};
</script>
 
<style lang="scss">
  .select-tree-container {
    .el-select {
      width: 280px;
    }
  }

  .select-tree-popper {
    box-sizing: border-box;
    width: 280px;
  }
</style>
<template>
  <div class="app-container">
    <select-tree
      :tree-data="treeData"
      :defaultKey="defaultCheckedKeys"
      @get:value="getTreeVal"
    />
  </div>
</template>

<script>
import SelectTree from '@/components/SelectTree.vue';

export default {
  components: { SelectTree },
  name: "App",
   data() {
    return {
      treeData: [
        {
          id: 1,
          label: "水果",
          children: [
            { 
              id: 4, 
              label: '香蕉',
              children: [
                { id: 41, label: '小香蕉' },
                { id: 42, label: '大香蕉' },
              ]
            },
            { 
              id: 5, 
              label: '圣女果',
              children: [
                { id: 51, label: '小圣果' },
                { id: 52, label: '大圣果' },
              ] 
            }
          ]
        },
        {
          id: 2,
          label: "食物",
          children: [
            { id: 6, label: '龍蝦' },
            { id: 7, label: '螃蟹' }
          ]
        }
      ],
      defaultCheckedKeys: []
    }
  },
  methods: {
    getTreeVal(val, data) {
      // console.log(val, data);
    }
  }
};
</script>

2. 增加虛擬滾動(dòng)

  1. 安裝vue-virtual-scroll-list
$ yarn add vue-virtual-scroll-list
  1. tree-virtual-node.vue中增加以下方法,否則點(diǎn)擊收起箭頭無(wú)效果

  2. el-tree改為virtual-tree彪蓬,其余參數(shù)都一致

<!-- child.vue -->
<template>
  <div class="select-tree-container">
    ...
    <virtual-tree
      ref="tree"
      :data="treeData"
      node-key="id"
      default-expand-all
      :expand-on-click-node="false"
      check-strictly
      check-on-click-node
      show-checkbox
      :default-expanded-keys="defaultKey"
      @check="nodeClick"
    ></virtual-tree>
    ...
  </div>
</template>
 
<script>
import VirtualTree from './virtualNodeTree/tree'

export default {
  name: 'SelectTree',
  components: { VirtualTree }
}
</script>

3. 效果圖

4. 參考文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捺萌,一起剝皮案震驚了整個(gè)濱河市档冬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌互婿,老刑警劉巖捣郊,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異慈参,居然都是意外死亡呛牲,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)驮配,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)娘扩,“玉大人,你說(shuō)我怎么就攤上這事壮锻∷雠裕” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵猜绣,是天一觀的道長(zhǎng)灰殴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)掰邢,這世上最難降的妖魔是什么牺陶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮辣之,結(jié)果婚禮上掰伸,老公的妹妹穿的比我還像新娘。我一直安慰自己怀估,他們只是感情好狮鸭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著多搀,像睡著了一般歧蕉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上康铭,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天廊谓,我揣著相機(jī)與錄音,去河邊找鬼麻削。 笑死蒸痹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呛哟。 我是一名探鬼主播叠荠,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扫责!你這毒婦竟也來(lái)了榛鼎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鳖孤,失蹤者是張志新(化名)和其女友劉穎者娱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體苏揣,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黄鳍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了平匈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片框沟。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖增炭,靈堂內(nèi)的尸體忽然破棺而出忍燥,到底是詐尸還是另有隱情,我是刑警寧澤隙姿,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布梅垄,位于F島的核電站,受9級(jí)特大地震影響输玷,放射性物質(zhì)發(fā)生泄漏队丝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一饲嗽、第九天 我趴在偏房一處隱蔽的房頂上張望炭玫。 院中可真熱鬧,春花似錦貌虾、人聲如沸吞加。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)衔憨。三九已至,卻和暖如春袄膏,著一層夾襖步出監(jiān)牢的瞬間践图,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工沉馆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留码党,地道東北人德崭。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像揖盘,于是被迫代替她去往敵國(guó)和親眉厨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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