html 树形图可拖拽,HTML5拖拽API实现vue树形拖拽组件

因业务场景需要一个可拖拽修改节点位置的树形组件,因此动手撸了一个,乘此机会摸了一把html5原生拖拽。近期有时间将核心部分代码抽出,简单说下实现方式。

1.树形结构-组件递归使用

树形结构非常简单,tree组件作为父组件,结构如下

tree.vue

复制代码

vue组件允许在它们自己的模板中调用自身,因此可以形成树形结构,在组件中必须填写唯一的name。

tree-node.vue

复制代码

2.HTML5拖拽api

1.draggable属性规定元素是否可拖动,目前Internet Explorer 9+, Firefox, Opera, Chrome, and Safari 支持 draggable 属性

2.HTML 5 拖放api

ondragstart: 元素开始被拖动时触发 作用在拖拽元素上

ondragenter:当拖曳元素进入目标元素的时候触发的事件,作用在目标元素上

ondragover:拖拽元素在目标元素上移动的时候触发的事件,作用在目标元素上

ondragleave:拖拽元素拖离开了目标元素时触发,作用在目标元素上

ondrop:被拖拽的元素在目标元素上同时鼠标放开触发的事件,作用在目标元素上

ondragend:当拖拽完成后触发的事件,作用在被拖曳元素上

3.拖拽节点

定义变量

处理拖拽节点需要几个关键变量

当前拖拽的节点

拖拽时经过的节点

最终放置的节点

因此定义了一个用于保存拖拽信息的对象

dragOverStatus: {

overNodeKey: "",

dropPosition: "",

dragNode: {}

}

复制代码

绑定拖拽事件

这里将ondragstart事件绑定在子元素上,将其他事件绑定在父元素上,因为在测试真机IE10的时候,发现ondragstart和其他事件绑定在同一个元素上,无法触发ondragenter等事件。

复制代码mounted() {

//绑定拖拽事件

if (this.root.draggable) {

this.$refs.draggAbleDom.draggable = !this.nodeData.noDrag;

this.$refs.draggAbleDom.ondragstart = this.onDragStart;

this.$refs.dropTarget.ondragenter = this.onDragEnter;

this.$refs.dropTarget.ondragover = this.onDragOver;

this.$refs.dropTarget.ondragleave = this.onDragLeave;

this.$refs.dropTarget.ondrop = this.onDrop;

this.$refs.dropTarget.ondragend = this.onDragEnd;

}

}

复制代码

触发某节点的拖拽事件时,就可以从拖拽事件里拿到当前节点实例。

使用HTML5提供的专门的拖拽与拖放API,原生的实现了复杂的操作,不需要自己用鼠标事件模拟,因此实现拖拽效果非常简单。

(1).开始拖拽:在拖拽元素上触发,事件内只需要保存当前拖拽节点的信息即可

