MENU

vue3+element-plus+table+sortablejs实现行或列的拖拽web前端之实现拖拽放置、复制元素vue2+html5+原生dom+原生JavaScript实现跨区域拖放vue+element实现跨区域复制拖放vue2实现跨区域拖放vue2+mousedown实现全屏拖动,全屏投掷vue+element+vuedraggable实现拖拽排序vue3+element-plus+vuedraggable实现图片上传拖拽排序(若依)vue2+transition-group实现拖动排序原生拖拽排序

vue3+element-plus+table+sortablejs实现行或列的拖拽

前言

vue3+element-puls列表行、列拖拽的需求,想找一个成熟的解决方法。但发现vue3的比较少,所以就把这个分享出来,希望可以帮助到大家。vuedraggable是一款vue3的拖拽插件,基于sortable.js实现,可以用来拖拽列表、菜单、工作台、选项卡等常见的工作场景。安装的是vuedraggable@next,引入使用的是sortable.js。

npm install vuedraggable@next -S

yarn add vuedraggable@next

html

行拖动排序

列拖动排序

表格标签一定要加上唯一值。如果没有,则数据更新,但界面没有效果。 行的唯一值 <=> :row-key="(row) => row.id" 列的唯一值 <=> :key="keyTable" 当需要在一个表内同时实现行或列拖拽时,需要把行和列的唯一值都写在el-table上才起作用。

JavaScript

import Sortable from "sortablejs";

let tableList1 = ref([

{ id: "a1", name: "何二", sex: 0, age: 18 },

{ id: "b2", name: "张三", sex: 1, age: 20 },

{ id: "c3", name: "李四", sex: 1, age: 20 },

{ id: "d4", name: "王五", sex: 0, age: 25 },

{ id: "e5", name: "赵六", sex: 1, age: 56 },

{ id: "f6", name: "田七", sex: 1, age: 35 },

]),

tableList2 = ref([

{ id: "a1", name: "何二", sex: 0, age: 18 },

{ id: "b2", name: "张三", sex: 1, age: 20 },

{ id: "d4", name: "王五", sex: 0, age: 25 },

{ id: "e5", name: "赵六", sex: 1, age: 56 },

]);

// 拖动列排序

let refColumn = ref(),

keyTable = ref(),

tableIColumn = ref([

{ label: "姓名", prop: "name", width: "", align: "" },

{ label: "性别", prop: "sex", width: "68", align: "center" },

{ label: "年龄", prop: "age", width: "68", align: "center" },

]);

/**

* 列拖动排序初始化

*/

function handleInitColumn() {

nextTick(() => {

let refEl = refColumn.value.$el.querySelector(".el-table__header-wrapper tr");

Sortable.create(refEl, {

animation: 150,

onEnd(event) {

const oldItem = tableIColumn.value[event.oldIndex];

tableIColumn.value.splice(event.oldIndex, 1);

tableIColumn.value.splice(event.newIndex, 0, oldItem);

keyTable.value = "key" + new Date().getTime();

nextTick(() => {

// 因为table被强制重新绘制

// 因此需要重新监听

handleInitColumn();

});

},

});

});

}

/**

* 行拖动排序初始化

*/

function handleInitRow() {

// 要拖拽元素的父容器

let tbody = document.querySelector("#idRow .el-table__body-wrapper tbody");

new Sortable(tbody, {

// 可被拖拽的子元素

draggable: "#idRow .el-table__row",

/**

* 开始移动

* @param {Object} event

*/

onStart: function (event) {

event.item.classList.add("b_lg01_i");

},

/**

* 移动过程

* @param {Object} event

*/

// onMove(event) {

// // 设置经过的行的背景色为灰色(此方式不起作用,因为样式权重问题)

// event.related.classList.add("b_lg01_i");

// },

/**

* 移动结束(放置)

* @param {Object} event

*/

onEnd({ item, newIndex, oldIndex }) {

// 设置经过的行的背景色为灰色(此方式不起作用,因为样式权重问题)

// item.style.backgroundColor = 'initial';

const currRow = tableList1.value.splice(oldIndex, 1)[0];

tableList1.value.splice(newIndex, 0, currRow);

item.classList.remove("b_lg01_i");

},

});

}

nextTick(() => {

handleInitColumn();

handleInitRow();

});

