element-ui Tree如何定位到一个节点,并高亮显示该节点?

发布于 2022-09-11 23:31:45 字数 601 浏览 16 评论 0

我要实现的效果是:搜索关键字,得到搜索结果
image.png

点击搜索结果,展开节点,并定位到该结果的位置(高亮显示)

目前只实现了展开节点的效果
image.png

定位到该结果的位置和高亮显示这两点无法实现

  • 定位到该结果的位置:目前只是展开了节点,并没有定位效果,如果该节点的列表很长,也只会显示上半部分的可视区域,无定位效果,但是不知道如何来写?
  • 高亮显示:我想要最终实现的是下面的图中的效果

image.png

并且当结果过长的时,能定位到该节点的位置
image.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

念﹏祤嫣 2022-09-18 23:31:45

这两天正好在写这个功能,搜集到这里来了,贴出我的代码,希望可以为遇到这个问题的朋友提供参考。
我写的比较复杂,请网友多多指教
首先我用的是一次性加载,不是懒加载。
这段代码里还有折叠其他节点的代码,可以忽略。

图片为啥插不进来。。。第一次写这个,不会搞。。

`

<div id="heheda" style="height: 700px;overflow: auto;">
                <el-tree id="heheda1"
                        v-loading="loading"
                        :data="videoData"
                        :props="props"
                        :allow-drag="allowDrag"
                        :empty-text="emptyTips"
                        draggable
                        accordion
                        :highlight-current="highLight"
                        node-key="deviceid"
                        :default-expanded-keys="expandedKeys"
                        :current-node-key="currentNode"
                        ref="videoTree"
                >
                    <span slot-scope="{node, data}">
                          <svg v-if="data.children == null && data.status == 'ON'" aria-hidden="true"
                               class="site-sidebar__menu-icon icon-svg icon-svg__menu camera_icon1">
                          </svg>
                          <svg v-if="data.children == null && data.status == 'OFF'" aria-hidden="true"
                               class="site-sidebar__menu-icon icon-svg icon-svg__menu camera_icon2">
                          </svg>
                       {{node.label}}
                     </span>
                </el-tree>
            </div>

`

videoTree这棵树是默认展开第一个节点的,
selectCamera(camera)方法是点击搜索节点结果的方法,入参是点击的节点结果对象。
下面用到的camera.deviceid就是node-key。
主要逻辑就是,当前只有这一个节点的路径是展开的,
计算出所有展开显示的节点数量nodeCount,
计算出,从根节点开始数,当前节点处于第几个nodeIndex,
已知我的树每个节点高度是26px,故树总高度为26*nodeCount px,
设置树的高度,dom1.style.height = (nodeCount * nodeHight) + "px",
这一步是关键,设置树高,外层DIV的scrollHeight才会变化,
后面代码就写的比较清楚了。
`

selectCamera(camera) {
                //在这次选中节点之前被选中的节点
                let lastNode = this.$refs.videoTree.getNode(this.$refs.videoTree.getCurrentNode())
                //这次选中的节点
                let currentNode = this.$refs.videoTree.getNode(camera.deviceid)
                //收起之前因选中而展开的节点
                if (1 != lastNode.level) {
                    let parentLevel
                    do {
                        lastNode.expanded = false
                        lastNode = lastNode.parent
                        parentLevel = lastNode.level
                    }
                    while (1 != parentLevel)
                }

                let parentLevel
                let nodeCount = 1//当前树展开节点的数量
                let nodeIndex = 1//当前选中节点在当前树的位置
                let currentNodeName = currentNode.data.name
                //计算nodeCount和nodeIndex
                do {
                    currentNode = currentNode.parent
                    parentLevel = currentNode.level
                    let childNodes = currentNode.childNodes
                    nodeCount += childNodes.length
                    for (let i = 0; i < childNodes.length; i ++) {
                        if (childNodes[i].data.name == currentNodeName) {
                            nodeIndex += (i + 1)
                        }
                    }
                    currentNodeName = currentNode.data.name
                }
                while (1 != parentLevel)

                this.expandedKeys = [camera.deviceid]
                this.visible = false//可以忽略,与题主功能无关
                //设置选中,配置highlight-current后,即可高亮
                this.$refs.videoTree.setCurrentKey(camera.deviceid)

                let dom = document.querySelector("#heheda")
                let dom1 = document.querySelector("#heheda1")
                //一个节点的高度是26px,这个值能否从对象中获取,等我把这个功能做好再考虑吧
                let nodeHight = 26
                dom1.style.height = (nodeCount * nodeHight) + "px"
                // 13是因为,div高度为700像素,nodeHight*27=702,略超过700,
                // 又因为,div高度是700像素,要使被选中的节点显示在div可视区域的中间,
                // 所以就要将27折半,后一半节点要参与滚动条的位移
                // 计算位移距离时,减350的原因也是一样,要使被选中的节点显示在div可视区域的中间,就要减去div高度的一半
                if (13 < nodeIndex) {
                    dom.scrollTo(0, (nodeIndex * nodeHight) - 350)
                } else {
                    dom.scrollTo(0, 0)
                }
            }

`

薆情海 2022-09-18 23:31:45

搜索到关键字后,设置 element-ui Tree 的 current-node-key 属性,可以设置节点选中,样式可以自己覆盖调整

this.$refs.tree.setCurrentKey(key)没有问题,
但是要正确设置属性node-key="XXX",
名称和类型都需要和要设置的 key 一样

至于滚动,需要计算选中节点到树图顶点的距离,这个需要根据展开情况计算,下面是测试代码,模拟选中然后滚动

image.png

蛮可爱 2022-09-18 23:31:45

做的项目中也遇到过类似的问题,说一下解法。
需求:在搜索框中输入搜索内容,下拉出来的搜索结果中第一个默认高亮显示,点击搜索结果中的其中一个,然后直接跳转到相应的节点位置。
思路: 1.使用el-tree 2.监听filter,当filter变化的时候,获取class为‘.el-tree-node__children’的第一个标签,然后遍历他的children,如果children中有一个元素的className中不含有is-hidden的则该标签为搜索结果的第一个选项,此时设置他的style。
3.点击某个搜索结果的时候,此时跟2一样,也是获取class为‘.el-tree-node__children’的第一个标签,但是此时遍历children的时候选择的是将所有不含有is-hidden的标签的样式恢复。接着,获取点击的元素,并使用element.scrollIntoView({block: 'end', behavior: 'smooth'})来滚动到点击的位置.
附上相关代码(省略部分的,仅供参考,不一定符合你的需求,拒绝伸手党):
`

 <el-input size="mini" class="search" placeholder="请输入节点搜索" v-model="filterText" clearable></el-input>
<el-tree
  ref="baseTree"
  ...
  :filter-node-method="filterNode"
  @node-click="handleNodeClick"
></el-tree>
watch: {
filterText(val) {
  this.isScroll = true
  this.$refs.baseTree.filter(val)
  if (val) {
    setTimeout(_ => {
      this.setSearchResultClass(val)
    },500)
  }
},

// 设置搜索结果样式
setSearchResultClass () {
  let that = this
  // 搜寻结果的第一个高亮显示
  let parent = document.querySelector('.el-tree-node__children')
  let array = parent.children
  for (let i = 0; i < array.length; i++) {
    let element = array[i]
    if (element.className.indexOf('is-hidden') === -1) {
      // debugger
      if (element.className.indexOf('s-c') === -1 && that.filterText) {
        element.className += ' s-c'
        return
      } else {
        element.className -= ' s-c'
      }
    }
  }
}

handleNodeClick(data, node) {
  let that = this
  this.clickNode = data
  that.$emit("on-node-click", data);
  // 根据主题色变换树的颜色
  that.changeTreeAboutTheme();
  // 如果存在搜索,点击节点的时候清空搜索内容且将搜索结果颜色恢复
  if (that.filterText) {
    that.filterText = ''
    that.setSearchResultClass()
  }
},

// 根据主题色变换树的颜色
changeTreeAboutTheme() {
  let that = this;
  that.$nextTick(function () {
    let array = document.querySelectorAll('.is-current');
    if (array && array.length > 0) {
      ......
          if (that.isScroll) {
            element.scrollIntoView({block: 'end', behavior: 'smooth'})
            that.isScroll = !that.isScroll
          }
        }
      }
    }
  })

`

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文