[mind-elixir]Mind-Elixir 的交互增强:单击、双击与鼠标 Hover 功能实现

[mind-elixir]Mind-Elixir 的交互增强:单击、双击与鼠标 Hover 功能实现

功能简述

  1. 通过防抖,实现单击双击区分
  2. 通过mousemove事件,实现hover效果

实现思路

(一)单击与双击事件
  1. 功能描述

    • 单击节点时,可以触发单击事件,用于执行一些简单操作,如显示节点详情、切换样式等。
    • 双击节点时,可以触发双击事件,用于执行更复杂的操作,如编辑节点内容、展开/折叠子节点等。
    • 通过防抖处理,能够准确区分单击和双击事件,避免误判。
  2. 实现思路

    • 使用 clickTimerclickCount 来记录点击事件的时间和次数。
    • 当节点被选中时,通过 handleNodeSelect 方法判断是单击还是双击。
    • 如果是同一个节点在短时间内多次点击,则视为双击;否则视为单击。
  3. 代码实现

    javascript 复制代码
    handleNodeSelect(nodeData) {
      // 如果是同一个节点
      if (this.lastClickedNode && this.lastClickedNode.id === nodeData.id) {
        this.clickCount++
      } else {
        // 不同节点,重置计数
        this.clickCount = 1
        this.lastClickedNode = nodeData
      }
    
      // 清除之前的定时器
      if (this.clickTimer) {
        clearTimeout(this.clickTimer)
      }
    
      // 设置新的定时器
      this.clickTimer = setTimeout(() => {
        if (this.clickCount === 1) {
          // 单击
          console.log('触发点击', nodeData)
        } else if (this.clickCount >= 2) {
          // 双击(或多击,都当作双击处理)
          console.log('触发双击', nodeData)
        }
        // 重置计数
        this.clickCount = 0
        this.lastClickedNode = null
      }, 200) // 200ms内的多次点击判断为双击
    }
(二)鼠标 Hover 事件
  1. 功能描述

    • 当鼠标悬停在某个节点上时,可以获取该节点的 ID,用于高亮显示、提示信息等操作。
    • 通过监听 mousemove 事件,实时获取鼠标位置和对应的节点信息。
  2. 实现思路

    • handleMouseMove 方法中,通过事件目标(e.target)获取节点的 ID。
    • 判断当前鼠标所在位置是否包含特定的节点元素(如 me-tpc),从而确定是否触发 Hover 事件。
  3. 代码实现

    javascript 复制代码
    handleMouseMove(e) {
      const hasMeTpc = e?.target?.querySelector('me-tpc') !== null
      if (!hasMeTpc) {
        if (e.target) {
          const nodeId = e.target.getAttribute('data-nodeid')
          console.log('鼠标所在节点的id:', nodeId)
        }
      }
    }

代码

html 复制代码
<template>
  <div class="box">
    <div id="map" @mousemove="handleMouseMove"></div>
    <div style="margin-top: 20px">
      <button @click="test1">测试1</button>
    </div>
  </div>
</template>

<script>
import MindElixir from 'mind-elixir'
import example from 'mind-elixir/example'

const mock = {
  id: 'root',
  topic: '中心主题',
  children: [
    {
      id: 'child1',
      topic: '子主题1',
      children: []
    },
    {
      id: 'child2',
      topic: '子主题2',
      children: []
    }
  ]
}

export default {
  name: 'MindElixir',
  data() {
    return {
      ME: null,
      // 单击双击防抖处理
      clickTimer: null,
      clickCount: 0,
      lastClickedNode: null
    }
  },
  mounted() {
    const generateMainBranch = ({ pT, pL, pW, pH, cT, cL, cW, cH, direction }) => {
      console.log('111', pT, pL, pW, pH)
      console.log('222', cT, cL, cW, cH)
      console.log('direction', direction)
      const x1 = pW
      const y1 = pT + pH / 2
      const c1 = pW + (cL - pW) / 2
      const c2 = cT + cH / 2
      return `M ${x1} ${y1} H ${c1} V ${c2} H ${cL}`
    }
    console.log('example', example)
    const theme = MindElixir.THEME
    theme.cssVar['--root-bgcolor'] = '#2499f2'
    theme.cssVar['--root-radius'] = '5px'
    theme.cssVar['--main-radius'] = '5px'
    theme.palette = ['#27f25a']
    this.ME = new MindElixir({
      el: '#map',
      locale: 'zh_CN',
      draggable: true, // 启用节点拖拽
      editable: true, // 启用编辑功能
      contextMenu: true, // 启用右键菜单
      toolBar: true, // 启用工具栏
      nodeMenu: true, // 启用节点菜单
      keypress: true, // 启用快捷键
      // before: {},
      generateMainBranch
    })
    this.ME.bus.addListener('operation', operation => {
      console.log('operation', operation)
    })
    this.ME.init({
      nodeData: mock,
      theme
    })

    // 监听节点选择事件(需要防抖处理单击/双击)
    this.ME.bus.addListener('selectNode', this.handleNodeSelect)
  },
  methods: {
    test1() {
      const mock2 = {
        id: 'root',
        topic: '中心主题222',
        style: {
          color: 'yellow'
        },
        children: [
          {
            id: 'child3',
            topic: '子主题3',
            children: []
          },
          {
            id: 'child4',
            topic: '子主题4',
            children: []
          }
        ]
      }
      this.ME.refresh({
        nodeData: mock2
      })
    },

    // 单击双击事件
    handleNodeSelect(nodeData) {
      // 如果是同一个节点
      if (this.lastClickedNode && this.lastClickedNode.id === nodeData.id) {
        this.clickCount++
      } else {
        // 不同节点,重置计数
        this.clickCount = 1
        this.lastClickedNode = nodeData
      }

      // 清除之前的定时器
      if (this.clickTimer) {
        clearTimeout(this.clickTimer)
      }

      // 设置新的定时器
      this.clickTimer = setTimeout(() => {
        if (this.clickCount === 1) {
          // 单击
          console.log('触发点击', nodeData)
        } else if (this.clickCount >= 2) {
          // 双击(或多击,都当作双击处理)
          console.log('触发双击', nodeData)
        }
        // 重置计数
        this.clickCount = 0
        this.lastClickedNode = null
      }, 200) // 200ms内的多次点击判断为双击
    },

    // 鼠标移动事件
    handleMouseMove(e) {
      const hasMeTpc = e?.target?.querySelector('me-tpc') !== null
      if (!hasMeTpc) {
        if (e.target) {
          const nodeId = e.target.getAttribute('data-nodeid')
          console.log('鼠标所在节点的id:', nodeId)
        }
      }
    }
  }
}
</script>

<style lang="less" scoped>
.box {
  text-align: center;
}
#map {
  width: 100%;
  height: 800px;
  overflow: auto;
}
</style>
相关推荐
程序员码歌25 分钟前
短思考第261天,浪费时间的十个低效行为,看看你中了几个?
前端·ai编程
Swift社区1 小时前
React Navigation 生命周期完整心智模型
前端·react.js·前端框架
若梦plus1 小时前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花2 小时前
Python环境安装
前端
Light602 小时前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy2 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴2 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里2 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路2 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端
多看书少吃饭2 小时前
从Vue到Nuxt.js
前端·javascript·vue.js