javascript
<!-- 通用布局:左右拖拽 -->
<template>
<div :class="className">
<div class="box">
<div v-show="isExpand" ref="leftPane" :style="{ width: leftPaneWidth + 'px' }" class="pane left-pane">
<div class="el-icon-s-fold shrinkage" @click="setExpandState" />
<slot name="left" />
</div>
<div v-show="isExpand" ref="divider" class="divider" @mousedown="startDrag" />
<div v-show="!isExpand" class="el-icon-s-unfold openThe2" @click="setExpandState" />
<div class="pane right-pane">
<slot name="right" />
</div>
</div>
</div>
</template>
<script>
export default {
props: {
className: {
type: String,
default: 'boss'
},
// 左侧布局最小宽度
minLeftWidth: {
type: Number,
default: 100
},
// 左侧初始化宽度
defaultLeftWidth: {
type: [Number, String],
default: 260
},
// 右侧布局最小宽度
minRightWidth: {
type: Number,
default: 150
}
},
data() {
return {
isExpand: true, // 展开收缩state
dragging: false,
startDragX: 0,
// 添加一个变量来记录上次更新的时间戳
lastUpdate: 0,
startLeftPaneWidth: 0,
startRightPaneWidth: 0
}
},
computed: {
leftPaneWidth() {
return Math.max(this.startLeftPaneWidth, this.minLeftWidth)
},
rightPaneWidth() {
const availableWidth = this.$el.offsetWidth - this.$refs.divider.offsetWidth - this.leftPaneWidth
return Math.max(availableWidth, this.minRightWidth, 0)
}
},
watch: {
defaultLeftWidth(newVal) {
this.startLeftPaneWidth = this.calculateWidth(newVal)
}
},
mounted() {
this.initView()
},
beforeUnmount() {
document.removeEventListener('mousemove', this.handleDrag)
document.removeEventListener('mouseup', this.stopDrag)
this.$refs.divider.removeEventListener('mouseup', this.dividerMouseupBlur)
},
methods: {
initView() {
this.startLeftPaneWidth = this.calculateWidth(this.defaultLeftWidth)
this.startRightPaneWidth = this.$el.offsetWidth - this.$refs.divider.offsetWidth - this.startLeftPaneWidth
document.addEventListener('mousemove', this.handleDrag)
document.addEventListener('mouseup', this.stopDrag)
this.$refs.divider.addEventListener('mouseup', this.dividerMouseupBlur)
},
// 设置展开收缩状态
setExpandState() {
this.isExpand = !this.isExpand
},
calculateWidth(value) {
if (typeof value === 'number') {
return value
} else if (typeof value === 'string' && value.endsWith('%')) {
return (this.$el.offsetWidth * parseFloat(value)) / 100
} else {
throw new Error('Invalid defaultLeftWidth value. Please use a valid number or a percentage string (e.g., "50%" or 100).')
}
},
/**
* 开始拖拽
* @param e
*/
startDrag(e) {
this.dragging = true
this.startDragX = e.clientX
this.startLeftPaneWidth = this.$refs.leftPane.offsetWidth
this.startRightPaneWidth = this.$el.offsetWidth - this.$refs.divider.offsetWidth - this.startLeftPaneWidth
},
/**
* 拖动中
* @param e
*/
handleDrag(e) {
if (!this.dragging) return
const currentTime = performance.now()
const deltaTime = currentTime - this.lastUpdate
// 使用节流控制更新频率为8.33ms(120帧/秒)
// 使用节流控制更新频率为6.67ms(150帧/秒)
// 使用节流控制更新频率为16ms(60帧/秒)
if (deltaTime >= 8.33) {
this.lastUpdate = currentTime
// 使用requestAnimationFrame在下一帧执行更新
requestAnimationFrame(() => {
const deltaX = e.clientX - this.startDragX
const containerWidth = this.$el.offsetWidth
const newLeftPaneWidth = this.startLeftPaneWidth + deltaX
const newRightPaneWidth = this.startRightPaneWidth - deltaX
const maxLeftPaneWidth = containerWidth - this.minLeftWidth
const minRightPaneWidth = this.minRightWidth
if (newLeftPaneWidth >= this.minLeftWidth && newLeftPaneWidth <= maxLeftPaneWidth && newRightPaneWidth >= minRightPaneWidth) {
this.startLeftPaneWidth = newLeftPaneWidth
this.startRightPaneWidth = newRightPaneWidth
this.startDragX = e.clientX
}
})
}
},
/**
* 拖动结束
*/
stopDrag() {
this.dragging = false
},
/**
* 拖动完成页面失焦
*/
dividerMouseupBlur() {
document.activeElement.blur()
}
}
}
</script>
<style lang="scss" scoped>
.boss {
height: calc(100vh - 128px);
}
.box {
padding-bottom: 0 !important;
display: flex;
width: 100%;
height: 100%;
background-color: white;
.b1 {
padding: 15px;
width: 100%;
}
}
.pane {
flex-grow: 1;
overflow: hidden;
height: 100%;
position: relative;
}
.left-pane {
flex-grow: 0;
flex-shrink: 0;
}
.divider {
width: 4px;
background-color: #f2f2f2;
cursor: ew-resize;
flex-shrink: 0;
}
/* 展开收起按钮 */
.el-icon-s-fold,
.el-icon-s-unfold {
cursor: pointer;
font-size: 20px;
}
.el-icon-s-fold {
position: absolute;
top: 13px;
right: 14px;
z-index: 99;
}
.el-icon-s-unfold {
padding: 13px 4px 0;
}
</style>
使用方式:
html
// DragLeftRight是引入的左右栏组件名称
<template>
<DragLeftRight>
<template slot="left">
<div class="header">
名称
</div>
<div class="simline">
<div class="point" />
<div class="point" />
<div class="point" />
<div class="line" />
</div>
<el-scrollbar style="height: calc(100vh - 135px); overflow: hidden;" :noresize="true">
<el-tree
ref="tree"
:data="data"
:highlight-current="true"
node-key="label"
:props="defaultProps"
:default-expand-all="true"
@node-click="handleNodeClick"
/>
</el-scrollbar>
</template>
<template slot="right">
<div style="padding: 10px 2px;">
<div class="btn">
<div />
<div style="margin-left: 10px; margin-bottom: 10px;" class="expbtn">
<el-button theme="lcs" type="primary" icon="el-icon-plus" plain @click="PLAdd">新增</el-button>
</div>
</div>
<!-- 表格 -->
<div class="tableDiv">
<el-table
ref="table"
class="custom-header-table"
theme="lcs"
:data="tableDataList"
:header-cell-style="{ background: '#F5F7FA', height: '30px' }"
style="width: 100%; margin: 0 auto"
height="100%"
align="center"
row-key="node_code"
stripe
border
>
<el-table-column type="index" align="center" label="序号" />
<template>
<el-table-column
v-for="(item, index) in viewColumns"
:key="index"
:fixed="item.fixed"
:prop="item.prop"
:align="item.align"
:sortable="item.sortable"
:label="item.label"
:min-width="item.width"
:show-overflow-tooltip="true"
/>
</template>
<el-table-column
align="center"
label="操作"
width="80"
fixed="right"
>
<template slot-scope="scope">
<div>
<a class="mc" title="修改" @click="editdiaopen(scope.row)"><em class="el-icon-edit" />修改</a>
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
</DragLeftRight>
</template>
css
<style lang="scss" scoped>
.header {
line-height: 40px;
font-size: 14px;
font-weight: 700;
margin-left: 5px;
}
.simline {
overflow: hidden;
display: flex;
flex-wrap: nowrap;
// margin-top: 10px;
.point {
width: 3px;
height: 3px;
border-radius: 50%;
background: #00b4e1;
margin-right: 3px;
}
.line {
width: 100%;
height: 2px;
background: #00b4e1;
}
}
::v-deep{
.el-scrollbar__wrap{
overflow-x: hidden !important;
}
.tableDiv{
height: calc(100vh - 183px);
}
}
.pageblock{
display: flex;
justify-content: flex-end;
}
</style>