el-trre 支持双击事件-dblclick

1,140 阅读1分钟

需求

项目使用element-plus的<el-trre/>,要求点击正常折叠展开,双击时执行其他逻辑。本以为在slot元素上加个@dblclick就好了,结果并不顺利。网上查了很多最后归纳实现了一个相对事件靠谱的方案。

实现

思路,利用监听用户click行为,分析是不是做的双击动作。
利用点击计数,使用防抖(debounce)控制行为流向。200毫秒内的多次点击视为双击动作(可以根据体验要求调节时间间隔)。

<template>
    <el-tree
    ref="_tree"
    :default-expanded-keys="data.openKeys"
    :props="data.tableTrreConfig"
    :data="data.tableTrre"
    node-key="id"
    :expand-on-click-node="false"
    @node-click="trreNodeClick"
    >
        <template #default="{ node }">
          <span class="custom-tree-node">
            <span>{{ node.label }}</span>
          </span>
        </template>
    </el-tree>
</template>

<script setup>
    import { watch, reactive, ref } from "vue";

    const _tree = ref("");
    const data = reactive({
      tableTrre: [],
      tableTrreConfig: {
        children: "children",
        label: "title",
      },
      openKeys: [],
    });
    
    let treeClickCount = 0;
    async function trreNodeClick(d1, d2) {
      treeClickCount++;
      trreNodeClickListener(d1, d2);
    }
    
    function debounce(fn, awaitTime, ...args) {
      let lock = null;
      return function (...event) {
        if (lock) clearTimeout(lock);
        lock = setTimeout(() => {
          fn.apply(this, [...event, ...args]);
          lock = null;
        }, awaitTime);
      };
    }

    var trreNodeClickListener = debounce((...ages) => {
      const [d1, d2] = ages;
      if (treeClickCount > 1) {
        dblclickTrre(...ages);
      } else {
        clickTrre(...ages);
      }
      treeClickCount = 0;
    }, 200);

    function clickTrre(d1, d2) {
      const id = d1.id;
      // 用来支持正常的折叠和展开
      const nodesMap = _tree.value.store.nodesMap;
      nodesMap[id].expanded = !nodesMap[id].expanded;
    }
    
    function dblclickTrre(d1, d2){
        // 双击监听
    }
<script>

<style>
// 优化双击的体验(不选择文字)
.custom-tree-node {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
</style>