代码中的每一个nextTick都有它的用处,一个都不能少,否则有bug。

style

.b_lg01_i {

background: linear-gradient(to top, #fffaf0, #ffdead) !important;

}

.bc_initial_i {

background-color: initial !important;

}

添加lang="scss" scoped属性需谨慎,这会导致样式不起作用。

web前端之实现拖拽放置、复制元素

效果图

html

语文

数学

英语

音乐

政治

历史

体育

课表星期一星期二星期三星期四星期五星期六星期天
上午
下午

JavaScrip

const container = document.querySelector('.container');

// 移动的元素

let source = undefined;

/**

* 移动开始

* @param {Element} e 元素

*/

container.ondragstart = (e) => {

// 设置鼠标样式

e.dataTransfer.effectAllowed = e.target.dataset.effect;

source = e.target;

}

/**

* 移动过程

* @param {Element} e 元素

*/

container.ondragover = (e) => {

// 大部分标签不允许把元素放到它上面

// 导致ondrop事件不被触发

// 这个是阻止标签默认行为

e.preventDefault();

}

/**

* 当前子元素如果不存在该属性,继续寻找父元素,直到找到为止

* @param {*} node 元素节点

* @returns 带匹配的自定义属性的元素节点

*/

function getDropNode(node) {

while (node) {

if (node.dataset?.drop) return node;

node = node.parentNode;

}

}

/**

* 清空背景

*/

function clearDropStyle() {

const dropNodes = document.querySelectorAll('.drop_over');

dropNodes.forEach((node) => {

node.classList.remove('drop_over');

});

}

/**

* 移动结束

* @param {Element} e 元素

* @returns null

*/

container.ondragenter = (e) => {

clearDropStyle();

const dropNode = getDropNode(e.target);

if (!dropNode) return false;

if (e.dataTransfer.effectAllowed === dropNode.dataset.drop) dropNode.classList.add('drop_over');

}

/**

* 放置时触发

* @param {Element} e 元素

* @returns null

*/

container.ondrop = (e) => {

clearDropStyle();

const dropNode = getDropNode(e.target);

if (!dropNode) return false;

if (e.dataTransfer.effectAllowed !== dropNode.dataset.drop) return false;

if (dropNode.dataset.drop === 'copy') {

dropNode.innerHTML = '';

const cloned = source.cloneNode(true);

cloned.dataset.effect = 'move';

dropNode.appendChild(cloned);

} else {

source.remove();

}

}

style

* {

margin: 0;

padding: 0;

box-sizing: border-box;

}

body {

height: 100vh;

display: flex;

flex-direction: column;

align-items: center;

justify-content: center;

}

.container {

height: 268px;

display: flex;

}

.left {

height: 100%;

margin-right: 5px;

display: flex;

flex-flow: column;

justify-content: space-between;

background-color: #efefef;

padding: 8px;

}

.item {

width: 40px;

height: 24px;

font-size: 16px;

line-height: 24px;

text-align: center;

margin-left: auto;

margin-right: auto;

}

.color1 {

background-color: #e44387;

}

.color2 {

background-color: #69f9a6;

}

.color3 {

background-color: #e25d4b;

}

.color4 {

background-color: #ffea60;

}

.color5 {

background-color: #7ae5f6;

}

.color6 {

background-color: #c55fef;

}

.color7 {

background-color: #66fea7;

}

.right {

height: 100%;

margin-left: 5px;

background-color: #efefef;

padding: 8px;

display: flex;

align-items: center;

}

th {

background-color: #afafaf;

}

td {

width: 50px;

height: 30px;

text-align: center;

}

.drop_over {

background-color: #cfcfcf;

}

vue2+html5+原生dom+原生JavaScript实现跨区域拖放

关键代码

// 放

function drop(ev) {

let data = ev.dataTransfer.getData("Text"),

i = ev.path[1].getAttribute("i"),

text = document.getElementById(data).cloneNode(true).innerText.trim();

if (i == null) return alert('请放置在文件名上');

if (app.fileS[i].divs.includes(text)) return alert('不能放重复数据');

app.fileS[i].divs.push(text);

for (let is = 0; is < app.fileS.length; is++) {

if (i == is) {

app.fileS[is].isShow = true;

} else {

app.fileS[is].isShow = false;

}

}

}

完整代码

gitee(码云) - mj01分支 - copyDragAndDrop 文件

vue+element实现跨区域复制拖放

html部分

ondrop="drop(event)" ondragover="allowDrop(event)">

{{item.title}}

{{items}}

×

draggable="true" ondragstart="drag(event)">

源数据 {{item}}

JavaScript部分

let app = new Vue({

el: "#app",

data() {

return {

fileS: [

{ id: 1, title: "文件夹1", divs: [], isShow: false },

{ id: 2, title: "文件夹2", divs: [], isShow: false },

{ id: 3, title: "文件夹3", divs: [], isShow: false }

]

}

},

methods: {

openOff(i) {

for (let is = 0; is < this.fileS.length; is++) {

if (i == is && !this.fileS[is].isShow) {

this.fileS[is].isShow = true;

} else {

this.fileS[is].isShow = false;

}

}

}

}

});

// 移动

function allowDrop(ev) {

ev.preventDefault();

}

// 拖

function drag(ev) {

ev.dataTransfer.setData("Text", ev.target.id);

}

// 放

function drop(ev) {

let data = ev.dataTransfer.getData("Text"),

i = ev.path[1].getAttribute("i"),

text = document.getElementById(data).cloneNode(true).innerText.trim();

if (i == null) return alert('请放置在文件名上');

if (app.fileS[i].divs.includes(text)) return alert('不能放重复数据');

app.fileS[i].divs.push(text);

for (let is = 0; is < app.fileS.length; is++) {

app.fileS[is].isShow = i === is ? true : false;

}

}

vue2实现跨区域拖放

关键代码

dragend(item) {

console.log(item);

if (this.oldItem != this.newItem) {

let oldIndex = this.List.indexOf(this.oldItem);

let newIndex = this.List.indexOf(this.newItem);

let oldflag = false

let newflag = false

if (oldIndex === -1) {

oldflag = true

oldIndex = this.list.indexOf(this.oldItem);

}

if (newIndex === -1) {

newflag = true

newIndex = this.list.indexOf(this.newItem);

}

let newList = [...this.List]; // 中间数组,用于交换两个节点

let newlist = [...this.list]; // 中间数组,用于交换两个节点

if (!oldflag) {

newList.splice(oldIndex, 1);

} else {

newlist.splice(oldIndex, 1);

}

if (!newflag) {

newList.splice(newIndex, 0, this.oldItem);

} else {

newlist.splice(newIndex, 0, this.oldItem);

}

// 删除老的节点

// newList.splice(oldIndex, 1);

// // 在列表目标位置增加新的节点

// newList.splice(newIndex, 0, this.oldItem);

// // 更新this.List,触发transition-group的动画效果

this.List = [...newList];

this.list = [...newlist];

}

}

完整代码

gitee(码云) - mj01分支 - dragAndDrop 文件

vue2+mousedown实现全屏拖动,全屏投掷

html

鼠标滑动

@mousemove.prevent='mousemove(site, $event)' @mouseup='mouseup(site, $event)'>

{{ site.name }}

{{ index }} : {{ site.name }}

JavaScript

new Vue({

el: '#app',

data: {

list1: [{ name: '拖动我', index: 0 }],

list2: [{ name: 'a', index: 0 }, { name: 'b', index: 1 }, { name: 'c', index: 2 }, { name: 'd', index: 3 }],

vm: '',

sb_bkx: 0,

sb_bky: 0,

is_moving: false

},

methods: {

mousedown: function (site, event) {

var startx = event.x;

var starty = event.y;

this.sb_bkx = startx - event.target.offsetLeft;

this.sb_bky = starty - event.target.offsetTop;

this.is_moving = true;

},

mousemove: function (site, event) {

var endx = event.x - this.sb_bkx;

var endy = event.y - this.sb_bky;

var _this = this

if (this.is_moving) {

event.target.style.left = endx + 'px';

event.target.style.top = endy + 'px';

}

},

mouseup: function (e) {

this.is_moving = false;

}

}

});

css

.ctn {

line-height: 50px;

cursor: pointer;

font-size: 20px;

text-align: center;

float: left;

}

.sub:hover {

background: #e6dcdc;

color: white;

width: 100px;

}

.ctn1 {

border: 1px solid green;

width: 100px;

}

.ctn2 {

border: 1px solid black;

width: 100px;

margin-left: 50px;

}

.fixed {

width: 100px;

height: 100px;

position: fixed;

background: red;

left: 10px;

top: 10px;

cursor: move;

}

vue+element+vuedraggable实现拖拽排序

使用yarn add vuedraggable或者npm i -S vuedraggable安装拖拽组件。

v-model="codeList"

@update="datadragEnd"

:options="{ animation: 200 }"

>

 {{ item.field_title }}

import draggable from "vuedraggable";

async datadragEnd(evt) {

evt.preventDefault();

// console.log('拖动前的索引 :' + evt.oldIndex)

// console.log('拖动后的索引 :' + evt.newIndex)

// 遍历数组,将索引值赋值到对应的 sort_order上面,完成排序

let arr = this.codeList;

let newArr = await arr.map((item, i) => {

return {

sort_order: i,

field_code: item.field_code,

};

});

const res = await this.$axios.post(`customer/save_order`, {

list: newArr,

});

// console.log(res);

const { error, message } = res.data;

if (error == 0) {

this.$message.success(message);

}

},

vue3+element-plus+vuedraggable实现图片上传拖拽排序(若依)

前言

安装对应的vuedraggable组件 npm install vuedraggable@4.1.0 --save package.json文件中记录对应的版本号为: "vuedraggable": "4.1.0",这里要注意咯!!!克隆项目的时候这里的4.1.0可能会变为^4.1.0,一定要改为4.1.0;如果不是可以先卸载然后安装正确的版本即可。 如果版本不对会报错,并且不能运行。

本案例基于若依vue3前后端分离项目做二次开发 若依自带二次封装element-plus图片上传组件,但是没有实现拖拽排序功能。 于是又自己封装了一个ImageUploadDraggable图片上传组件,此组件基于若依自带的图片上传组件的基础上进行再次封装。 组件正常引入即可,可以全局引入或局部引入,引入方式跟我们自定的组件一样。

html

JavaScript

let info = reactive({

dialogForm: {

// 图片

images: []

}

}),

{

dialogForm

} = toRefs(info);

二次封装上传组件

vue2+transition-group实现拖动排序

html

{{item}}

JavaScript

new Vue({

el: '#app',

data: {

lists: ['1: apple', '2: banana', '3: orange', '4: melon']

},

methods: {

// 取消默认行为

allowDrop(e){

e.preventDefault();

},

// 开始拖动

dragStart(e, index){

let tar = e.target;

e.dataTransfer.setData('Text', index);

if (tar.tagName.toLowerCase() == 'li') {

// console.log('drag start')

// console.log('drag Index: ' + index)

}

},

// 放置

drop(e, index){

this.allowDrop(e);

// console.log('drop index: ' + index);

//使用一个新数组重新排序后赋给原变量

let arr = this.lists.concat([]),

dragIndex = e.dataTransfer.getData('Text');

temp = arr.splice(dragIndex, 1);

arr.splice(index, 0, temp[0]);

// console.log('sort');

this.lists = arr;

}

}

});

原生拖拽排序

html

  • 1
  • 2
  • 3
  • 4
  • 5

JavaScript

(function () {

let ulList = document.querySelector('#idUl'),

liList = document.querySelectorAll('li'),

currentLi = undefined;

liList.forEach(item => item.draggable = "true");

ulList.addEventListener('dragstart', (e) => {

e.dataTransfer.effectAllowed = 'move';

currentLi = e.target;

setTimeout(() => currentLi.classList.add('bc_transparent color_transparent'), 0);

});

ulList.addEventListener('dragenter', (e) => {

e.preventDefault();

if (e.target === currentLi || e.target === ulList) return false;

let liArray = Array.from(ulList.childNodes),

currentIndex = liArray.indexOf(currentLi),

targetindex = liArray.indexOf(e.target)

if (currentIndex < targetindex) {

ulList.insertBefore(currentLi, e.target.nextElementSibling);

} else {

ulList.insertBefore(currentLi, e.target);

}

});

ulList.addEventListener('dragover', (e) => e.preventDefault());

ulList.addEventListener('dragend', (e) => currentLi.classList.remove('bc_transparent color_transparent'));

})();

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: