使用jsMind实现可拖拽思维导图

1.安装依赖:

npm install vue-jsmind

2.在main.js中引入:

import jm from 'vue-jsmind'
Vue.use(jm)
if (window.jsMind) {
  Vue.prototype.jsMind = window.jsMind
}

3.拖拽完成时间需要引入文件jsmindDrag.js,下载地址:

https://download.csdn.net/download/qq_40364610/85218557

4.数据格式:

{
    "data": [
        {
            "children": [
                {
                    "children": [
                        {
                            "id": "8",
                            "topic": "专家信息"
                        }
                    ],
                    "id": "3",
                    "topic": "教师信息"
                },
                {
                    "children": [],
                    "id": "4",
                    "topic": "人才称号"
                },
                {
                    "children": [
                        {
                            "id": "9",
                            "topic": "教学团队"
                        }
                    ],
                    "id": "5",
                    "topic": "创新团队"
                }
            ],
            "id": "1",
            "topic": "师资队伍"
        },
        {
            "children": [
                {
                    "children": [],
                    "id": "6",
                    "topic": "国家级科研教学平台"
                },
                {
                    "children": [],
                    "id": "7",
                    "topic": "学科平台"
                }
            ],
            "id": "2",
            "topic": "支撑平台"
        }
    ]
}

5.完整代码:

<template>
  <div class="app-container">
    <div class="header">
      <div style="float: right;margin: 10px 20px 0px 0px;display:inline-block;">
        <el-button type="primary" class="noimpor-btn" @click="addNode"><i class="el-icon-plus"></i> 添加节点</el-button>
        <el-button type="primary" class="noimpor-btn" @click="editNode"><i class="el-icon-edit"></i> 编辑节点</el-button>
        <el-button type="primary" class="noimpor-btn" @click="onRemoveNode"><i class="el-icon-minus"></i> 删除节点
        </el-button>
        <el-divider direction="vertical"></el-divider>
        <!--        <el-button type="primary" class="common-btn" @click='saveMind'><i class="el-icon-s-claim"></i> 保存</el-button>-->
        <el-button type="primary" class="danger-btn" @click='deleteMind' :disabled="formData.id === ''?true:false"><i
          class="el-icon-delete"></i> 删除
        </el-button>
      </div>
    </div>
    <js-mind :values="mind" :options="options" ref="jsMind" :height="mindHeight"></js-mind>
    <el-dialog title="编辑节点" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
      <el-form ref="nodeForm" :model="nodeOption" :rules="rules" label-width="80px">
        <el-form-item label="目录名称" prop="targetName">
          <el-input v-model="nodeOption.targetName" style="width: 60%"></el-input>
        </el-form-item>
        <el-form-item label="目录顺序" prop="order">
          <el-input style="width: 200px" type="number" v-model="nodeOption.order"></el-input>
        </el-form-item>
        <el-form-item label="表关联" prop="connect" style="text-align: left">
          <el-select
            clearable
            v-model="nodeOption.connect"
            :disabled="tableDisabled"
            filterable
            remote
            reserve-keyword
            :popper-append-to-body="true"
            :remote-method="remoteMethod"
            :default-first-option="true"
            placeholder="请选择"
            v-el-select-loadmore="loadMore">
            <el-option
              v-for="item in tableOptions"
              :key="item.tableId"
              :label="item.tableDesc"
              :value="item.tableId">
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
          <el-button type="primary" class="common-btn" @click="sureEditNode('nodeForm')">确 定</el-button>
        </span>
    </el-dialog>
  </div>
</template>

