整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

实现JavaScript图形拖拽功能

实现炫酷的的拖行拖拽

1.需求分析:设计一个元素,可以跟随鼠标的移动,元素也进行移动,并且能够在鼠标按上与按下元素的时候,元素可以进行改变样式颜色。

2. 设计思路:先是需要获取元素,给元素绑定鼠标按下的事件,在绑定的事件中,兼容event事件,获取鼠标的坐标和元素的坐标,通过鼠标的坐标减去元素的坐标就可以得到鼠标在元素中的坐标。在绑定事件中,写上一个元素的移动事件,获取元素的移动坐标。最后,在鼠标按上的事件函数中,可以调用元素的移动事件就可以了。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>图层拖拽</title>
 <style>
 .box {
 width: 200px;
 height: 200px;
 background-color: skyblue;
 border: 2px solid #ccc;
 cursor: pointer;
 position: absolute;
 top: 20px;
 left: 100px;
 }
 </style>
</head>
<body>
<div class="box" id="box"></div>
</body>
<script>
 var box = document.getElementById("box");
 box.onmousedown = function(env){
 // 兼容event事件
 var env = env || window.event;
 // 获取鼠标的坐标
 var x = env.clientX;
 var y = env.clientY;
 // 获取元素的坐标
 var left = box.offsetLeft;
 var top = box.offsetTop;
 // 获取鼠标在元素中的坐标
 var x_left = x - left;
 var y_top = y -top;
 // 鼠标点击后改变颜色
 box.style.background = "red";
 // 元素的移动事件函数
 box.onmousemove = function(env){
 // 兼容event事件
 var env = env || window.event;
 // 获取元素移动时的鼠标的坐标
 var x = env.clientX;
 var y = env.clientY;
 // 元素的移动坐标
 box.style.left = (x - x_left)+"px";
 box.style.top = (y - y_top)+"px";
 }
 };
 // 鼠标弹出的事件函数
 box.onmouseup = function(){
 box.style.background = "skyblue";
 // 在鼠标弹出后再次调用元素的鼠标移动事件
 box.onmousemove = function(){};
 };
</script>
</html>

学习从来不是一个人的事情,要有个相互监督的伙伴,想要学习或交流前端问题的小伙伴可以私信回复小明“学习” 获取资料,一起学习!

要用到的 JS 事件有:

onmousedown:鼠标点下事件

onmousemove:鼠标移动事件

onmouseup:鼠标放开事件