onDragStart(e, treeNode) {

this.dragOverStatus.dragNode = {

nodeData: treeNode.nodeData,

parentNode: treeNode.parentNodeData

};

this.$emit("on-dragStart", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

}

复制代码

(2).进入目标节点:在目标元素上触发,主要保存当前经过的节点的key,然后向外层发出事件,供组件调用者做其他操作。为了避免拖拽一个元素快速经过许多个节点时频繁发出事件,设置定时器当停留一定时间后触发。

onDragEnter(e, treeNode) {

//当没有设置拖拽节点时,禁止作为目标节点

if (!this.hasDragNode()) {

return;

}

this.dragOverStatus.overNodeKey = "";

//拖拽节点与目标节点是同一个,return掉

if (

treeNode.nodeData._hash === this.dragOverStatus.dragNode.nodeData._hash

) {

return;

}

this.dragOverStatus.overNodeKey = treeNode.nodeData._hash; //当前经过的可放置的节点的key

//当前节点禁止做为放置节点时

if (treeNode.nodeData.noDrop) {

return;

}

//设置dragEnter定时器,停留250毫秒后触发事件

if (!this.delayedDragEnterLogic) {

this.delayedDragEnterLogic = {};

}

Object.keys(this.delayedDragEnterLogic).forEach(key => {

clearTimeout(this.delayedDragEnterLogic[key]);

});

this.delayedDragEnterLogic[

treeNode.nodeData._hash

] = setTimeout(() => {

if (!treeNode.nodeData.isExpand) {

treeNode.toggleCollapseStatus();

}

this.$emit("on-dragEnter", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

}, 250);

}

复制代码

(3).在目标节点上经过:在目标元素上触发,即时计算鼠标在目标节点上的位置,用于判断最终的放置位置,0(作为目标节点的子节点),-1(放置在目标节点的前面),1(放置在目标节点的后面),显示相应的样式。

onDragOver(e, treeNode) {

//当没有设置拖拽节点时,禁止作为目标节点

if (!this.hasDragNode()) {

return;

}

if (

this.dragOverStatus.overNodeKey === treeNode.nodeData._hash

) {

this.dragOverStatus.dropPosition = this.calDropPosition(e); //放置标识0,-1,1

}

this.$emit("on-dragOver", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

this.dragOverClass = this.setDragOverClass();//设置鼠标经过样式

},

复制代码

当鼠标处于目标节点内目标节点偏上方(1/5处),则意为放在目标节点前面-同级,当鼠标处于目标节点内目标节点偏下方(1/5处),意为放在目标节点后面-同级,否则作为目标节点的子节点

calDropPosition(e) {

var offsetTop = this.getOffset(e.target).top;

var offsetHeight = e.target.offsetHeight;

var pageY = e.pageY;

var gapHeight = 0.2 * offsetHeight;

if (pageY > offsetTop + offsetHeight - gapHeight) {

//放在目标节点后面-同级

return 1;

}

if (pageY < offsetTop + gapHeight) {

//放在目标节点前面-同级

return -1;

}

//放在目标节点里面-作为子节点

return 0;

}

复制代码

(4).放置节点:在目标元素上触发,此时将拖拽的信息变量作为参数将事件发射到外层,其余操作由外层来决定即可。

onDrop(e, treeNode) {

//当没有设置拖拽节点时,禁止作为目标节点

if (!this.hasDragNode()) {

return;

}

//当前节点禁止拖拽时

if (treeNode.nodeData.noDrop) {

return;

}

//拖拽节点与目标节点是同一个,不做任何操作

if (

this.dragOverStatus.dragNode.nodeData._hash === treeNode.nodeData._hash

) {

return;

}

var res = {

event: e,

dragNode: this.dragOverStatus.dragNode,

dropNode: {

nodeData: treeNode.nodeData,

parentNode: treeNode.parentNodeData

},

dropPosition: this.dragOverStatus.dropPosition

};

this.$emit("on-drop", res);

}

复制代码

(5).拖拽结束:作用在拖拽元素上,拖拽结束后将清除变量,恢复样式。

onDragEnd(e, treeNode) {

//当没有设置拖拽节点时,禁止作为目标节点

if (!this.hasDragNode()) {

return;

}

//当前节点禁止拖拽时

if (treeNode.nodeData.noDrop) {

return true;

}

this.dragOverStatus.dragNode = null;

this.dragOverStatus.overNodeKey = "";

this.$emit("on-dragEnd", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

}

复制代码

4.应用

调用树形拖拽组件,获取拖拽过程中的拖拽节点,目标节点,以及放置位置,具体处理拖拽结果由调用方决定,可以是通过调接口更新树结构,也可以由前端处理输入数据,更新视图。

复制代码getDropData(info) {

var dragData = info.dragNode.nodeData;

var dragParent = info.dragNode.parentNode;

var dropData = info.dropNode.nodeData;

var dropParent = info.dropNode.parentNode;

var dropPosition = info.dropPosition; //0作为子级,-1放在目标节点前面,1放在目标节点后面

//把拖拽元素从父节点中删除

dragParent.children.splice(dragParent.children.indexOf(dragData), 1);

if (dropPosition === 0) {

dropData.children.push(dragData);

} else {

var index = dropParent.children.indexOf(dropData);

if (dropPosition === -1) {

dropParent.children.splice(index, 0, dragData);

} else {

dropParent.children.splice(index + 1, 0, dragData);

}

}

}

复制代码

作为子节点,改变层级991fe97359d9bd5a07e850aac379a862.png

2e904c39ae48be32ebe924396d2c8392.png

修改排序,将拖拽节点放在目标节点后面8ebb0e0fd53c1394777e199c0cead02a.png

b380713f024f410f3ba5adbeb94c745b.png

修改排序,将拖拽节点放在目标节点前面

f5678cd5d9059b1fd35fb765052c2c53.png

71f69858902bcd408b7610b96d0c56bb.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/272984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jmeter如何定位网络延时_JMeter用户定义变量和properties变量高级使用

Jmeter有个配置元素叫做用户自定义变量(英文名称是UserDefinedVariables)而我们提到的vars即是Variables的简写。 之前我们也说到过Jmeter的脚本中(jsr223sampler或者beanshell编写的脚本)使用varsput和varsget的操作(varsget和put的操作仅在threadgroup测试组线程中执行&#…

jQuery中的几个模块总结

Query插件&#xff0c;以备并希望在前端方面有所长进。请批评指正。 一&#xff0c;类型判断全解 JQuery判断类型扩展方法&#xff1a;$.type() 1 /*type: function( obj ) { 2 if ( obj null ) { 3 return obj ""; 4 } …

python实现连续数列相加_技术 | Python经典面试题解析实现斐波那契数列

黑马程序员微信号&#xff1a;heiniu526传智播客旗下互联网资讯&#xff0c;学习资源免费分享平台大家在面试过程中经常会考到斐波那契数列&#xff0c;斐波那契数列(Fibonacci)最早由印度数学家Gopala提出&#xff0c;而第一个真正研究斐波那契数列的是意大利数学家 Leonardo …

广西2021高考成绩位次查询,2020年广西高考一分一段表及高考位次成绩排名查询(理科+文科)...

一、2020年广西高考一分一段表查询排名方法广西招办(考试院)会公布的省市高考每一分分数的考生数额统计表就是我们所说的——高考“一分一段表”&#xff0c;其显示出每一分的分数值全省考生有多少名&#xff0c;就可以让考生估算出自己的排名位次。2020年广西高考一分一段表排…

台式计算机单核与双核,什么是单核cpu、双核cpu 单核cpu和双核cpu的区别是什么...

在买电脑的时候&#xff0c;我们经常会发愁&#xff0c;究竟是买单核cpu好&#xff0c;还是买双核cpu比较好&#xff0c;尤其是面对售货员把单核cpu电脑和双核cpu电脑都可以夸的天花乱坠的时候&#xff0c;我们更糊涂了&#xff0c;究竟买哪种好呢?针对这种情况&#xff0c;小…

美国计算机生物学要求,美国大学CS专业分支生物信息学和计算生物学专业 Bioinformatics and Computational Biology介绍...

美国留学申请美国大学计算机专业(CS)的学生非常多。美国大学CS专业的研究分支也非常 多&#xff0c;不同分支对学生的要求也会不同&#xff0c;因此&#xff0c;学生们要根据自己的条件选择适合自己的研究方向。下面主要为大家介绍的是美国大学CS专业分支生物信息学和计算生物学…

Spark入门实战系列--8.Spark MLlib(上)--机器学习及SparkMLlib简介

【注】该系列文章以及使用到安装包/测试数据 可以在《倾情大奉送--Spark入门实战系列》获取 1、机器学习概念 1.1 机器学习的定义 在维基百科上对机器学习提出以下几种定义&#xff1a; l“机器学习是一门人工智能的科学&#xff0c;该领域的主要研究对象是人工智能&#xff0c…

计算机基础cpu知识,CPU基础知识: DIY装机小白必看的CPU知识扫盲

CPU也就是中央处理器&#xff0c;全拼为Central Processing Unit&#xff0c;在计算机中可以比喻成人的大脑。它是一块超大规模的集成电路&#xff0c;是一台计算机的运算核心和控制核心。它的功能主要是解释计算机指令以及处理计算机软件中的数据。下面华强电子网的小编分享一…

mvc html validator,ASP.NET MVC实现Validation验证器扩展

今天介绍在ASP.NET MVC实现Validation验证器扩展,通过使用Controller验证并不是最好的方法&#xff1a;验证过于分散&#xff0c;容易造成重复代码&#xff0c;不利于维护与扩展,因此本节将使用MVC默认绑定器(DefaultModelBinder)中包含了验证架构,并实现Validation验证器扩展&…

自定义列表视图

通过继承BaseAdapter写一个子类&#xff0c;可以创建自定义列表视图&#xff1a; public class MyListAdapter extends BaseAdapter { private LayoutInflater mInflater;//声明一个LayoutInflater类变量 private Context mContext;//声明一个Context类变量 priva…

springmvc请求返回一个字符_SpringMVC系列之Web利器SpringMVC

课程简介&#xff1a;课程目标&#xff1a;了解SpringMVC和Spring的关系&#xff0c;能够使用SpringMVC框架开发自己的Web应用。整合Spring , SpringMVC , MyBatis搭建项目开发环境&#xff0c;理解三层架构和MVC模式适用人群&#xff1a;适合对Java基础知识应用自如&#xff0…

一次完整较为渗透过程

步骤一&#xff1a; 利用阿D浏览器通过https&#xff1a;//s.bt.gg 注入关键字扫描发现注入点&#xff1a; http://www.rqyl.gov.cn/*****.php?ID153 用啊D跑不出账号密码 步骤二&#xff1a; 手工注入http://www.rqyl.gov.cn/*****.php?ID153 and 11 、and12出错 猜字段ht…

计算机网络线路争用,计算机网络系统集成复习要点

计算机网络系统集成复习要点计算机网络系统集成复习要点1.在信息领域&#xff0c;对于系统集成一般分为软件集成、硬件集成和网络系统集成。2.按网络覆盖范围的大小&#xff0c;将计算机网络分为局域网(LAN)、城域网(MAN)、广域网(WAN)和互联网。3. 计算机网络拓扑结构是指一个…

v380pro设备连接失败_天猫精灵可以连接台式电脑使用吗?需要什么东西? 安装操作是哪几个步骤? 最好有图片解说!...

使用语音将天猫精灵调到【蓝牙配对】&#xff1b;打开电脑的蓝牙适配界面&#xff0c;让电脑找到天猫精灵&#xff0c;稍等片刻&#xff0c;点击【使用远程装置的扬声器聆听来自此PC的音频】后的连接&#xff1b;最后调整音量即可。以下是详细介绍&#xff1a;1、对天猫精灵说【…

IDE-Ecplise-代码注释 模版 编码规范 配色

说明&#xff1a; 代码注释主要用于方便代码后期维护&#xff0c;编码规范&#xff0c;增加代码阅读性和维护性。因网上看到的很多博客中片段局多&#xff0c;故整理后重写一篇&#xff0c;方便交流学习。 先看下加过注释模版后的效果。如上图所示&#xff0c;创建类&#xff0…

个人信息管理系统代码_学生信息管理系统(springboot + vue)

学生信息管理系统零、基础项目为前后分离项目1、前端(front-end)基于 vue-admin-template 开发2、后端(rear-end)Jdk8Maven3MySQL5.7SpringBoot2SQLYog一、功能模块图图片.png二、系统预览1、登录登录.png2、首页首页.png3、查看学生信息查看学生信息.png4、编辑学生信息编辑学…

苹果手机6s运营商在哪里显示无服务器,iPhone6s信号很弱或无服务如何解决【解决方法】...

很多果粉都遇到过自己的手机常常“无服务”或者信号很弱的情况。 iphone6s 信号很弱或无服务怎么办&#xff1f;iPhone手机信号不好的原因有很多&#xff0c;排除SIM卡&#xff0c;手机本身硬件故障等问题&#xff0c;你可以尝试以下方法“修复”你的手机信号问题。1、开关飞行…

72年属鼠48岁有一灾2020_李半仙推算:1972年虚岁48岁属鼠人,2020年干什么最能发财??...

李半仙推算:1972年虚岁48岁属鼠人&#xff0c;2020年干什么最能发财&#xff1f;&#xff1f;生肖属鼠的朋友&#xff0c;在未来&#xff0c;喜事接二连三&#xff0c;属鼠人能够得到财神赐福&#xff0c;一路大发特发&#xff0c;很快就会有发财致富的商机&#xff0c;加上属鼠…

vue怎么插入接口demo_前端学起来特别吃力,新人入前端怎么学?

最近知乎收到一些问题&#xff0c;问前端学起来吃力&#xff0c;连续更新几次回答的比较全了。现在整理下分享给掘金的小伙伴们。原知乎问题:前言前端工作两年多。大部分前端原理、框架都能完全运用。工作中几乎遇不到解决不了的问题&#xff08;除了那些恶心无法实现的需求&am…

w7怎么重启无限服务器,w7重启数据库服务器

w7重启数据库服务器 内容精选换一换WordPress是使用PHP语言开发的博客平台&#xff0c;用户可以在支持PHP和MySQL数据库的服务器上搭建属于自己的网站&#xff0c;本文教您通过华为云虚拟私有云、弹性云服务器和RDS MySQL数据库&#xff0c;轻松几步&#xff0c;在LAMP环境下搭…