拖拽删除

实现效果

在这里插入图片描述

背景

自营上传图片,但是需要排序和删除功能,所以用到了h5的拖拽
在这里插入图片描述

源元素: 即被拖拽的元素。

目标元素: 即合法的可释放元素。

每个事件的事件主体都是两者之一。

拖拽事件

在这里插入图片描述

触发顺序及次数

被拖拽元素,事件触发顺序是 dragstart->drag->dragend;对于目标元素,事件触发的顺序是 dragenter->dragover->drop/dropleave。

其中drag和dragover会分别在源元素和目标元素反复触发。整个流程一定是dragstart第一个触发,dragend最后一个触发。

这里还有一个注意的点,如果某个元素同时设置了dragover和drop的监听,那么必须阻止dragover的默认行为,否则drop将不会被触发。

  • 站在源元素和目标元素的角度来看,就是dragstart 可以获取到当前的信息,源dragenter可以获取到目标元素,dragend,此时拖拽结束,可以做碰撞检测的逻辑

移动位置

api使用

这里我利用 dragstart 记录源数据,和索引。利用dragenter记录目标元素的数据,和索引,等拖拽结束,利用dragend做位置移动逻辑。

排序逻辑 (核心逻辑)

  • 利用splice, 先删除源数据,然后在目标元素之后,添加新元素。实现拖拽排序

比如将a 和b交换位置

  1. 获取a和b的索引
  2. 先将a删除
  3. 在b之后,再添加a
let oldData = 'a'; // 拖动那个元素
let newData = 'b'; // 要移动到那
let arr = ['d', 'a', 'c', 'b', 'e'];
let indexA = arr.indexOf(oldData); // 0
let indexB = arr.indexOf(newData); // 1
arr.splice(indexA, 1);
arr.splice(indexB, 0, oldData);
console.log('arr', arr); //[ 'd', 'c', 'b', 'a', 'e' ]

代码逻辑

<template>
	<div class="mg-top-wrap">
			<!-- @dragover="dragover($event)" -->
		<div
			class="drag-sort-box"
		>
			<div
				class="drag-sort-item"
				v-for="(item, index) in images"
				:key="item"
				:draggable="true"
				@dragstart="dragstart(item, index)"
				@dragenter="dragenter(item, $event)"
				@dragend="dragend(item, $event)"
				@dragover="dragover($event)"
				@mouseover="mouseover(index)"
				@mouseout="mouseout()"
			>
				<p
					:class="index === indexDel ? 'moxsind' : ''"
					@click="delPicHandler()"
				></p>

				<img :src="item.image_url" />
			</div>
		</div>
		<wd-button class="" @click="chooseImage()" :loading="loading">
			上传图片
			<input
				@change="uploadImg($event)"
				type="file"
				style="display: none"
				id="upload"
			/>
		</wd-button>
		<div>记得去图文详情保存哦~</div>
	</div>
</template>

<script setup>
import { onMounted, reactive, ref, watch } from 'vue';
import axios from '../../../utils/ajax';
const props = defineProps({
	shopImage: Array, // 图片列表
});
const images = ref([]);

const emit = defineEmits(['change']);

watch(
	() => props.shopImage,
	(val) => {
		console.log('数据是否发生变化', val);
		if (val.length) {
			images.value = props.shopImage;
		}
	}
);

const itemClass = ref('');
// images.value = images.value.map((v, i) => (v = v + '?index=' + i)); //不重复key
console.log('sssss', images.value);
let oldData = null;
let newData = null;

const dragstart = (value, index) => {
	oldData = value;
	console.log('开始的值', images.value);
};
const dragenter = (value, e) => {
	newData = value;
	e.preventDefault();
};

const dragover = (e) => {
	e.preventDefault();
};
const indexDel = ref('');
const mouseover = (index) => {
	indexDel.value = index;
	console.log('index', index);
};
const mouseout = () => {
	indexDel.value = '';
};
const delPicHandler = () => {
	images.value.splice(indexDel.value, 1);
	// emit('change', images.value);
};

const dragend = () => {
	if (oldData !== newData) {
		let oldIndex = images.value.indexOf(oldData);
		let newIndex = images.value.indexOf(newData);

		let newItems = [...images.value];
		newItems.splice(oldIndex, 1);
		newItems.splice(newIndex, 0, oldData);
		images.value = [...newItems];
		console.log('结束的值', images.value);
		emit('change', images.value);
	}
};
const loading = ref(false);
const chooseImage = () => {
	document.getElementById('upload').click();
};
const uploadImg = (e) => {
	let file = e.target.files[0];
	let formdata = new FormData();
	formdata.append('file', file);
	uploadImage(formdata);
};
const uploadImage = (formdata) => {
	loading.value = true;
	axios.post('/Upload/uploadImage', formdata).then((res) => {
		if (!res.code) {
			loading.value = false;
			console.log('res.data', res.data);
			images.value.push({ image: res.data.key, image_url: res.data.url });
			console.log('images.value', images.value);
			emit('change', images.value);

			// 刷新列表
		} else {
			loading.value = false;
		}
	});
};
</script>

<style lang="scss" scoped>
p {
	margin: 0;
	padding: 0;
}
.drag-sort-box {
	height: 330px;
	overflow: scroll;
	width: 100%;
	display: flex;
	flex-wrap: wrap;
}
.drag-sort-box .drag-sort-item {
	width: 200px;

	margin: 10px;
	cursor: pointer;
	transition: all 0.3s;
	// background: #ccc;
	position: relative;
}

.drag-sort-box .drag-sort-item img {
	width: 100%;
	transition: all 0.3s;
	position: relative;
}
.drag-sort-box .drag-sort-item .active {
	position: absolute;
	top: 0;
	left: 0;
	align-items: center;
	justify-content: center;
	background: url(https://jira.inagora.org/secure/projectavatar?pid=11206&avatarId=10326)
		no-repeat center center;
	width: 30px;
	height: 30px;
}

.moxsind {
	width: 100%;
	height: 100%;
	position: absolute;
	top: -10px;
	left: -10px;
	z-index: 10;
	background: url(https://s5.52ritao.cn/s/70/_620652.png) no-repeat;
	background-size: 18px 18px;
	width: 18px;
	height: 18px;
}
.mg-top-wrap {
	margin-top: 10px;
}
</style>

Logo

前往低代码交流专区

更多推荐