vue 使用draggable拖拽实现响应式侧边栏,拖拽数据悬停在侧边栏分区超一秒时自动切换到对应分区-爱代码爱编程
封装侧边栏组件
<template>
<div>
<transition name="fade">
<div class="rightNav" v-show="show">
<div class="sidebar_draggable_right">
<div class="group_title" :data-code="areaCode" v-for="areaCode in equipmentAreaList" :key="areaCode">
{{ equipmentAreasObj[areaCode] }}
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name: 'sidebarModal',
props: {
equipmentAreaList: {
type: Array,
default: () => []
},
equipmentAreasObj: {
type: Object,
default: () => ({})
},
},
data() {
return {
show: false,
hoverStartTime: null,
hoverTime: 0,
timer: null
}
},
mounted() {
let drag = document.querySelector('.sidebar_draggable_right');
//进入元素触发
drag.ondragenter = (e) => {
//先清除hover时的样式
this.clearHoverClass()
// 判断是group_title
if (e.target.dataset.code) {
// 给放置元素添加样式
e.target.classList.add('title_hover');
}
}
//悬停触发
drag.ondragover = (e) => {
// 判断是group_title
if (e.target.dataset.code) {
if (!this.hoverStartTime) {
this.hoverStartTime = Date.now();
this.timer = setInterval(() => {
this.updateHoverTime(e.target);
}, 100);
}
}
}
//离开元素触发
drag.ondragleave = (e) => {
clearInterval(this.timer);
this.hoverStartTime = null;
this.hoverTime = 0;
}
},
methods: {
//打开sidebar
openSidebar() {
this.show = true
},
//关闭sidebar
closeSideBar() {
this.show = false
//先清除hover时的样式
this.clearHoverClass()
},
//计算拖拽切换区停留超过1s
updateHoverTime(target) {
if (this.hoverStartTime) {
this.hoverTime = (Date.now() - this.hoverStartTime) / 1000;
if (this.hoverTime > 1) {
console.log("超过1s", target.dataset.code);
this.$emit("switchTab", target.dataset.code)
}
}
},
// 清除hover时的样式
clearHoverClass() {
document.querySelectorAll('.title_hover').forEach(ele => ele.classList.remove("title_hover"));
},
}
}
</script>
<style scoped lang="less">
.rightNav {
position: fixed;
right: 5px;
top: 45%;
translate: 0 -50%;
width: 120px;
background-color: #fff;
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.2);
z-index: 1000;
border-radius: 5px;
//border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 10px;
}
.sidebar_draggable_right {
width: 100%;
}
.group_title {
font-size: 15px;
//border: 1px solid #ccc;
margin: 5px 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
height: 35px;
box-shadow: -2px 1px 5px rgba(0, 0, 0, 0.2);
}
.title_hover {
transform: translateX(-2px) scale(1.07);
color: #38b55a;
}
//过渡动画
.fade-enter-active, .fade-leave-active {
transition: all 0.3s linear;
transform: translateX(0);
}
.fade-enter, .fade-leave {
transform: translateX(100%);
}
.fade-leave-to{
transform: translateX(100%);
}
</style>
引用侧边栏组件页面
<template>
<div class="layout">
<div class="container">
<div class="left_container">
<!-- 左侧流转卡工序 -->
<draggable
class="draggable_left"
v-model="dataList"
:group="group"
:animation="300"
data-sheet="X"
filter=".forbid"
ghostClass="ghost"
dragClass="drag"
chosenClass="chosen"
@start="leftDragStart"
:move="leftDragMove"
@end="leftDragEnd"
>
<template>
<div
class="operation_card"
v-for="(operationItem, index) in dataList"
:key="operationItem.id"
>
{{operationItem.partName}}
</div>
</template>
</draggable>
</div>
<div class="right_container">
<Tabs class="right_tabs" type="card" v-model="rightTabsName">
<TabPane :label="equipmentAreasObj[areaCode]" :name="areaCode" v-for="areaCode in equipmentAreaList">
<div class="right_content">{{equipmentAreasObj[areaCode]}}</div>
</TabPane>
</Tabs>
</div>
</div>
<sidebar-modal ref="sidebarModal":equipmentAreaList="equipmentAreaList" :equipmentAreasObj="equipmentAreasObj" @switchTab="switchTab"></sidebar-modal>
</div>
</template>
<script>
import draggable from 'vuedraggable';
import sidebarModal from './components/sidebarModal'
export default {
name: "processDispatching11",
components: {
draggable,
sidebarModal
},
data() {
return {
group: 'operation',
rightTabsName: 'A01',
dataList: [
{id: '1', partName: '产品1'},
{id: '2', partName: '产品2'},
{id: '3', partName: '产品3'},
{id: '4', partName: '产品4'},
{id: '5', partName: '产品5'},
{id: '6', partName: '产品6'},
{id: '7', partName: '产品7'},
{id: '8', partName: '产品8'},
],
equipmentAreaList: ['A01', 'A02', 'A03', 'A04', 'A05', 'A06', 'A07', 'A08', 'A09', 'A091', 'A10', 'A11', 'A13', 'A14'],
equipmentAreasObj: {A01:"一区",A02: "二区", A03: "三区", A04: "3.5区", A05: "四区", A06: "五区", A07: "六区", A08: "七区", A09: "八区", A10: "磁铁封胶", A11: "后段组装", A13: "后道终检", A14: "品质部", A091: "九区", null: "其它",}, //用于存放分组名称 key代表code; value代表name
}
},
methods: {
//todo: 左侧开始拖拽事件
leftDragStart() {
//打开侧边栏
this.$refs.sidebarModal.openSidebar();
},
//todo: 左侧拖拽移动事件
leftDragMove(e) {
return true
},
//todo: 左侧拖拽结束事件
leftDragEnd(e) {
//关闭侧边栏
this.$refs.sidebarModal.closeSideBar();
return true
},
//切换
switchTab(tabCode) {
if(this.rightTabsName == tabCode) {
return
}
console.log('onDragOver', tabCode)
this.rightTabsName = tabCode
},
}
}
</script>
<style scoped lang="less">
@padding-len: 10px;
.layout {
width: 100%;
height: 100%;
background: #edeff3;
padding: @padding-len;
}
.container {
display: flex;
width: 100%;
height: 100%;
}
//拖拽样式-----------------------
.draggable_left {
min-height: 100px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.left_container {
width: 25%;
height: 100%;
background: white;
margin-right: 10px;
padding: @padding-len;
text-align:center;
}
.operation_card {
width: 60%;
height: 50px;
line-height: 42px;
border: 1px solid #dfdfdf;
padding: 4px 8px;
border-radius: 4px;
margin-bottom: 8px;
}
.right_container {
width: 75%;
height: 100%;
background: white;
padding: @padding-len;
}
.right_content {
width: 100%;
height: 800px;
font-size: 25px;
font-weight: bold;
}
</style>
演示效果
拖拽响应侧边栏,悬停切换