具体代码如下:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列拖动</title>
<style type="text/css">
body,ul,li {padding: 0; margin: 0;}
ul, li {list-style: none;}
.left {width: 300px; float: left;margin: 3px;}
.right {width: 300px; float: left; margin:3px;}
.column {width: 200px;height: 30px; line-height: 30px; background-color: #AACCFF; margin: 8px 5px; text-align: center; cursor: pointer;}
.columnOld {width: 200px; height: 30px; line-height: 30px; background-color: #CCC; margin: 8px 5px; text-align: center;}
.target {border: 1px solid #CCC; background-color: #FFF5EE;box-shadow: 0 0 8px #CCC; -moz-box-shadow: 0 0 8px #CCC; -webkit-box-shadow: 0 0 8px #CCC;}
.container {width: 600px; height: 200px; display: block;}
</style>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
window.onload = function(){
var Lis = document.getElementsByClassName("column");
var container = document.getElementsByClassName("container")[0];
for (var i = Lis.length - 1; i >= 0; i--) {
var obj = Lis[i];
var source = obj.parentNode;
var target = document.getElementById("container");
moveColumn(obj, target, source);
}
}
/**
* 字段拖拽事件
*/
function moveColumn(obj, target, source) {
// 1. 获取事件
obj.onmousedown = function(event) {
var ev = event || window.event;
// 2. 复制新节点,设置透明度和innerHTML,class
var newObj = document.createElement("li");
newObj.className = 'column';
newObj.style.opacity = '0.5';
newObj.style.filter = 'alpha(opacity:50)';
newObj.innerHTML = obj.innerHTML;
newObj.style.margin = '0';
newObj.style.position = 'absolute';
newObj.style.zIndex = '5';
newObj.source = source;
// 3. 计算点击点在 obj 上的位置
var disH = ev.clientY - obj.offsetTop;
var disL = ev.clientX - obj.offsetLeft;
// 4. 设置绝对定位的top和left
newObj.style.top = obj.offsetTop + 'px';
newObj.style.left = obj.offsetLeft + 'px';
// 5. 添加节点
obj.parentNode.appendChild(newObj);
// 6. 鼠标移动事件
document.onmousemove = function(e) {
// 1. 获取事件
var e = e || window.event;
// 2. 获取鼠标位置,设置newObj的定位
var L = e.clientX - disL;
var T = e.clientY - disH;
newObj.style.top = T + 'px';
newObj.style.left = L + 'px';
// 3. source 背景色和边框变换
$(target).addClass("target");
obj.className = "columnOld";
}
// 7. 鼠标松开事件
document.onmouseup = function() {
$(target).removeClass("target");
// target.class = '';
var not = newObj.offsetTop;
var nol = newObj.offsetLeft;
var tot = target.offsetTop;
var tol = target.offsetLeft;
if (not >= tot && nol >= tol && not <= tot + target.offsetHeight && nol <= tol + target.offsetWidth) {
newObj.removeAttribute('style');
newObj.className = "column";
newObj.style.float = "left";
target.appendChild(newObj);
backColumn(newObj, source, target);
var id = obj.id;
newObj.id = id;
obj.id = id + "_old";
obj.onmousedown = null;
} else {
obj.className = "column";
obj.parentNode.removeChild(newObj);
}
document.onmouseup = null;
document.onmousemove = null;
}
}
}
function backColumn(obj, target, source) {
var Lis = source.getElementsByTagName('li');
var lineNum = Math.floor(source.offsetWidth / 210);
var liFirst = Lis[0].offsetTop;
var liHeight = Lis[0].offsetHeight;
var liWidth = Lis[0].offsetWidth;
// 1. 获取事件
obj.onmousedown = function(event) {
var ev = event || window.event;
// 2. 复制新节点,设置透明度和innerHTML,class
var newObj = document.createElement("li");
newObj.className = 'column';
newObj.style.opacity = '0.5';
newObj.style.filter = 'alpha(opacity:50)';
newObj.innerHTML = obj.innerHTML;
newObj.style.margin = '0';
newObj.style.position = 'absolute';
newObj.style.zIndex = '5';
// 3. 计算点击点在 obj 上的位置
var disH = ev.clientY - obj.offsetTop;
var disL = ev.clientX - obj.offsetLeft;
// 4. 设置绝对定位的top和left
newObj.style.top = obj.offsetTop + 'px';
newObj.style.left = obj.offsetLeft + 'px';
// 5. 添加节点
obj.parentNode.appendChild(newObj);
// 6. 添加空白节点(占位)
var blank = document.createElement("li");
blank.className = 'column';
blank.style.backgroundColor = '#63B8FF';
blank.style.float = "left";
// 6. 鼠标移动事件
document.onmousemove = function(e) {
// 1. 获取事件
var e = e || window.event;
// 2. 获取鼠标位置,设置newObj的定位
var L = e.clientX - disL;
var T = e.clientY - disH;
newObj.style.top = T + 'px';
newObj.style.left = L + 'px';
// 3. source 背景色和边框变换
$(target).addClass("target");
obj.className = "columnOld";
// 根据当前拖拽到的位置计算其重新排序后的位置
var line = lineNum * Math.round((T - liFirst)/liHeight)
var n = line + Math.floor(L / liWidth);
// 将空白节点插入到该位置
// if ()
source.insertBefore(blank,source.children[n]);
}
// 7. 鼠标松开事件
document.onmouseup = function() {
$(target).removeClass("target");
// target.class = '';
var not = newObj.offsetTop;
var nol = newObj.offsetLeft;
var tot = target.offsetTop;
var tol = target.offsetLeft;
if (not >= tot && nol >= tol && not <= tot + target.offsetHeight && nol <= tol + target.offsetWidth) {
var oldObj = document.getElementById(obj.id + '_old');
oldObj.className = 'column';
source.removeChild(newObj);
source.removeChild(obj);
oldObj.id = obj.id;
moveColumn(oldObj, source, target);
obj.onmousedown = null;
} else {
obj.className = "column";
obj.parentNode.removeChild(newObj);
// 将被拖拽的元素插入到空白节点的位置
if (blank.parentNode == source) {
source.insertBefore(obj,blank);
}
// 删除拖拽样式
// obj.removeAttribute('style');
}
if (blank.parentNode == source) {
// 删除空白节点
source.removeChild(blank);
}
document.onmouseup = null;
document.onmousemove = null;
}
}
}
function getStyle(obj, attr) {
if (obj.currentStyle) {
return obj.currentStyle[attr];
} else {
return getComputedStyle(obj, false)[attr];
}
}
</script>
</head>
<body>
<div style="overflow: hidden;">
<ul class="left">
<li class="column" id="c1">字段a-1</li>
<li class="column" id="c2">字段a-2</li>
<li class="column" id="c3">字段a-3</li>
<li class="column" id="c4">字段a-4</li>
<li class="column" id="c5">字段a-5</li>
</ul>
<ul class="right">
<li class="column" id="c6">字段b-1</li>
<li class="column" id="c7">字段b-2</li>
<li class="column" id="c8">字段b-3</li>
<li class="column" id="c9">字段b-4</li>
<li class="column" id="c10">字段b-5</li>
</ul>
</div>
<div class="container" id="container">
</div>
</body>
</html>

最终效果

比较简单,欢迎留言指正,代码比较冗余,还没来得及做整理,往见谅。

【标题】:一文教你用Vue.js轻松实现50行代码的拖拽式自定义分割布局

---

篇引言



在Web前端开发领域中,构建高度交互和用户友好的界面是至关重要的一步。Vue.js作为一款流行的渐进式JavaScript框架,以其响应式的数据绑定、组件化开发模式以及易于上手的API深受开发者喜爱。本文将通过一个实战案例,教你在短短50行Vue.js代码内,实现一个灵活易用的拖拽式自定义分割布局,让你的应用瞬间提升用户体验。

---

项目初始化与环境搭建

bash
vue create my-split-layout
cd my-split-layout
npm install vuedraggable

1. 引入并注册组件

javascript
import Vue from 'vue'
import Draggable from 'vuedraggable'

Vue.component('draggable', Draggable)

2. 创建自定义分割布局组件



创建名为`SplitLayout.vue`的组件文件,我们将在这个组件中编写主要逻辑。

---
  

3. 设计布局结构

3.1 定义基础模板

html
<template>
  <div class="split-layout">
    <draggable v-model="layoutItems">
      <div 
        v-for="(item, index) in layoutItems"
        :key="index"
        class="layout-item"
        :style="{ width: item.width + '%' }"
      >
        <!-- 这里放置你的内容 -->
      </div>
    </draggable>
  </div>
</template>

这里的`layoutItems`数组将存储每个布局区域的宽度信息。

3.2 添加样式

css
.split-layout {
  display: flex;
}
.layout-item {
  box-sizing: border-box;
  height: 100%;
  overflow: auto;
}

---

4. 实现拖拽逻辑

4.1 初始化数据

javascript
export default {
  data() {
    return {
      layoutItems: [{ width: 50 }, { width: 50 }] // 初始两个等宽区域
    };
  },
  // ...
}

4.2 监听拖拽事件

javascript
mounted() {
  this.$nextTick(() => {
    this.updateLayout();
  });
},
methods: {
  updateLayout() {
    const totalWidth = 100; // 布局总宽度
    let sum = 0;
    this.layoutItems.forEach((item, index) => {
      if (index !== this.layoutItems.length - 1) {
        sum += item.width;
        item.width = `${sum}%`;
      } else {
        item.width = `${totalWidth - sum}%`; // 最后一个元素填充剩余宽度
      }
    });
  },
  onDragEnd(newIndex, oldIndex) {
    this.updateLayout();
  }
},
watch: {
  layoutItems: {
    handler(newVal) {
      this.updateLayout();
    },
    deep: true
  }
}

4.3 绑定拖拽结束事件

html
<draggable @end="onDragEnd" ...>
<!-- ... -->
</draggable>

---

结语