<script>
  import '@/utils/directive'
  import {treeIndex, addIndex, tableList, deleteIndex, queryIndex, updateIndex,moveIndex} from "@/api/config/targetConfig"
  require("./component/jsmindDrag")
  export default {
    name: 'targetConfig',
    inject: ['reload'],
    data() {
      return {
        currentSpaceId:"",
        tableDisabled: false,
        tablePage: 0,
        tableOptions: [],
        optionTotal: 0,
        dialogVisible: false,
        nodeOption: {
          order: '',
          connect: '',
          targetName: ""
        },
        defaultTableList: [],
        rules: {
          targetName: [
            {required: true, message: '请输入目录名称', trigger: 'blur'},
          ],
          order: [
            {required: true, message: '顺序不能为空', trigger: 'blur'},
          ],
        },
        theme_value: '',
        mindHeight: 'calc(100vh - 127px)',
        themOptions: ['primary', 'warning', 'danger', 'success', 'info', 'greensea', 'nephrite', 'belizehole', 'wisteria', 'asphalt', 'orange', 'pumpkin', 'pomegranate', 'clouds', 'asbestos'],
        mind: {
          meta: {
            name: 'jsMind remote',
            author: 'hizzgdev@163.com',
            version: '0.2'
          },
          format: 'node_tree',
          data: {
            id: "0",
            topic: "根目录",
            children: []
          }
        },
        options: {
          container: 'jsmind_container', // [必选] 容器的ID
          shortcut: { //禁用快捷键
            enable: false
          },
          editable: false, // [可选] 是否启用编辑
          theme: 'info' // [可选] 主题
        },
        formData: {
          id: '',
          mindCode: '',
          mindName: '',
          mindType: '',
          mindData: '',
          mindOptions: ''
        },
        mindOptions: {
          theme: ''
        },
        treeData: [],
        defaultProps: {
          children: 'children',
          label: 'name'
        },
        color: 'rgba(255, 69, 0, 0.68)',
        predefineColors: [
          '#ff4500',
          '#ff8c00',
          '#ffd700',
          '#90ee90',
          '#00ced1',
          '#1e90ff',
          '#c71585',
          'rgba(255, 69, 0, 0.68)',
          'rgb(255, 120, 0)',
          'hsv(51, 100, 98)',
          'hsva(120, 40, 94, 0.5)',
          'hsl(181, 100%, 37%)',
          'hsla(209, 100%, 56%, 0.73)',
          '#c7158577'
        ]
      }
    },
    computed: {
      spaceId() {
        return this.$store.state.user.spaceId
      }
    },
    watch:{
      spaceId(newVal){
        this.reload()
      }
    },
    mounted() {
      this.currentSpaceId = this.$store.state.user.spaceId? this.$store.state.user.spaceId:localStorage.getItem("spaceId")
      this.jm = this.$refs.jsMind.jm
      this.jm.enable_edit()
      this.jm.enable_event_handle('dblclick')
      this.getMind()
      let that = this
      Object.defineProperties(jsMind.dragObj, { //拖拽完成事件
        target_direct: {
          configurable: true,
          set: function (newValue) {
            let target_direct = newValue;
            that.moveHandle(target_direct)
          }
        },
      });
      Object.defineProperties(jsMind.dragObj, { //点击事件
        edit_value: {
          configurable: true,
          set: function (newValue) {
            // let edit_value = newValue;
            that.$nextTick(()=>{
              that.dblclickEditHandle(newValue)
            })
          }
        }
      })
    },
    methods: {
      dblclickEditHandle(newValue) {
        let param = {
          indexId: newValue.id,
          indexName: newValue.topic,
          sortIndex: ""
        };
        // console.log(param,"途经此处")
        updateIndex(param).then(res => {
          this.getMind()
        })
      },
      loadMore() {
        if (this.tableOptions.length < this.optionTotal) {
          this.tablePage++
          this.getTableConnect()
        }
      },
      remoteMethod(query) {
        this.tablePage = 0
        this.nodeOption.tableDesc = query.trimStart()
        this.tableOptions = []
        this.getTableConnect()
      },
      getTableConnect() {
        let param = {
          page: this.tablePage,
          size: 10,
          tableDesc: this.nodeOption.tableDesc,
          spaceId: this.currentSpaceId,
        }
        let selectedId = this.get_selected_nodeid()
        const nodeObj = this.jm.get_node(selectedId)
        if (nodeObj.children != null && nodeObj.children.length > 0) {
          param = { ...param, sourceType: '20' }
        }
        tableList(param).then(res => {
          this.optionTotal = res.totalElements
          if (this.tablePage === 0 && !this.nodeOption.tableDesc) {
            this.tableOptions = [ ...this.defaultTableList ]
          }
          let newContent = res.content.filter(item => { return item.tableId != this.nodeOption.connect })
          if (this.nodeOption.tableDesc) {
            if (this.tablePage === 0) {
              this.tableOptions = []
            }
            newContent = res.content
          }
          // const newContent = res.content.filter(item => { return item.tableId != this.nodeOption.connect })
          this.tableOptions = [ ...this.tableOptions, ...newContent ]
        })
      },
      async getMind(mindCode) {
        let param = {
          spaceId:  this.currentSpaceId
        }
        treeIndex(param).then(res => {
          this.mind.data = res
          // if (this.formData.mindOptions&&this.formData.mindOptions !== '') {
          //   this.theme_value = JSON.parse(this.formData.mindOptions).theme
          //   this.set_theme()
          // }
          this.jm.show(this.mind)
        }).catch(err => {
        })
      },
      moveHandle(target_direct) {
        // console.log("移动名称:" + jsMind.dragObj.src_node.topic, "id为" + jsMind.dragObj.src_node.id);
        // console.log("父级名称:" + jsMind.dragObj.target_node.topic, "id为" + jsMind.dragObj.target_node.id);
        // console.log("移动方向:" + target_direct);
        let param= {
          indexId:jsMind.dragObj.src_node.id,//移动的资源目录id
          superId:jsMind.dragObj.target_node.id,//移动后的父资源目录id
        }
        moveIndex(param).then(res=>{})
      },
      // 新增节点
      addNode() {
        let selectedNode = this.jm.get_selected_node() // as parent of new node
        if (!selectedNode) {
          this.$message({
            type: 'warning',
            message: '请先选择一个节点!'
          })
          return
        }
        let nodeid = this.jsMind.util.uuid.newid()
        let topic = '新增节点'
        this.jm.add_node(selectedNode, nodeid, topic)
        let params = {
          indexName: topic,//指标名称
          levelNum: "",//层级
          superId: selectedNode.id,//指标id
          spaceId:  this.currentSpaceId
        };
        addIndex(params).then(res => {
          this.getMind()
        })
      },
      // 重置
      resetForm() {
        this.nodeOption = {
          targetName: '',
          order: null,
          connect: null
        }
        setTimeout(() => {
          if (this.$refs.nodeForm) {
            this.$refs.nodeForm.clearValidate()
          }
        }, 300)
        this.tablePage = 0
      },
      // 编辑节点
      editNode() {
        let selectedId = this.get_selected_nodeid()
        if (!selectedId) {
          this.$message({
            type: 'warning',
            message: '请先选择一个节点!'
          })
          return
        }
        this.resetForm()
        let nodeObj = this.jm.get_node(selectedId)
        queryIndex({indexId: nodeObj.id}).then(res => {
          this.nodeOption = {
            targetName: res.indexName,
            order: res.sortIndex,
            connect: res.tableId,
            tableDesc: ''
          }
          this.dialogVisible = true
          if (res.tableId) {
            this.defaultTableList = [{ tableId: res.tableId, tableDesc: res.tableDesc }]
            this.tableOptions = [{ tableId: res.tableId, tableDesc: res.tableDesc }]
          } else {
            this.defaultTableList = []
            this.tableOptions = []
          }
          this.getTableConnect()
          /*if (nodeObj.children.length > 0) {
            this.tableDisabled = true
          } else {
            this.tableDisabled = false
          }*/
        })
      },
      sureEditNode(formName) {
        let selectedId = this.get_selected_nodeid()
        this.$refs[formName].validate((valid) => {
          if (valid) {
            let param = {
              indexId: selectedId,
              tableId: this.nodeOption.connect,
              indexName: this.nodeOption.targetName,
              sortIndex: this.nodeOption.order
            }
            updateIndex(param).then(res => {
              this.dialogVisible = false
              this.getMind()
              this.jm.update_node(selectedId, this.nodeOption.content)
              this.jm.set_node_font_style(selectedId, this.nodeOption.fontSize, this.nodeOption.fontWeight, this.nodeOption.fontStyle)
              this.jm.set_node_color(selectedId, this.nodeOption.bgColor, this.nodeOption.fontColor)
              this.nodeOption = {
                content: '',
                bgColor: '',
                fontColor: '',
                fontSize: '',
                fontWeight: '',
                fontStyle: ''
              }
              this.$refs.nodeForm.resetFields()
            })
          }
        })
      },
      // 删除节点
      onRemoveNode() {
        let selectedId = this.get_selected_nodeid()
        if (!selectedId) {
          this.$message({
            type: 'warning',
            message: '请先选择一个节点!'
          })
          return
        }
        // let selectedNode = this.jm.get_selected_node()
        this.$confirm('确定删除此指标吗?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
            this.jm.remove_node(selectedId)
            let param = {
              indexId: selectedId
            }
            deleteIndex(param).then(res => {
              this.getMind()
              this.$message({
                type: "success",
                message: "已删除"
              })
            })
          }).catch(err => {})
      },
      // 选择主题颜色
      set_theme() {
        this.jm.set_theme(this.theme_value)
      },
      // 获取选中标签的 ID
      get_selected_nodeid() {
        let selectedNode = this.jm.get_selected_node()
        if (selectedNode) {
          return selectedNode.id
        } else {
          return null
        }
      },
      saveMind() {
        return;
        if (this.formData.mindCode === '') {
          this.$message({type: 'warning', message: '导图编码不能为空!'})
          return
        }
        if (this.formData.mindName === '') {
          this.$message({type: 'warning', message: '导图名称不能为空!'})
          return
        }
        this.mindOptions.theme = this.theme_value
        this.formData.mindOptions = JSON.stringify(this.mindOptions)
        this.formData.mindData = JSON.stringify(this.jm.get_data())
        let url = process.env.VUE_APP_BASE_CRUD_PATH + `/api/jsmind/save`
        this.$axios.post(url, JSON.stringify(this.formData), {
          headers: {
            'Content-Type': 'application/json;charset=UTF-8'
          }
        }).then(res => {
          if (res.resultCode === 500) {
            this.$message({
              type: 'error',
              message: '导图编码已存在!'
            })
          }
          if (res.resultCode === 200) {
            this.$message({
              type: 'success',
              message: '保存成功!'
            })
          }
        }).catch(err => {
          console.log(err)
        })
      },
      deleteMind() {
        this.$confirm('您确定要删除该导图吗?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {}).catch(() => {})
      }
    }
  }
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
  .app-container {
    padding: 0;

    .header {
      height: 60px;
      background-color: #eee;
      border-bottom: solid 1px #aaa;
      z-index: 100;
    }
  }
