直奔主题 你们可以初始化一份JS脚本 把我代码C过去看 阅读性高一些 注释清晰
一、jsplumb
// 1、初始化 => jsPlumb.connect用于建立连线 参数有三个 source(必选,连接源的标识,可以为id、element或Endpoint,)、target(必选,连接目标的标识,可以为id、element或Endpoint,)、endpoint(可选,端点的形状)
// ----------------------------------- 示例
// jsPlumb.ready(function () {
// jsPlumb.connect({
// source: 'item_left',
// target: 'item_right',
// endpoint: 'Dot'
// })
// })
// 2、拖拽节点(拖拽盒子) => 使用draggable()
// 注意点 => 似乎盒子必须不能是标准流文档 一定要浮动起来 才可以拖拽Div
// ----------------------------------- 示例
// jsPlumb.ready(function () {
// jsPlumb.connect({
// source: 'item_left',
// target: 'item_right',
// endpoint: 'Rectangle'
// })
// jsPlumb.draggable('item_left')
// jsPlumb.draggable('item_right')
// })
// 3、其他参数 => connecttor(设置连接线的形状) 、anchor(设置锚点的位置)
// Bezier: 贝塞尔曲线
// Flowchart: 具有90度转折点的流程线
// StateMachine: 状态机
// Straight: 直线
// ----------------------------------- 示例
// jsPlumb.ready(function () {
// jsPlumb.connect({
// source: 'item_left',
// target: 'item_right',
// endpoint: 'Rectangle',
// connector: ['Bezier'],
// anchor: ['Left', 'Right']
// })
// jsPlumb.draggable('item_left')
// jsPlumb.draggable('item_right')
// })
// 4、设置连接的默认值(很多连线都是相同设置的情况下,我们可以将配置项抽离出来,作为一个单独的变量,作为connect的第二个参数传入,实际上第二个参数会和第一个参数作为一个整体)
// ----------------------------------- 示例
// let common = {
// endpoint: 'Rectangle',
// connector: ['Bezier'],
// anchor: ['Left', 'Right']
// }
// jsPlumb.ready(function () {
// jsPlumb.connect({
// source: 'item_left',
// target: 'item_right'
// }, common)
// jsPlumb.draggable('item_left')
// jsPlumb.draggable('item_right')
// })
// 5、给节点增加样式 => paintStyle(连接线的样式) 、endpointStyle(端点的样式) 作为配置项 卸载common里
// 6、限制节点拖动区域 => containment(限制节点可拖动的区域) 作为draggable的第二个参数使用
// ----------------------------------- 示例
// jsPlumb.draggable('A',{containment: 'parent'}) // {containment: 'parent'} parent => 父亲 意思为可移动区域为父亲的盒子内
// jsPlumb.draggable('B',{containment: 'parent'})
// 7、一个端点如何拖拽出多条连线
// 默认的情况下maxConnections的值为1 也就是一个端点最多只能拉出一条线 可以设为其他值
// 不限制连线数量 将该值设为-1
// ----------------------------------- 示例
// let common = {
// isSource: true,
// isTarget: true,
// connector: ['Straight'],
// maxConnections: -1
// }
// 8、给连接增加点击事件 点击删除连线 jsPlumb.deleteConnection()
// jsPlumb.bind('click', function (conn, originalEvent) {
// if (confirm("确定要删除吗")) {
// jsPlumb.deleteConnection(conn)
// }
// })
// 9、删除节点,包括节点的相关的连接 参数为 节点id
// jsPlumb.remove('item_left')
// 10、连接前的检查,判断是否给建立连接
// 当链接建立前
// jsPlumb.bind('beforeDrop', function (info) {
// var a = 10
// var b = 2
// if (a < b) {
// console.log('链接会自动建立')
// return true // 链接会自动建立
// } else {
// console.log('链接取消')
// return false // 链接不会建立,注意,必须是false
// }
// })
二、Vuedraggable
// vuedraggble插件实现拖拽效果
// 使用draggable组件步骤
// 1、安装依赖
yarn add vuedraggable
npm i -S vuedraggable
// 2、组件中 导入并注册 import draggable from 'vuedraggable';
// 3、基本参数
<!--
name 可跨越拖拽的共同类名
pull:clone 禁止拖入这里
put:false 禁止拖出这里
sort:false 禁止拖动排序
anmition 拖动时的延时动画效果
filter 不能拖动的类名
delay 延迟多少ms时拖动,防止用户误操作
使用draggable组件 v-model绑定数组
@start="onStart"// =>拖拽开始触发 @end="onEnd" // => 拖拽结束触发
-->
// 示例 => 列表拖拽
<draggable
@end="end" => 拖拽结束触发
@start="move" => 拖拽开始触发
v-model="menu.children" => 数据结构 使用v-model绑定数据
:options="draggableOptions"
>
<li
v-for="subMenu in menu.children"
class="ef-node-menu-li"
:key="subMenu.id"
:type="subMenu.type"
>
<i :class="subMenu.ico"></i> {{ subMenu.name }}
</li>
</draggable>
// 4、注意:vuedraggable新版本废弃了options属性,建议使用v-bind属性作为配置项
vue.draggable 全部事件列表
@start => 开始拖动时触发的事件
@add => 从一个数组拖拽到另外一个数组时触发的事件
@remove => 移除事件
@update => 拖拽变换位置时触发的事件
@end => 拖拽完成时的事件
@choose => 鼠标点击选中要拖拽元素时的事件
@unchoose => 选中后松开鼠标的事件
@sort => 位置变化时的事件
@clone => 从一个数组拖拽到另外一个数组时触发的事件和add不同,clone是复制了数组元素
三、G6/X6 ER图
import { Graph, Shape } from '@antv/x6'
import { data } from './GraphData'
data() {
return {
graph:null
}
},
// 要在mounted中初始化 因为created中暂未获取dom节点
mounted(){
this.init() // 初始化
this.$bus.$on('addCanvs',(x,y,obj)=>{
this.addTable(x,y,obj)
})
},
methods:{
init(){
// 渲染画布 => 创建一个 Graph 对象 并为其指定一个页面上的绘图容器,并且通常也会在这里指定画布的大小。
this.graph = new Graph({
container: document.getElementById('container'),
width: 800,
height: 600,
background: {
color: '#fffbe6', // 设置画布背景颜色
},
grid: {
size: 20, // 网格大小 10px
visible: true, // 渲染网格背景
},
connecting: {
router: {
name: 'er',
args: {
offset: 25,
direction: 'H',
},
},
createEdge() {
return new Shape.Edge({
attrs: {
line: {
stroke: '#A2B1C3',
strokeWidth: 2,
},
},
})
},
},
})
Graph.registerPortLayout(
'erPortPosition',
(portsPositionArgs) => {
return portsPositionArgs.map((_, index) => {
return {
position: {
x: 0,
y: (index + 1) * LINE_HEIGHT,
},
angle: 0,
}
})
},
true,
)
// 注册自定义节点
Graph.registerNode(
'er-rect', // 注册的节点名
{
inherit: 'rect',
markup: [
{
tagName: 'rect',
selector: 'body',
},
{
tagName: 'text',
selector: 'label',
},
],
attrs: {
rect: {
strokeWidth: 1,
stroke: '#5F95FF',
fill: '#5F95FF',
},
label: {
fontWeight: 'bold',
fill: '#ffffff',
fontSize: 12,
},
},
ports: {
groups: {
list: {
markup: [
{
tagName: 'rect',
selector: 'portBody',
},
{
tagName: 'text',
selector: 'portNameLabel',
},
{
tagName: 'text',
selector: 'portTypeLabel',
},
],
attrs: {
portBody: {
width: NODE_WIDTH,
height: LINE_HEIGHT,
strokeWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
magnet: true,
},
portNameLabel: {
ref: 'portBody',
refX: 6,
refY: 6,
fontSize: 10,
},
portTypeLabel: {
ref: 'portBody',
refX: 95,
refY: 6,
fontSize: 10,
},
},
position: 'erPortPosition',
},
},
},
},
true, // 重名时是否覆盖,默认为 false 不覆盖(重名时报错)
)
// this.graph.zoom(30) => 缩放
// this.graph.translate(800, 40) => 平移
// 渲染
const cells = []
data.forEach((item) => {
// 通过图形进行区分push
if (item.shape === 'edge') {
// push边的数据
cells.push(this.graph.createEdge(item))
} else {
// push节点的数据
cells.push(this.graph.createNode(item))
}
})
this.graph.resetCells(cells)
this.graph.zoomToFit({ padding: 10, maxScale: 1 })
},
offset(){
let offset = {
top: this.$refs.maxDiv.offsetTop,
left: this.$refs.maxDiv.offsetLeft
}
return offset
},
addTable(x,y,obj){
// 判断是否拖拽至正确区域位置
if(x > this.$refs.maxDiv.offsetLeft && y > this.$refs.maxDiv.offsetTop){
console.log(obj, this);
this.graph.addNode(obj) // 添加到画布
} else {
alert("请拖拽至正确区域")
}
}
}
ER图的data数据来源
export const data = [
{
"id": "1", // String,可选,节点的唯一标识
"shape": "er-rect", // 图形渲染 => shape 的默认值为 'rect'
"label": "学生", // String,节点标签
"width": 150, // Number,可选,节点大小的 width 值
"height": 24, // Number,可选,节点大小的 height 值
"position": { // 设置节点位置
"x": 24, // Number,必选,节点位置的 x 值
"y": 150 // Number,必选,节点位置的 y 值
},
"ports": [
{
"id": "1-1",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "ID"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "1-2",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Name"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "1-3",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Class"
},
"portTypeLabel": {
"text": "NUMBER"
}
}
},
{
"id": "1-4",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Gender"
},
"portTypeLabel": {
"text": "BOOLEAN"
}
}
}
]
},
{
"id": "2",
"shape": "er-rect",
"label": "课程",
"width": 150,
"height": 24,
"position": {
"x": 250,
"y": 210
},
"ports": [
{
"id": "2-1",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "ID"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "2-2",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Name"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "2-3",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "StudentID"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "2-4",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "TeacherID"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "2-5",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Description"
},
"portTypeLabel": {
"text": "STRING"
}
}
}
]
},
{
"id": "3",
"shape": "er-rect",
"label": "老师",
"width": 150,
"height": 24,
"position": {
"x": 480,
"y": 350
},
"ports": [
{
"id": "3-1",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "ID"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "3-2",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Name"
},
"portTypeLabel": {
"text": "STRING"
}
}
},
{
"id": "3-3",
"group": "list",
"attrs": {
"portNameLabel": {
"text": "Age"
},
"portTypeLabel": {
"text": "NUMBER"
}
}
}
]
},
{
"id": "4",
"shape": "edge",
"source": { // String,必须,起始节点 id
"cell": "1", // 连接源 id
"port": "1-1" // 连接源 具体id
},
"target": { // String,必须,目标节点 id
"cell": "2", // 目标id
"port": "2-3" // 目标具体id
},
"attrs": {
"line": {
"stroke": "#A2B1C3",
"strokeWidth": 2
}
},
"zIndex": 0
},
{
"id": "5",
"shape": "edge",
"source": {
"cell": "3",
"port": "3-1"
},
"target": {
"cell": "2",
"port": "2-4"
},
"attrs": {
"line": {
"stroke": "#A2B1C3",
"strokeWidth": 2
}
},
"zIndex": 0
}
]
四、兄弟传值 兄弟调用方法
// main.js中 挂载全局变量(实例)
Vue.prototype.$bus = new Vue()
// 发送
this.$bus.$emit('方法名',参数)
// 接收 (mounted 钩子里)
mounted(){
this.$bus.$on('方法名',(参数)=>{
事件处理....
})
},