vue 后管项目实现跨目录拖拽功能
我使用的是vuedraggable插件。参考文档:https://www.itxst.com/vue-draggable/fueijmfy.html
安装:npm i -S vuedraggable
引入:import draggable from 'vuedraggable'
<template>
<div class="classification_configuration">
<a-card>
<div class="content" v-for="(items, indexs) in classificationList" :key="indexs">
<div class="content_title">
<h4 v-show="items.moduleTypeShow">{{items.moduleType}}</h4>
<div v-show="!items.moduleTypeShow" class="content_edit">
<a-input v-model="dataTitle" placeholder="请输入内容" />
</div>
<img v-show="items.moduleTypeShow" @click="clickEdit(items, indexs)" class="image_edit" src="../../assets/img/edit.png" />
<img v-show="items.moduleTypeShow && items.menuSubList.length === 0 " @click="clickDelete(indexs)" src="../../assets/img/delete.png" />
<span v-show="!items.moduleTypeShow" @click="clickSave(indexs)" style="margin-left: 16px; margin-right: 8px;">保存</span>
<span v-show="!items.moduleTypeShow" @click="clickSaveCancel(indexs)">取消</span>
</div>
<draggable v-model="items.menuSubList" group="site" animation="300" dragClass="dragClass" ghostClass="ghostClass" chosenClass="chosenClass" @start="onStart" @end="onEnd">
<transition-group class="content_con">
<div class="content_card" v-for="item in items.menuSubList" :key="item.id"><img class="content_image" :src="item.imgUrl" :alt="item.appName">{{item.appName}}</div>
</transition-group>
</draggable>
<!-- <div class="content_title">
<h4 v-show="items.moduleTypeShow">{{items.moduleType}}</h4>
<div v-show="!items.moduleTypeShow" class="content_edit"><a-input :value="dataTitle" placeholder="请输入内容" /></div>
<img v-show="items.moduleTypeShow" @click="clickEdit(items, indexs)" class="image_edit" src="../../assets/img/edit.png" />
<img v-show="items.moduleTypeShow && items.menuSubList.length === 0 " @click="clickDelete(indexs)" src="../../assets/img/delete.png" />
<span v-show="!items.moduleTypeShow" @click="clickSave(indexs)" style="margin-left: 16px; margin-right: 8px;">保存</span>
<span v-show="!items.moduleTypeShow" @click="clickSaveCancel(indexs)">取消</span>
</div>
<div class="content_con">
<div class="content_card" v-for="(item, index) in items.menuSubList" :key="index" :draggable="true" @dragstart="dragStart(items, item)" @dragenter="dragEnter(items, item,$event)" @dragend="dragEnd(items, item, $event)" @dragover="dragOver($event)">
<img class="content_image" :src="item.imgUrl" :alt="item.appName">
{{item.appName}}
</div>
</div> -->
</div>
<div class="add_list" @click="clickAddList()"><img src="../../assets/img/add.png" />新增应用分类</div>
</a-card>
<div class="content_bottom">
<div></div>
<div>
<a-button @click="clickCancel()">取消</a-button>
<a-button @click="clickPreview()" class="button_class">预览</a-button>
<a-button @click="clickRelease()" class="button_class" type="primary">发布</a-button>
</div>
</div>
<div class="messge" v-show="showPreview">
<div class="messge_con test">
<div class="card">
<div v-for="(elements, indexs) in classificationList" :key="indexs">
<h4>{{elements.moduleType}}<span class="card_shadow"></span></h4>
<div class="content">
<div class="content_card" v-for="(element, index) in elements.menuSubList" :key="index">
<img :src="element.imgUrl" />
<div>{{element.appName}}</div>
</div>
</div>
</div>
</div>
</div>
<div class="messge_but" @click="showPreview = false"><img class="que" src="../../assets/img/close.png" /></div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import draggable from 'vuedraggable'
import { buttonPermission } from '../../util/util';
export default {
components: {
draggable,
},
// computed: {
// ...mapGetters(['classificationList']),
// },
data() {
return {
drag: false,
classificationList: [],
moduleTypeShow: true,
dataTitle: '',
// oldData: null,
// newData: null,
oldData: {
module: null,
menuSubList: [],
},
newData: {
module: null,
menuSubList: [],
},
dataList: [
{ id:1,appName:'测试一号' },
{ id:2,appName:'测试二号' },
{ id:3,appName:'测试三号' },
{ id:4,appName:'测试四号' },
],
showPreview: false,
};
},
created() {
this.$store.commit('SET_MENU', '/classification');
this.init();
},
methods: {
init() {
this.$store.dispatch('getClassificationListAction').then(res => {
this.classificationList = res.data.menuList.map(({
module,
moduleType,
menuSubList,
}) => {
return {
module,
moduleType,
menuSubList,
moduleTypeShow: true,
}
});
}).catch(err => {
console.error(err);
});
},
//开始拖拽事件
onStart() {
this.drag = true;
},
//拖拽结束事件
onEnd() {
this.drag = false;
},
clickEdit(items, indexs) {
this.dataTitle = items.moduleType;
this.classificationList[indexs].moduleTypeShow = false;
},
clickDelete(indexs) {
this.classificationList.splice(indexs, 1);
},
clickSave(indexs) {
this.classificationList[indexs].moduleType = this.dataTitle;
this.classificationList[indexs].moduleTypeShow = true;
},
clickSaveCancel(indexs) {
if (this.dataTitle === '') {
this.classificationList.splice(indexs, 1);
} else {
this.classificationList[indexs].moduleTypeShow = true;
this.dataTitle = '';
}
},
dragStart(items, value) {
// this.oldData = value;
this.oldData.module = items.module;
this.oldData.menuSubList[0] = value;
},
dragEnter(items, value, e) {
// this.newData = value;
this.newData.module = items.module;
this.newData.menuSubList[0] = value;
e.preventDefault();
},
dragEnd(items, item, e) {
if (this.oldData !== this.newData) {
// let oldIndex = this.dataList.indexOf(this.oldData);
// let newIndex = this.dataList.indexOf(this.newData);
// let newItems = [...this.dataList];
// // 删除老的节点
// newItems.splice(oldIndex, 1);
// // 在列表中目标位置增加新的节点
// newItems.splice(newIndex, 0, this.oldData);
// this.dataList = [...newItems];
this.classificationList = [...newItems];
}
},
dragOver(e) {
e.preventDefault();
},
clickAddList() {
this.dataTitle = '';
this.classificationList.push({
moduleType: '',
menuSubList: [],
moduleTypeShow: false,
});
},
clickCancel() {
const that = this;
this.$confirm({
title: '确认取消吗?',
okText: '确认',
cancelText: '取消',
onOk() {
that.init();
},
});
},
clickPreview() {
this.showPreview = true;
},
clickRelease() {
let dataMessage = '';
this.classificationList.forEach(item => {
if (!item.moduleTypeShow) {
dataMessage = '您还未保存更改名称!'
}
})
if (dataMessage === '') {
this.$store.dispatch('giveReleaseAction', { menuList: this.classificationList }).then(res => {
if (res.resultCode === '1') {
this.$message.success('发布成功!');
} else {
this.$message.error(res.message);
}
}).catch(err => {
console.error(err);
})
} else {
debugger
this.$message.error(dataMessage);
}
},
},
};
</script>
<style lang="less" scoped>
.classification_configuration {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.85);
line-height: 14px;
.content {
.content_title{
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
line-height: 16px;
display: flex;
align-items: center;
.content_edit{
width: 120px;
display: inline-block;
}
img{
width: 18px;
height: 18px;
cursor: pointer;
}
.image_edit{
margin-left: 15px;
margin-right: 12px;
}
span{
cursor: pointer;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1890FF;
line-height: 24px;
}
}
.content_con{
margin: 8px 0 28px 0;
display: flex;
flex-wrap: wrap;
.content_card{
cursor: pointer;
width: 23.45%; //254px
height: 50px;
background: #F8F8F8;
border-radius: 2px;
line-height: 50px;
padding-left: 8px;
display: flex;
align-items: center;
margin-right: 24px;
margin-top: 12px;
.content_image{
width: 24px;
height: 23px;
margin-right: 9px;
}
}
}
}
.add_list{
cursor: pointer;
height: 32px;
// line-height: 2;
border: 1px dashed #e8e8e8;
// text-align: center;
display: flex;
justify-content: center;
align-items: center;
img{
width: 12px;
margin-right: 7px;
}
}
.content_bottom {
height: 56px;
width: calc(~"100% - 250px");
width: -moz-calc(~"100% - 250px");
width: -webkit-calc(~"100% - 250px");
background: #ffffff;
position: fixed;
bottom: 0;
box-shadow: 0px -1px 2px 0px rgba(0, 0, 0, 0.03);
filter: blur(0px);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px 0 48px;
.ant-btn-link {
color: rgba(0, 0, 0, 0.45);
}
.button_class {
margin-left: 8px;
}
}
.messge{
position: fixed;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
width: -webkit-fill-available;
height: -webkit-fill-available;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transition: .2s;
transition: .2s;
background-color: rgba(36, 36, 36, 0.5);
z-index: 999;
color: #2B333F;
line-height: 16px;
.messge_con{
position: fixed;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
width: 87%;
background-color: #FFFFFF;
border-radius: 4px;
// width: 30%;
// height: 90%;
width: 391px;
height: 667px;
overflow: auto;
.card{
padding: 16px 15px 26px 18px;
h4{
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: bold;
color: #333333;
line-height: 22px;
}
.card_shadow{
display: inline-block;
width: 36px;
height: 16px;
background: linear-gradient(180deg, #FECF00 0%, #F9BD0A 100%);
box-shadow: 0px 4px 8px 0px rgba(253, 202, 4, 0.45);
border-radius: 8px;
opacity: 0.25;
position: relative;
top: 10px;
left: -20px;
}
.content{
margin-left: 7px;
display: flex;
flex-wrap: wrap;
margin-top: 16px;
margin-bottom: 24px;
.content_card{
width: 22.1%;
margin-right: 10px;
margin-bottom: 8px;
text-align: center;
}
img{
width: 36px;
height: 36px;
}
}
}
}
.test::-webkit-scrollbar {/*滚动条整体样式*/
width: 6px;
height: 50px;
background: #595959;
// border-radius: 3px;
// opacity: 0.64;
}
.test::-webkit-scrollbar-thumb {/*滚动条整体样式*/
// width: 6px;
// height: 10px;
background: #595959;
border-radius: 3px;
}
.test::-webkit-scrollbar-track {/*滚动条里面轨道*/
background: #FFFFFF;
border-radius: 4px;
}
.messge_but{
cursor: pointer;
position: fixed;
top: 88%;
left: 50%;
.que{
width: 36px;
}
}
}
}
</style>
效果:


浙公网安备 33010602011771号