</style>

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您好!要实现思维导图效果的拖拽功能,可以按照以下步骤进行操作: 1. 创建思维导图节点:首先,您需要创建思维导图的节点元素。可以使用HTML和CSS来定义节点的外观和样式。 2. 添加拖拽功能:通过JavaScript,您可以为每个节点元素添加拖拽功能。可以使用HTML5的拖放API来实现。在节点元素上添加拖动事件监听器,以便跟踪鼠标的位置变化。 3. 实现拖拽效果:在拖动事件的处理函数中,您可以更新节点元素的位置,以实现拖拽效果。通过更新节点元素的CSS属性,例如top和left,可以改变节点元素的位置。 4. 处理节点的连接关系:思维导图中的节点通常会有连接关系,您可能需要处理节点之间的连线。可以使用SVG或者Canvas来绘制连线,并通过JavaScript来处理连线的位置和样式。 5. 更新节点位置:当用户拖动节点时,您需要更新节点的位置信息。可以将节点的位置信息保存在数据结构中,例如数组或者对象中。 6. 保存和加载数据:为了能够保存和加载思维导图,您可以将节点的位置信息和其他相关数据保存在数据库或者本地存储中。当页面重新加载时,可以从存储中读取数据,并将节点重新定位到正确的位置。 通过以上步骤,您可以实现前端的思维导图效果,并使节点能够拖拽逐渐。希望对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值