自营上传图片,但是需要排序和删除功能,所以用到了h5的拖拽
源元素: 即被拖拽的元素。
目标元素: 即合法的可释放元素。
每个事件的事件主体都是两者之一。
被拖拽元素,事件触发顺序是 dragstart->drag->dragend;对于目标元素,事件触发的顺序是 dragenter->dragover->drop/dropleave。
其中drag和dragover会分别在源元素和目标元素反复触发。整个流程一定是dragstart第一个触发,dragend最后一个触发。
这里还有一个注意的点,如果某个元素同时设置了dragover和drop的监听,那么必须阻止dragover的默认行为,否则drop将不会被触发。
这里我利用 dragstart 记录源数据,和索引。利用dragenter记录目标元素的数据,和索引,等拖拽结束,利用dragend做位置移动逻辑。
比如将a 和b交换位置
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>