1. 前言
项目开发中需要首页进行定制化,依据不同用户按照自己喜好添加模块并能够进行拖拽排序等功能,本篇是自己在项目开发前基于vuedraggable开发的一个demo。由于在vuedraggable简单的示例基础上进行修改了很多东西,在开发时踩了很多坑...太难了
2. 安装
1.npm install vuedraggable //安装
2.import draggable from 'vuedraggeable' //引入
3. 示例
1.父组件的代码
<div class="drag_demo allContainerStyle">
<div class="Flex">
<draggable
class="left"
v-model="list1"
group="taskbar"
v-bind="dragOptions"
:move="onMoveLeft"
@start="startDragLeft"
@end="endDragLeft"
@unchoose="unchooseLeft"
>
<transition-group tag="div" class="transition_div transition_div_left">
<div
ref="leftComponents"
class="drag_item drag_item_left"
v-for="item in list1"
:key="item.id"
:componentIsDrag="item.isDrag"
@mousedown="leftRemoveClass()"
>
<component
:is="item.component"
:isDrag="isDrag"
:id="item.id"
:title="item.title"
position="left"
@edit="editBtn"
@hide="hideBtn"
></component>
</div>
</transition-group>
</draggable>
<draggable
class="right"
v-model="list2"
group="taskbar"
v-bind="dragOptions"
:move="onMoveRight"
@start="startDragRight"
@end="endDragRight"
@unchoose="unchooseRight"
>
<transition-group tag="div" class="transition_div transition_div_right">
<div
ref="rightComponents"
class="drag_item drag_item_right"
v-for="item in list2"
:key="item.id"
:componentIsDrag="item.isDrag"
@mousedown="rightRemoveClass()"
>
<component
:is="item.component"
:isDrag="isDrag"
:id="item.id"
:title="item.title"
position="right"
@edit="editBtn"
@hide="hideBtn"
></component>
</div>
</transition-group>
</draggable>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
import drag1 from "@/views/monitor/components/drag1";
import drag2 from "@/views/monitor/components/drag2";
import drag3 from "@/views/monitor/components/drag3";
import drag4 from "@/views/monitor/components/drag4";
import drag5 from "@/views/monitor/components/drag5";
import drag6 from "@/views/monitor/components/drag6";
import drag7 from "@/views/monitor/components/drag7";
import drag8 from "@/views/monitor/components/drag8";
export default {
components: {
draggable,
drag1,
drag2,
drag3,
drag4,
drag5,
drag6,
drag7,
drag8,
},
data() {
return {
title: "",
dialogVisible: false,
iSMove: false, //为false时,对于不能左右移动的,显示弹窗
isDrag: false, //
dragOptions: {
animation: 120,
scroll: true,
group: "sortlist",
handle: ".allDragHeader",
ghostClass: "ghostClass", // 设置拖动元素的class的占位符的类名。
chosenClass: "chosenClass", // 设置被选中的元素的class
dragClass: "dragClass", //拖动元素的class。
},
list1: [
{
id: 1,
component: "drag1",
isDrag: true,
title: "组件一",
},
{
id: 2,
component: "drag2",
isDrag: false,
title: "组件二",
},
{
id: 3,
component: "drag3",
isDrag: true,
title: "组件三",
},
{
id: 4,
component: "drag4",
isDrag: true,
title: "组件四",
},
],
list2: [
{
id: 6,
component: "drag6",
isDrag: false,
title: "组件六",
},
{
id: 7,
component: "drag7",
isDrag: true,
title: "组件七",
},
],
};
},
methods: {
/**
* 左边---开始拖拽
* 拖拽开始时,隐藏元素的内容,显示头部
*/
startDragLeft(e) {
this.isDrag = true;
},
/**
* 左边---拖拽过程中
* 在元素拖拽过程,存在只能在上下拖拽,无法将元素拖入右边模块
*/
onMoveLeft(e, originalEvent) {
this.iSMove = true;
if (e.draggedContext.element.isDrag == true) return true;
if (e.to.classList[1] == "transition_div_left") {
return true;
} else {
this.iSMove = false;
return false;
}
},
/**
* 左边---结束拖拽
* 拖拽开始时,隐藏元素的内容,显示头部
*/
endDragLeft(e) {
if (!this.iSMove) {
this.$message.error(e.item.innerText + "此区域无法放在右侧");
return false;
}
},
/**
* 左边元素不选中时,将isdrag变成false,元素内容显示出来
*/
unchooseLeft(e) {
this.isDrag = false;
},
/**
* 移除dragClass属性
*/
leftRemoveClass() {
this.$refs.leftComponents.forEach((item) => {
console.log(item.className);
item.className = item.className.split("dragClass")[0];
});
},
/**
* 以下为右边模块元素拖拽的方法
*
* 解释同上
*/
startDragRight(e) {
this.isDrag = true;
},
onMoveRight(e, originalEvent) {
this.iSMove = true;
if (e.draggedContext.element.isDrag == true) return true;
if (e.to.classList[1] == "transition_div_right") {
return true;
} else {
this.iSMove = false;
return false;
}
},
endDragRight(e) {
if (!this.iSMove) {
this.$message.error(e.item.innerText + "此区域无法放在左侧");
return false;
}
},
unchooseRight(e) {
this.isDrag = false;
},
rightRemoveClass() {
this.$refs.rightComponents.forEach((item) => {
console.log(item.className);
item.className = item.className.split("dragClass")[0];
});
},
},
};
</script>
<style lang="scss">
.drag_demo {
padding-top: 30px;
overflow-y: auto;
}
.left {
width: 60%;
padding-right: 10px;
}
.right {
width: 40%;
padding-left: 10px;
}
.transition_div {
width: 100%;
min-height: 700px;
}
.drag_item {
.allDragHeader {
cursor: move;
}
}
.dragClass {
.allDragHeader {
background: transparent;
.allDragHeaderTitle {
color: transparent;
}
}
.allDragContent,
.allDragOperation {
display: none;
}
}
.chosenClass {}
.ghostClass {
background: red !important;
border-radius: 6px;
margin-bottom: 20px;
.allDragHeader {
background: transparent;
}
.allDragOperation {
display: none;
}
}
.allDragContainer {
margin-bottom: 20px;
overflow: hidden;
border-radius: 6px;
position: relative;
.allDragHeader {
border-top-left-radius: 6px;
border-top-right-radius: 6px;
padding: 0 20px;
line-height: 42px;
background: #308FFC;
.allDragHeaderTitle {
font-size: 16px !important;
font-weight: bold;
color: #fff;
}
}
}
.allDragContent {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
background-color: #fff;
}
}
</style>
2.在父组件中引入的子组件以drag1.vue为示例
<div class="allDragContainer qqqq">
<div class="allDragHeader">
<span class="allDragHeaderTitle">{{ title }}</span>
</div>
<div class="allDragContent" v-show="!isDrag">
<div id="ageDistribution" style="width: 100%; height: 280px"></div>
</div>
</div>
</template>
<script>
export default {
name: "drag1",
props: {
//控制元素内容的显隐
isDrag: {
type: Boolean,
},
//元素的id
id: {
type: Number,
},
//元素的在父组件中的位置,左边or右边
position: {
type: String,
},
//元素的title
title: {
type: String,
},
},
data() {
return {};
},
methods: {
edit() {
this.$emit("edit", { id: this.id, position: this.position });
},
hide() {
this.$emit("hide", { id: this.id, position: this.position });
},
},
};
</script>
4. 解决问题
1.当两个模块中存在一个为空的情况时,很难将元素拖入其中,后来又去扒文档,发现需要给transition-group设置高度即可解决此问题。
<style>
.transition_div {
width: 100%;
min-height: 700px;
}
</style>
2.在自定义元素拖拽过程中,多次反复拖拽鼠标松开后,又出现因dragClass属性导致,元素无法显示的状况,如图所示。
通过ref将元素里面在控制台打印出来,通过mousedown方法在for循环中移除该属性(不知道为什么会这些这种情况...)
//for循环移除
this.$refs.rightComponents.forEach((item) => {
console.log(item.className);
item.className = item.className.split("dragClass")[0];
});