1. 前言
在现在这个信息爆炸的时代,人们需要具备更强的记忆能力来应对各种复杂信息的处理。而思维导图作为一种记忆辅助工具,一直以来都备受推崇。Vue.js作为一款流行的前端框架,是很多开发者的首选。在本文中,我们将一同探讨如何使用Vue.js和jsmind库来实现思维导图的节点拖拽和调整大小的功能。
2. jsmind介绍
jsmind是一款JavaScript编写的多功能思维导图工具库,能够轻松实现思维导图的展示和编辑。它支持多种主题颜色和节点图标,用户可以通过简单的配置来实现自定义主题。
3. 实现思维导图节点的拖拽
在jsmind中,可以通过拖拽节点来改变节点的位置。为了实现这个功能,我们需要在节点上建立一个拖拽事件监听器,并在拖拽事件中改变节点的位置。
首先,我们需要在Vue.js中引入jsmind库,并在data中定义一些参数。其中包括一个存储思维导图数据的数组`mindData`,以及nodeSize和hierarchyGap等布局参数:
import jsMind from 'jsmind'
//...
data() {
return {
mindData: [
{"id": "root", "isroot": true, "topic": "jsmind"}
],
jsMind: null,
nodeSize: { width: 150, height: 30 }, //节点大小
hierarchyGap: 20 //节点之间的距离
}
},
接下来,在mounted钩子函数中,我们可以初始化jsmind,并将其绑定到一个DOM元素上。这里我们使用`jsMind.show(options, jm)`方法将jm绑定到全局的document.body元素上:
mounted() {
this.jsMind = jsMind
var options = {
container: this.$refs.mindContainer,
theme: 'primary',
editable: true,
mode: 'full'
}
this.jsMind.show(options, this.mindData)
},
接着,在自定义组件中,我们可以为每个节点绑定一个拖拽事件监听器,代码如下:
<template>
<div class="node-wrap"
:style="{top: getNodeTop(), left: getNodeLeft()}">
<div class="node-header"
:style="{height: nodeSize.height + 'px', width: nodeSize.width + 'px'}"
@mousedown="dragStart($event)">
<div class="node-title">{{ node.topic }}</div>
<div class="node-option" v-show="isFold" @click="toggleFold">
<icon class="icon-chevron-right"></icon>
</div>
<div class="node-option" v-show="!isFold" @click="toggleFold">
<icon class="icon-chevron-down"></icon>
</div>
</div>
<div class="node-container" v-show="!isFold">
...
</div>
</div>
</template>
...
methods: {
dragStart(event) {
const nodeWrap = this.$el
event.stopPropagation()
event.preventDefault()
const mouseX = event.clientX
const mouseY = event.clientY
const left = nodeWrap.offsetLeft
const top = nodeWrap.offsetTop
document.onmousemove = function (event) {
event.stopPropagation()
event.preventDefault()
const deltaX = event.clientX - mouseX
const deltaY = event.clientY - mouseY
nodeWrap.style.left = left + deltaX + 'px'
nodeWrap.style.top = top + deltaY + 'px'
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
}
}
}
上述代码中,我们定义了dragStart事件,当节点被鼠标按下时触发。在dragStart事件中,我们获取鼠标点击时的位置、节点当前的位置,然后根据鼠标移动的距离改变节点的位置。此时,当节点被拖拽后,鼠标不会一直被拖拽的节点锁定,而是可以通过拖拽其他任意空白地方来释放。
4. 实现思维导图节点的调整大小
实现思维导图节点的调整大小,其实和实现拖拽类似。我们需要在节点右下角添加一个调整大小的边框,并在边框上添加mousedown和mousemove事件监听器,实现节点的resize功能。
下面是一个简单的实现思维导图节点resize功能的例子:
methods: {
...
resizeStart(event) {
const nodeWrap = this.$el
event.stopPropagation()
event.preventDefault()
const mouseX = event.clientX
const mouseY = event.clientY
const width = nodeWrap.offsetWidth
const height = nodeWrap.offsetHeight
document.onmousemove = function (event) {
event.stopPropagation()
event.preventDefault()
const deltaX = event.clientX - mouseX
const deltaY = event.clientY - mouseY
nodeWrap.style.width = width + deltaX + 'px'
nodeWrap.style.height = height + deltaY + 'px'
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
}
}
}
上述代码中,resizeStart事件和dragStart事件很相似,只是改变了节点的大小而不是位置。为了使节点能够被更好地调整大小,我们可以给节点右下角添加一个resize边框,并为resize边框添加mousedown事件监听器,通过mousedown事件来触发resizeStart事件。
4.1 调整大小边框的实现
为了实现节点的resize功能,我们需要为节点添加一个调整大小的边框。下面是一个简单的实现思路:
1. 为节点的最外层div元素添加一个resize-handle子元素。
2. 在resize-handle中添加一个resize-corner子元素,并设置其position为absolute,top和left为100%。
3. 通过CSS样式,将resize-corner宽高设为10px,设置resize-handle的position为relative,将resize-handle的z-index设为2。
下面是具体的代码实现:
.node-wrap {
position: absolute;
border: 1px solid #bbb;
background-color: #fff;
z-index: 1;
box-sizing: border-box;
cursor: move;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.resize-handle {
position: relative;
z-index: 2;
}
.resize-corner {
position: absolute;
width: 10px;
height: 10px;
top: 100%;
left: 100%;
margin-top: -5px;
margin-left: -5px;
cursor: se-resize;
z-index: 5;
}
4.2 进一步优化实现效果
实现节点调整大小功能后,你会发现节点的拖拽受到了影响。因为resize边框的mousedown事件和drag节点的mousedown事件是互斥的,我们需要将它们区分开来。
在Vue组件中,你可以通过v-if和v-else来判断鼠标按下时的状态,然后分别调用不同的事件函数,代码如下:
<div class="resize-handle"
:style="{width: nodeSize.width + 'px', height: nodeSize.height + 'px'}"
@mousedown="resizeMousedown"
v-if="!isDragging"
ref="resizeHandle"
>
<div class="resize-corner"
@mousedown="resizeStart"
></div>
</div>
...
methods: {
dragStart(event) {
this.isDragging = true
//...
},
dragEnd() {
this.isDragging = false
//...
},
resizeStart(event) {
this.isResizing = true
//...
},
resizeEnd() {
this.isResizing = false
//...
},
resizeMousedown(event) {
if (!this.isResizing) {
this.dragStart(event)
}
}
}
上面的示例中,我们使用了isDragging和isResizing两个变量来判断当前鼠标按下的状态,然后分别调用不同的事件。通过这种方式,我们可以优化节点的拖拽和resize功能,使得它们更加平滑。
5. 总结
在本文中,我们介绍了如何使用Vue.js和jsmind库实现思维导图节点的拖拽和调整大小两个重要功能。通过学习本文,您已经掌握了如何运用Vue.js和jsmind来开发思维导图应用。希望这篇文章对您有所帮助。