vue2脑图插件MindElixir

mind-elixir官方地址

官方地址
修改的点:
1、该插件默认是右键拖动画布,改为左键右键都可以拖动
2、默认画布内容是有点居右的,现在改为居中

1、新建MindMap.vue

<template>
  <div ref="mindContainer" class="mind-container"></div>
</template>

<script>
import MindElixir from "mind-elixir/dist/MindElixir.js";
import "mind-elixir/dist/MindElixir.css";

export default {
  name: "MindMap",
  props: {
    // 思维导图数据,从父组件传入
    mindData: {
      type: Object,
      required: true,
    },
    // 思维导图配置项
    options: {
      type: Object,
      default: () => ({
        direction: MindElixir.RIGHT,
        draggable: true,
        toolBar: true,
        editable: true,
        keypress: true,
        locale: "zh_CN",
      }),
    },
  },
  data() {
    return {
      mind: null,
    };
  },
  mounted() {
    this.initMind();
  },
  watch: {
    // 监听数据变化,更新思维导图
    mindData: {
      deep: true,
      handler(newData) {
        if (this.mind) {
          // 销毁现有实例
          this.mind.destroy();
          // 重新初始化
          this.initMind();
        }
      },
    },
    // 监听配置项变化
    options: {
      deep: true,
      handler() {
        if (this.mind) {
          this.mind.destroy();
          this.initMind();
        }
      },
    },
  },
  beforeDestroy() {
    if (this.mind) {
      this.mind.destroy();
    }

    // 移除DOM事件监听器
    if (this.domClickHandler && this.$refs.mindContainer) {
      this.$refs.mindContainer.removeEventListener("click", this.domClickHandler);
      console.log("已移除DOM事件监听器");
    }
  },
  methods: {
    // 初始化思维导图
    initMind() {
      // 初始化 MindElixir
      const mind = new MindElixir({
        el: this.$refs.mindContainer,
        ...this.options,
      });

      // 使用父组件传入的数据初始化
      mind.init(this.mindData);

      this.mind = mind;
      this.$nextTick(() => {
        this.safeCenter();
      }, 300);
      this.setAddListener();
      this.enableLeftDrag();
    },
    // 强制居中函数
    safeCenter() {
      const container = this.$refs.mindContainer;
      const canvas = container.querySelector(".map-canvas");
      if (!canvas) return;

      // 计算容器和脑图宽高
      const rect = container.getBoundingClientRect();
      const mindRect = canvas.getBoundingClientRect();

      // 把根节点移到容器中心
      const offsetX = (rect.width - mindRect.width) / 2;
      const offsetY = (rect.height - mindRect.height) / 2;

      canvas.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
    },
    setAddListener() {
      this.mind.bus.addListener("operation", (operation) => {
        console.log(operation);
      });
      this.mind.bus.addListener("selectNodes", (node) => {
        this.$emit("select-node", node);
      });
      this.mind.bus.addListener("expandNode", (node) => {
        console.log("expandNode: ", node);
      });
    },
    // 对外暴露获取当前数据的方法
    getData() {
      if (this.mind) {
        return this.mind.getData();
      }
      return null;
    },
    enableLeftDrag() {
      const container = this.$refs.mindContainer.querySelector(".map-canvas");
      let isDragging = false;
      let lastX = 0,
        lastY = 0;
      let transformX = 0,
        transformY = 0;

      const getTransform = () => {
        const transform = container.style.transform || "translate(0px, 0px)";
        const match = transform.match(/translate\(([-\d.]+)px,\s*([-\d.]+)px\)/);
        if (match) {
          transformX = parseFloat(match[1]);
          transformY = parseFloat(match[2]);
        } else {
          transformX = 0;
          transformY = 0;
        }
      };
      container.addEventListener("mousedown", (e) => {
        if (e.button === 0 && !e.target.closest(".node")) {
          isDragging = true;
          lastX = e.clientX;
          lastY = e.clientY;
          getTransform();
          e.preventDefault();
        }
      });

      window.addEventListener("mousemove", (e) => {
        if (!isDragging) return;
        const dx = e.clientX - lastX;
        const dy = e.clientY - lastY;
        container.style.transform = `translate(${transformX + dx}px, ${transformY + dy}px)`;
      });

      window.addEventListener("mouseup", () => {
        isDragging = false;
      });
    },
  },
};
</script>

<style scoped>
.mind-container {
  width: 100%;
  height: 600px;
  border: 1px solid #ccc;
}
</style>

2、在页面index.vue里面使用

<template>
  <div class="mind-map-container">
    <div class="mind-container wbgc-card">
      <MindMap ref="mindMap" :mind-data="mindData" :options="mindOptions" @select-node="handleSelectNode" />
    </div>
  </div>
</template>

<script>
import MindMap from "./components/MindMap.vue";
import MindElixir from "mind-elixir/dist/MindElixir.js";
import "mind-elixir/dist/MindElixir.css";

export default {
  name: "CaseMindEdit",
  inject: ["closeTab"],
  components: {
    MindMap,
  },
  data() {
    return {
      // 思维导图数据,将传递给子组件
      mindData: {},
      // 思维导图配置项
      mindOptions: {
        direction: MindElixir.RIGHT,
        draggable: true,
        toolBar: true,
        editable: true,
        locale: "zh_CN",
      },
    };
  },
  mounted() {
    // 初始化思维导图数据
    this.initMindData();
  },
  methods: {
    // 初始化思维导图数据
    initMindData() {
      // 创建初始数据结构
      const data = MindElixir.new("自定义右键菜单示例");
      data.nodeData = {
        id: "root",
        topic: "root:",
        children: [
          {
            id: "1",
            topic: "1",
            children: [
              {
                id: "1-1",
                topic: "1-1",
                children: [
                  { id: "1-1-1", topic: "1-1-1:", children: [{ id: "1-1-1-1", topic: "New Node" }] },
                  {
                    id: "1-1-2",
                    topic: "1-1-2:",
                    children: [
                      { id: "1-1-1-1", topic: "New Node" },
                      { id: "1-1-1-2", topic: "New Node" },
                    ],
                  },
                  {
                    id: "1-1-3",
                    topic: "1-1-3:",
                    children: [
                      { id: "1-1-1-1", topic: "New Node" },
                      { id: "1-1-1-2", topic: "New Node" },
                      { id: "1-1-1-3", topic: "New Node" },
                    ],
                  },
                  {
                    id: "1-1-4",
                    topic: "1-1-4:",
                    children: [
                      { id: "1-1-1-1", topic: "New Node" },
                      { id: "1-1-1-2", topic: "New Node" },
                      { id: "1-1-1-3", topic: "New Node" },
                      { id: "1-1-1-4", topic: "New Node" },
                    ],
                  },
                ],
              },
            ],
          },
        ],
      };

      this.mindData = data;
    },

    // 处理思维导图数据变化事件
    handleChangeData(data) {
      console.log("思维导图数据变化:", data);
      // 这里可以处理数据变化后的逻辑
    },
  },
};
</script>

<style scoped lang="less">
.mind-map-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 0 12px 12px;
  .row-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 24px;
    margin-bottom: 12px;
    .header-left {
      color: #6281a3;
      font-size: 16px;
      padding-left: 13px;
      line-height: 36px;
      position: relative;
      display: flex;
      &::before {
        content: "";
        position: absolute;
        width: 5px;
        height: 14px;
        left: 0;
        top: 11px;
        background-color: #87ce40;
      }
    }
    .wpg-btn {
      margin-left: 10px;
    }
  }
  .mind-container {
    flex: 1;
    height: 100%;
  }
}
</style>

效果

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容