Vue中实现拖拽元素改变宽高
Vue中使用自定义指令实现动态拖拽元素改变宽高
·
首先说一下自定义指令的使用
日程开发中会遇到操作 dom 元素,如果只是个别需要操作 dom 元素,可以通过 ref 获取当前 dom 元素,并对其进行操作,但是需要操作的dom比较复杂或者多的话,需要每次都去写一遍 ref 或者直接获取dom操作,所以这时候自定义指令就可以解决这个问题;
首先自定义指令分为全局的和局部的;
自定义指令有5个钩子函数:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
每个钩子函数中都有4个参数
el:指令所绑定的元素,可以用来直接操作 DOM,就是放置指令的那个元素。
binding: 一个对象,里面包含了几个属性:value:指令的绑定值,name:指令名等;
vnode:Vue 编译生成的虚拟节点。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
先简单介绍一下这次要实现的功能:就是需要在后台中实现一个自定义模板的功能,可以对每行的每个格子的宽高进行自定义拖拽和输入;下面先看一下实现后的一个效果。
下面是具体的实现代码
<template>
<div class="innerLayer">
<ul class="tem-grid-list">
<li :style="{ width: maxW / 2 + 'px', 'max-width': maxW / 2 + 'px' }">
<div
class="tem-grid-item"
v-for="(item, index) in gridData"
:key="index"
:style="{
width: item.width / 2 + 'px',
height: item.height / 2 + 'px',
'line-height': item.height / 2 + 'px',
}"
>
{{ item.navName }}
<!-- 左右拖拽条 -->
<div
v-dragAbout
:key="index"
v-if="gridData.length - 1 !== index"
class="drag-right"
:style="{ height: item.height / 2 + 'px' }"
>
<p :style="{ height: item.height / 2 + 'px' }"></p>
</div>
</div>
</li>
<!-- 底部拖拽条 -->
<li v-dragDown :style="{ width: maxW / 2 + 'px', 'max-width': maxW / 2 + 'px' }" class="drag-bottom"></li>
</ul>
</div>
</template>
export default {
name: "tem",
data() {
return {
gridData: [], // 选中行的格子数据
startY: 0, // 移动前的Y轴坐标
startX: 0, // 移动前的X轴坐标
leftDragW: null, // 拖拽宽度的时候,当前拖拽条左边元素的宽度
rightDragW: null, // 当前拖拽条右边元素的宽度
};
},
directives: {
dragDown: {
inserted(el,binding,vNode) {
el.style.cursor = 'n-resize';
const that = vNode.context;
document.addEventListener('selectstart', function (e) {
e.preventDefault(); // 阻止右键选中文本,避免在拖拽的时候不小心复制内容
})
el.onmousedown = function (e) {
that.startY = e.clientY; // 获取第一次拖动的坐标
document.onmousemove = function (e) {
let moveH = e.clientY - that.startY; // 通过移动的坐标 - 第一次拖动的坐标获取移动的距离
let lastHeight = that.dragHeight + moveH; // 初始的高度加上移动后的距离就是最终的高度
if (lastHeight <= 74 || lastHeight >= 751) return; // 设置可拖拽的最高和最低高度
that.lineHeight = lastHeight;
// 给每一项设置高度跟行高
that.gridData.forEach(item => {
item.height = lastHeight;
item.lineHeight = lastHeight;
})
}
// 最后让他的鼠标按下和移动都为null,防止继续执行
document.onmouseup = function () {
document.onmousemove = document.onmousedown = null
}
}
}
},
dragAbout: {
inserted(el,binding,vNode) {
el.style.cursor = 'e-resize';
const that = vNode.context;
document.addEventListener('selectstart', function (e) {
e.preventDefault(); //阻止默认行为
})
el.onmousedown = function (e) {
let index = vNode.key;
that.startX = e.clientX; // 获取第一次拖动的坐标
that.leftDragW = that.gridData[index].width; // 获取拖拽条的父级也就是左边的
that.rightDragW = that.gridData[index + 1].width;
document.onmousemove = function (e) {
let moveW = e.clientX - that.startX; // 通过移动的坐标 - 第一次拖动的坐标获取移动的距离
if (moveW < 0) {
if (that.leftDragW + moveW <= 74) return;
// 拖拽条左边的宽度就相当于,左边宽度加移动的距离,如果是负数,就让左边宽度+负的移动距离算出他减少了多少
that.gridData[index].width = that.leftDragW + moveW;
// 如果是负数,就让左边宽度-负的移动距离算出他增加了多少
that.gridData[index + 1].width = that.rightDragW - moveW;
} else {
if (that.rightDragW - moveW <= 74) return;
that.gridData[index].width = that.leftDragW + moveW;
that.gridData[index + 1].width = that.rightDragW - moveW;
}
}
// 最后让他的鼠标按下和移动都为null,防止继续执行
document.onmouseup = function () {
document.onmousemove = document.onmousedown = null;
}
}
}
},
},
};
<style scoped lang="less">
.tem-grid-list {
li {
display: flex;
border: 1px solid #aaa;
border-bottom: none;
position: relative;
box-sizing: border-box;
margin: 0 auto;
.tem-grid-item {
text-align: center;
position: relative;
min-height: 37.5px;
max-height: 750px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
// border-right: 1px solid red;
.drag-right {
width: 10px;
position: absolute;
top: 0;
right: -5px;
cursor: e-resize;
p {
width: 4px;
background: #aaa;
margin: 0 auto;
background: #5babff;
}
}
}
}
.drag-bottom {
width: 100%;
height: 3px;
background: #5babff;
cursor: n-resize;
}
li:nth-child(1) {
border-top: 1px solid #aaa;
}
}
</style>
PS:因为全部功能代码有点多,所以只显示中间拖拽部分的。
更多推荐
已为社区贡献3条内容
所有评论(0)