技术栈:vue2
一、核心功能
支持拖动调节左右两侧盒子宽度
二、布局设计
- 采用 左-中-右 三列布局设计
- 左:左侧盒子显示内容
- 中:拖动竖线(鼠标悬浮时显示)
- 右:右侧盒子显示内容
三、组件参数
- 属性 Attributes
属性名 | 说明 | 类型 | 默认值 |
---|---|---|---|
width | 宽度,单位仅支持 px 、vw | string | —— |
leftBoxWidth | 左侧盒子默认宽度,单位仅支持 px 、vw | string | —— |
max | 最大阈值,即单个盒子最大宽度占比,最大值 1 | number / string | 0.8 |
disabled | 是否禁用拖动 | boolean | false |
haveDragSize | 是否需要获取拖动距离 | boolean | false |
- 插槽 Slots
名称 | 说明 |
---|---|
leftContent | 左侧盒子显示内容 |
rightContent | 右侧盒子显示内容 |
- 方法 Events
方法名 | 说明 |
---|---|
getDragSize | 获取拖动距离,单位px;以初始化组件时竖线所在位置为原点,如拖动后竖线在原点左侧20px处,返回 -20px,在原点右侧20px处,则返回 20px,需配合haveDragSize使用 |
四、使用教程
- 引入并注册组件
<script>
import PhScreenDrag from '@/components/PhScreenDrag/Index'
export default {
name: 'test',
components: {
PhScreenDrag
}
}
</script>
- 使用
<template>
<PhScreenDrag width="40vw" leftBoxWidth="20vw">
<template slot="leftContent">
<div>111111111111111111111111111111</div>
</template>
<template slot="rightContent">
<div>222222222222222222222222222222</div>
</template>
</PhScreenDrag>
</template>
完整代码
<template>
<div
id="drag-box"
class="drag-box"
:style="`width:${width}`"
>
<div
id="left-box"
class="drag-left-box"
:style="`width:${leftBoxWidth}`">
<slot name="leftContent"></slot>
</div>
<div
id="drag-line"
:class="`drag-line ${disabled ? 'drag-line_disabled' : ''}`"
@mousedown="handleMouseDown"
@mouseup="handleMouseUp"
>
<div class="small-line"></div>
</div>
<div class="drag-right-box">
<slot name="rightContent"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'PhScreenDrag',
props: {
width: {
type: String,
default: ""
}, // 宽度
leftBoxWidth: {
type: String,
default: ""
}, // 左侧盒子宽度
max: {
type: Number | String,
default: 0.8
}, // 最大阈值
disabled: {
type: Boolean,
default: false
}, // 是否禁用
haveDragSize: {
type: Boolean,
default: false
}, // 是否需要获取拖曳距离
},
data () {
return {
lineClientX: null, // 鼠标按下时竖线距离左侧屏幕的距离
boxWidth: null, // 鼠标按下时左侧盒子宽度
}
},
methods: {
// 鼠标按下
handleMouseDown (e) {
if (this.disabled) return;
this.lineClientX = e.clientX
const width = document.getElementById("left-box").style.width
const clentWidth = document.body.clientWidth;
if (width.includes('px')) {
this.boxWidth = width.replace(new RegExp("px"), "");
} else {
let vw = width.replace(new RegExp("vw"), "");
this.boxWidth = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
}
document.addEventListener('mousemove', this.handleMouseMove, { passive: false })
document.addEventListener('mouseup', this.handleMouseUp, { passive: false })
},
// 鼠标释放
handleMouseUp () {
document.removeEventListener('mousemove', this.handleMouseMove, { passive: false })
document.removeEventListener('mouseup', this.handleMouseUp, { passive: false })
},
// 鼠标按下移动
handleMouseMove (moveEvent) {
if (!this.judgeMax(moveEvent)) return;
// 左侧盒子宽度
let boxDiv = document.getElementById("left-box")
let moveDistance; // 移动距离
if (moveEvent.clientX >= this.lineClientX) {
moveDistance = Number(moveEvent.clientX) - Number(this.lineClientX);
boxDiv.style.width = (Number(this.boxWidth) + moveDistance) + "px"
} else {
moveDistance = Number(this.lineClientX) - Number(moveEvent.clientX);
boxDiv.style.width = (Number(this.boxWidth) - moveDistance) + "px"
}
},
// 判断阈值
judgeMax (e) {
let canMove = true;
// 分别判断盒子是否
const clentWidth = document.body.clientWidth;
let width = document.getElementById("drag-box").style.width
if (width.includes('px')) {
width = width.replace(new RegExp("px"), "");
} else {
let vw = width.replace(new RegExp("vw"), "");
width = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
}
const leftBox = document.getElementById("left-box")
let leftBoxWidth = leftBox.style.width
if (leftBoxWidth.includes('px')) {
leftBoxWidth = leftBoxWidth.replace(new RegExp("px"), "");
} else {
let vw = leftBoxWidth.replace(new RegExp("vw"), "");
leftBoxWidth = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
}
const lineBox = document.getElementById("drag-line")
// 拖动范围不能超过drag-box左边框及右边框
if (this.max >= 1) {
if ((e.clientX <= leftBox.getBoundingClientRect().left) ||
((Number(width) + Number(leftBox.getBoundingClientRect().left) - 5) <= e.clientX)) {
canMove = false
}
} else {
// 单个盒子阈值
if ((Number(e.clientX) - Number(leftBox.getBoundingClientRect().left)) <= Number(width) * (1 - Number(this.max))){
canMove = false
}
if ((Number(e.clientX) - Number(leftBox.getBoundingClientRect().left)) >= Number(width) * Number(this.max)) {
canMove = false
}
}
if (this.haveDragSize) {
this.callBackDragSize(Number(e.clientX), Number(leftBox.getBoundingClientRect().left), clentWidth)
}
return canMove;
},
// 回调父组件拖动距离
callBackDragSize (lineLeft, boxLeft, clentWidth) {
let dragSize;
let leftBoxWidth = this.leftBoxWidth;
if (leftBoxWidth.includes('px')) {
leftBoxWidth = leftBoxWidth.replace(new RegExp("px"), "");
} else {
let vw = leftBoxWidth.replace(new RegExp("vw"), "");
leftBoxWidth = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
}
if ((lineLeft - boxLeft) > leftBoxWidth) {
dragSize = (lineLeft - boxLeft - leftBoxWidth) + "px"
} else {
dragSize = '-' + (leftBoxWidth - (lineLeft - boxLeft)) + "px"
}
this.$emit("getDragSize", dragSize)
}
}
}
</script>
<style lang="scss" scoped>
.drag-box{
display: flex;
background: #fff;
flex-wrap: wrap;
.drag-left-box{
overFlow: hidden;
word-break: break-all;
}
.drag-line{
width: 6px;
cursor: col-resize;
padding-left: 2px;
.small-line{
background: #fff;
width: 2px;
height: 100%;
transition: background 0.2s;
}
}
.drag-line:hover{
.small-line{
background: #409eff;
transition: background 0.2s;
}
}
.drag-line_disabled{
cursor: not-allowed;
}
.drag-line_disabled:hover{
background: #eee;
}
.drag-right-box{
overFlow: hidden;
word-break: break-all;
flex: 1;
}
}
</style>
版权声明:本文为qq_41775006原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。