首页 前端知识 el-tree-v2虚拟滚动树,实现代码勾选、动态禁用勾选、检索、节点文字label宽度超出滚动等功能

el-tree-v2虚拟滚动树,实现代码勾选、动态禁用勾选、检索、节点文字label宽度超出滚动等功能

2024-06-26 23:06:50 前端知识 前端哥 740 844 我要收藏

前言

某个需求要展示大量树节点,原本使用普通el-tree,默认不要展开太多层次(注意树节点默认全部展开页面渲染很卡),勉强能应付,但是检索功能会展开所有节点,还是很卡顿,只能硬着头皮改版,就想到了用element-plus的虚拟滚动树。
查了网上没有多少el-tree-v2的使用文章,下面是自己的踩坑过程,给有需要的人提供些帮助

关键代码

基本代码

需要注意v2不使用node-key=“id”,使用value:“id”

<template>
	<!-- 计算最长文字宽度,显示横向滚动条用到 -->
     <span style="visibility: hidden; position: fixed; z-index: -1" ref="maxlengthLabelRef">{{ state.maxlengthLabel }}</span>
     <el-input class="mb10 ipt" v-model="filterText" clearable @input="onQueryChanged" placeholder="输入名称" />
     <el-tree-v2
       class="point-tree"
       v-loading="state.treeLoading"
       ref="treeRef"
       :data="state.treeData"
       @check-change="handleCheckChange"
       :filter-method="filterNode"
       :props="defaultProps"
       :height="treeHeight"
       show-checkbox
     >
     </el-tree-v2>
</template>
<script setup lang="ts">
interface Tree {
  id: string;
  label: string;
  leaf: boolean;
  disabled: boolean;
  children: Tree[];
}
//重点,value对应id
const defaultProps = {
  value: "id",
  label: "label",
  children: "children",
  disabled: "disabled",
};
const state = reactive({
  treeLoading: false,
  treeData: [] as Tree[], 
  maxlengthLabel: "", //最长label
  maxlengthLabelWidth: "",
});
const treeRef = ref();
//前端检索功能
const filterText = ref("");
const filterNode = (value: string, data: Tree) => {
  if (!value) return true;
  return data.label.includes(value);
};
const onQueryChanged = (query: string) => {
  treeRef.value!.filter(query);
};
//勾选复选框事件
const handleCheckChange = (data: Tree) => {
  //业务
  ……
};
</script>

使用代码勾选/取消复选框(回显功能)

nodeId指节点id,叶子节点和非叶子节点都可以

//勾选
treeRef.value.setChecked(nodeId, true, false);
//取消勾选
treeRef.value.setChecked(nodeId, false, false);

动态禁用/解除禁用复选框勾选(改变disabled属性)

//1、对treeData进行遍历处理,改变disabled属性状态为true/false
……递归或者遍历函数
func()
//2、重新赋值回去
treeRef.value.setData(state.treeData);

文字长度超出,显示横向滚动条

项目需求是文字过多,需要整体滚动,但是v2虚拟tree只展示视野内节点,动态生成,且节点是绝对定位absolute来实现,不能靠节点自身宽度撑开
期待效果
解决思路,有点麻烦
1、获取treeData,遍历计算哪个label文字最多(计算规则,汉字占2个字符,数字、字母、符号占1个字符),返回maxLengthLabel本身
(这一步是借助大模型写出的代码)

// 计算字符最多label,规则为汉字两个字符,其他一个字符
const findLongestLabelWithCustomLength = (nodeList: Tree[], longestLabel = "", maxLength = 0): [string, number] => {
  for (const node of nodeList) {
    const currentLabel = node.label;
    const currentLength = calculateLabelLength(currentLabel);
    if (currentLength > maxLength) {
      maxLength = currentLength;
      longestLabel = currentLabel;
    }
    if (node.children && node.children.length > 0) {
      const [childLongestLabel, childMaxLength] = findLongestLabelWithCustomLength(node.children, longestLabel, maxLength);
      if (childMaxLength > maxLength) {
        maxLength = childMaxLength;
        longestLabel = childLongestLabel;
      }
    }
  }

  return [longestLabel, maxLength];
};
const calculateLabelLength = (label: string) => {
  let length = 0;
  for (const char of label) {
    // 判断字符是否为汉字
    if (isChinese(char)) {
      length += 2;
    } else {
      length += 1;
    }
  }
  return length;
};
const isChinese = (char: string) => {
  // 判断字符是否属于Unicode中的汉字范围
  const code = char.charCodeAt(0);
  return (code >= 0x4e00 && code <= 0x9fff) || (code >= 0x3400 && code <= 0x4dbf);
};

2、在页面放一个隐藏的span标签,把maxLengthLabel的文本放进去,获取span标签宽度,这样做主要是考虑字体大小、字体因素影响。

<template>
	<!-- 计算最长文字宽度,显示横向滚动条用到 -->
     <span style="visibility: hidden; position: fixed; z-index: -1" ref="maxlengthLabelRef">{{ state.maxlengthLabel }}</span>
</template>

3、拿span宽度spanWidth赋值给tree,过程如下

const maxlengthLabelRef = ref();
const getTreeData = () => {
  const params = {
  };
  state.treeLoading = true;
  getTree(params).then((res: any) => {
    state.treeLoading = false;
    resHandler(res, () => {
      state.treeData = res.data || [];
      if (res.data.length) {
        // 调用第一步的函数
        const maxLabelLength = findLongestLabelWithCustomLength(res.data);
        state.maxlengthLabel = maxLabelLength[0];
        nextTick(() => {
        //这里+150,是各层级前边的缩进,因为这个项目的tree层级不确定,我就懒省事多写了点,固定的
          state.maxlengthLabelWidth = parseInt(getComputedStyle(maxlengthLabelRef.value, null).width) + 150 + "px";
        });
      }
    });
  });
};

4、给tree绑定宽度样式

<style lang="scss" scoped>
:deep() {
  //   设置el-tree宽度,产生水平滚动
  .el-vl__wrapper {
    width: v-bind("state.maxlengthLabelWidth");
    position: static;
  }
  //给虚拟滚动条重新定位,否则水平滚动滚动条会跟着滚走
  .el-virtual-scrollbar {
    position: fixed !important;
    top: 317px !important;//根据页面来
    left: 416px !important;//根据页面来
    right: unset !important;
    bottom: unset !important;
  }
}
</style>

需要注意,以上显示水平滚动条有两个不足:
1、折叠时候,滚动条还会存在
2、树层级不定时候,宽度不够精准

有更好的办法,欢迎评论反馈

转载请注明出处或者链接地址:https://www.qianduange.cn//article/13616.html
标签
评论
发布的文章

JSON、Ajax

2024-07-27 22:07:31

JsonNode、ObjectNode和ArrayNode

2024-07-27 22:07:30

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!