el-cascader-panel自定义角色权限页面-平铺显示+实现菜单+按钮区分显示+输入模糊搜索+点击定位展开对应的项+全选功能,checkStrictly: false的时候,获取半选的id

一.实现效果

el-cascader-panel自定义角色权限页面-平铺显示+实现菜单+按钮区分显示+输入模糊搜索+点击定位展开对应的项

在这里插入图片描述

        <el-cascader-panel
            ref="cascader"
            v-model="selectedOptions"
            class="cascader_panel"
            :present-text="keyword"
            filterable
            :props="cascaderProps"
            show-checkbox
            :options="permissionTree"
            :active-path.sync="activePath"
            @change="handleCascaderChange"
          >
            <template slot-scope="{ node, data }">
              <!-- 判断为按钮 -->
              <span v-if="data.menuType === 3" style="color: #2c69d8;">{{ data.menuName }}</span>
              <span v-else>{{ data.menuName }}</span>
            </template>
          </el-cascader-panel>
   cascaderProps: {
        value: 'menuId',
        multiple: true, children: 'childrenMenu',
        label: 'menuName',
        emitPath: false,
        id: 'menuId'
      },

输入模糊搜索+点击定位展开对应的项

    <div class="searchForm">
          <el-checkbox v-model="selectCheckedAll" class="all_checkbox" @change="selectAll">全选</el-checkbox>
          <div class="button">
            <el-input
              v-model="keyword"
              clearable
              placeholder="请输入菜单名称"
              prefix-icon="el-icon-search"
              size="small"
              style="width: 500px;"
              @input="handleInput"
            />
            <div v-if="selectedList&&selectedList.length && showselectedList" class="autocomplete_list">
              <div v-for="item in selectedList" :key="item.namePath" class="autocomplete_list_item" @click="autocompleteClick(item)">
                {{ item.namePath }}
              </div>
            </div>
          </div>
        </div>
    // // 处理树结构图标
    _processTree(treeData) {
      if (treeData && treeData.length) {
        for (let index = 0; index < treeData.length; index++) {
          const item = treeData[index]
          if (item.childrenButton && item.childrenButton.length > 0) {
            item.expanded = false
            treeData[index].childrenMenu = item.childrenButton
          }
          if (!this.allSelectedOptions.includes(item.menuId)) {
            this.allSelectedOptions.push(item.menuId)
          }
          if (item.childrenMenu && item.childrenMenu.length > 0) {
            this._processTree(item.childrenMenu)
          } else {
            delete item.childrenMenu
          }
        }
      }
      return treeData
    },
    selectAll(value) {
      if (value) {
        this.selectedOptions = [...this.allSelectedOptions]
      } else {
        this.selectedOptions = []
      }
    },
    //点击
    autocompleteClick(item) {
      const nodeList = []
      item.idPath && item.idPath.forEach((iItem, index) => {
        console.log('🚀 ~ item.idPath&&item.idPath.forEach ~ iItem:', iItem)
        nodeList.push(this.$refs.cascader.getNodeByValue(item.idPath.slice(0, index + 1)))
      })
      nodeList.forEach(item => {
        this.$refs.cascader.handleExpand(item, true)
      })
      this.activePath = item.idPath
      this.keyword = item.namePath
      this.showselectedList = false
    },
      searchTree(node, target) {
      if (!node) return []

      const paths = []
      const search = (node, path) => {
        if (node.menuName.includes(target)) {
          paths.push(path.slice()) // 使用slice()来复制路径
        }

        if (node.childrenMenu) {
          for (let i = 0; i < node.childrenMenu.length; i++) {
            path.push({
              menuName: node.childrenMenu[i].menuName,
              menuId: node.childrenMenu[i].menuId
            })
            search(node.childrenMenu[i], path)
            path.pop() // 回溯,移除当前节点
          }
        }
      }

      search(node, []) // 初始路径为空数组
      return paths
    },
    handleCascaderChange() {
      if (this.selectedOptions.length === this.allSelectedOptions.length) {
        this.selectCheckedAll = true
      } else {
        this.selectCheckedAll = false
      }
    },
    handleInput(keyword) {
      if (!keyword) {
        this.showselectedList = false
        return
      }
      const keywordList = [...this.searchTree({ menuName: '', childrenMenu: this.permissionTree }, keyword)]
      const keywordListTemp = []
      keywordList.forEach(item => {
        const namePathList = []
        const idPathList = []
        item && item.forEach(tItem => {
          namePathList.push(tItem.menuName)
          idPathList.push(tItem.menuId)
        })
        keywordListTemp.push({
          namePath: namePathList.join(' / '),
          idPath: idPathList
        })
      })
      this.selectedList = keywordListTemp
      this.showselectedList = true
    }

问题优化1:

  • checkStrictly: false的时候,可以父类联动子类选中,但是绑定的值不是全部选中的值
  • 需要使用 this.$refs.cascader.getCheckedNodes(false) 才能获取到所有的对应的值,才能实现全选的数量一致

问题优化2: checkStrictly: false的时候,后端需要获取半选的菜单id

    // 定义一个函数,用于遍历树状结构数据,获取父类的id
    findParents(treeData, childId, parents = []) {
      for (let i = 0; i < treeData.length; i++) {
        const node = treeData[i]
        if (node.menuId === childId) {
          // 找到了目标子节点,返回其所有父节点id
          return [...parents, node.menuId]
        } else if (node.childrenMenu && node.childrenMenu.length > 0) {
          // 递归遍历子节点的所有子节点
          const result = this.findParents(node.childrenMenu, childId, [...parents, node.menuId])
          if (result) {
            // 找到了目标子节点,返回其所有父节点id
            return result
          }
        }
      }
      // 没有找到目标子节点
      return null
    },

定义方法,根据当前全选的数组进行获取其父类的id,然后去重

      let menuList = this.$refs.cascader.getCheckedNodes(false)
      menuList = menuList.map(i => i.value)
      // 半选的情况下,接口也需要传父类的id
      const parentList = []
      menuList.forEach(item => {
        parentList.push(...this.findParents(this.permissionTree, item))
      })
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值