使用vue 实现页面左右拖拽效果,出现了好了多点问题
问题1.自己写的第一版代码,出现了 可以console打印出来,就是视图不更新
<template>
<div id="app">
<div class="layout-container">
<div class="left-panel" ref="leftPanel">
<p>左边面板内容,可以放导航栏等元素</p>
</div>
<div class="resizer" @mousedown="startResize"></div>
<div class="right-panel" ref="rightPanel">
<p>右边面板内容,比如主体内容展示区</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ConfigFile",
data() {
return {
isResizing: false,
startX: 0,
leftWidth: 0,
rightWidth: 0
};
},
mounted() {
console.log('Component mounted successfully');
const leftPanel = this.$refs.leftPanel;
const rightPanel = this.$refs.rightPanel;
this.leftWidth = leftPanel.offsetWidth;
this.rightWidth = rightPanel.offsetWidth;
},
methods: {
startResize(event) {
event.preventDefault();
event.stopPropagation();
console.log(event, 'event')
this.isResizing = true;
this.startX = event.pageX;
document.addEventListener("mousemove", this.resize);
document.addEventListener("mouseup", this.stopResize);
},
resize(event) {
console.log('resize method called');
if (this.isResizing) {
const dx = event.pageX - this.startX;
console.log('dx value:', dx);
const leftPanel = this.$refs.leftPanel;
const rightPanel = this.$refs.rightPanel;
const newLeftWidth = this.leftWidth + dx;
const newRightWidth = this.rightWidth - dx;
console.log('newLeftWidth:', newLeftWidth, 'newRightWidth:', newRightWidth);
if (newLeftWidth >= leftPanel.offsetWidth && newRightWidth >= rightPanel.offsetWidth) {
leftPanel.style.width = newLeftWidth + "px";
rightPanel.style.width = newRightWidth + "px";
this.leftWidth = newLeftWidth;
this.rightWidth = newRightWidth;
}
}
},
stopResize() {
this.isResizing = false;
document.removeEventListener("mousemove", this.resize);
document.removeEventListener("mouseup", this.stopResize);
}
}
};
</script>
<style scoped>
.layout-container {
display: flex;
height: 100vh;
/* 占据整个视口高度 */
}
.left-panel {
flex: 1;
min-width: 200px;
/* 左边面板最小宽度 */
background-color: lightblue;
overflow: auto;
}
.resizer {
pointer-events: auto;
width: 10px;
cursor: col-resize;
/* 鼠标指针样式变成左右拉伸样式 */
background-color: gray;
/* 检查是否有透明度等影响鼠标事件的属性,若有可尝试注释掉 */
/* opacity: 0.5; */
/* 检查是否有变换相关属性,若有可尝试注释掉 */
/* transform: rotate(10deg); */
}
.right-panel {
flex: 2;
min-width: 300px;
/* 右边面板最小宽度 */
background-color: lightgreen;
overflow: auto;
}
</style>
解决问题1: 代码的逻辑看起来是正确的,但视图不更新可能是因为在调整面板宽度时没有正确设置 flex 属性。
由于使用了 flex 布局,直接通过 style.width 修改面板的宽度可能不会产生预期的效果。
为了确保视图更新并且实现左右拖拽的功能,可以将面板的宽度设置为 flex 的 flex-basis 属性。
(1)使用 flex-basis 代替 style.width:在调整面板宽度时,使用 flex-basis 来控制面板的初始宽度。
(2)更新 resize 方法:在 resize 方法中,调整 flex-basis 而不是 style.width。
更改好的第二版代码
问题2: 拖拽幅度太大,跟着鼠标拖拽;
问题3: 左右布局的宽度都有最大宽度和最小宽度,到达一定宽度就不能拖拽,需要设置最大宽度和最小宽度
<template>
<div id="app">
<div class="layout-container">
<div class="left-panel" ref="leftPanel">
<p>左边面板内容,可以放导航栏等元素</p>
</div>
<div class="resizer" @mousedown="startResize"></div>
<div class="right-panel" ref="rightPanel">
<p>右边面板内容,比如主体内容展示区</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ConfigFile",
data() {
return {
isResizing: false,
startX: 0,
leftWidth: 0,
rightWidth: 0,
};
},
mounted() {
const leftPanel = this.$refs.leftPanel;
const rightPanel = this.$refs.rightPanel;
this.leftWidth = leftPanel.offsetWidth;
this.rightWidth = rightPanel.offsetWidth;
},
methods: {
startResize(event) {
event.preventDefault();
this.isResizing = true;
this.startX = event.pageX;
document.addEventListener("mousemove", this.resize);
document.addEventListener("mouseup", this.stopResize);
},
resize(event) {
if (this.isResizing) {
const dx = event.pageX - this.startX;
const leftPanel = this.$refs.leftPanel;
const rightPanel = this.$refs.rightPanel;
const newLeftWidth = this.leftWidth + dx;
const newRightWidth = this.rightWidth - dx;
// 设置最小宽度限制
if (newLeftWidth >= 200 && newRightWidth >= 300) {
leftPanel.style.flexBasis = newLeftWidth + "px";
rightPanel.style.flexBasis = newRightWidth + "px";
this.leftWidth = newLeftWidth;
this.rightWidth = newRightWidth;
}
}
},
stopResize() {
this.isResizing = false;
document.removeEventListener("mousemove", this.resize);
document.removeEventListener("mouseup", this.stopResize);
},
},
};
</script>
<style scoped>
.layout-container {
display: flex;
height: 100vh;
}
.left-panel {
flex: 0 0 auto; /* Prevents it from growing */
min-width: 200px;
background-color: lightblue;
overflow: auto;
}
.resizer {
width: 10px;
cursor: col-resize;
background-color: gray;
}
.right-panel {
flex: 1; /* Allows it to grow */
min-width: 300px;
background-color: lightgreen;
overflow: auto;
}
</style>
解决问题2:
为了控制拖拽幅度,使其更加平滑,可以在 resize 方法中计算相对于面板的移动量,而不是直接使用鼠标的 pageX 位置。可以通过在 startResize 方法中记录鼠标的初始位置来实现。
解决问题3:
在 resize 方法中,可以添加条件来限制面板的最大和最小宽度。
下面是完整的第三版代码
<template>
<div id="app">
<div class="layout-container">
<div class="left-panel" ref="leftPanel">
<p>左边面板内容,可以放导航栏等元素</p>
</div>
<div class="resizer" @mousedown="startResize"></div>
<div class="right-panel" ref="rightPanel">
<p>右边面板内容,比如主体内容展示区</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ConfigFile",
data() {
return {
isResizing: false,
startX: 0,
leftWidth: 0,
rightWidth: 0,
};
},
mounted() {
const leftPanel = this.$refs.leftPanel;
const rightPanel = this.$refs.rightPanel;
this.leftWidth = leftPanel.offsetWidth;
this.rightWidth = rightPanel.offsetWidth;
},
methods: {
startResize(event) {
event.preventDefault();
this.isResizing = true;
this.startX = event.pageX; // 记录鼠标起始位置
document.addEventListener("mousemove", this.resize);
document.addEventListener("mouseup", this.stopResize);
},
resize(event) {
if (this.isResizing) {
const dx = event.pageX - this.startX; // 计算相对移动
const leftPanel = this.$refs.leftPanel;
const rightPanel = this.$refs.rightPanel;
const newLeftWidth = this.leftWidth + dx;
const newRightWidth = this.rightWidth - dx;
// 设置最小和最大宽度限制
const minLeftWidth = 200; // 左边面板最小宽度
const minRightWidth = 300; // 右边面板最小宽度
const maxLeftWidth = 800; // 左边面板最大宽度
const maxRightWidth = 1200; // 右边面板最大宽度
// 如果新的宽度在限制范围内,则更新
if (newLeftWidth >= minLeftWidth && newLeftWidth <= maxLeftWidth &&
newRightWidth >= minRightWidth && newRightWidth <= maxRightWidth) {
leftPanel.style.flexBasis = newLeftWidth + "px";
rightPanel.style.flexBasis = newRightWidth + "px";
this.leftWidth = newLeftWidth;
this.rightWidth = newRightWidth;
}
// 更新起始位置
this.startX = event.pageX; // 更新起始位置为当前鼠标位置
}
},
stopResize() {
this.isResizing = false;
document.removeEventListener("mousemove", this.resize);
document.removeEventListener("mouseup", this.stopResize);
},
},
};
</script>
<style scoped>
.layout-container {
display: flex;
height: 100vh;
}
.left-panel {
flex: 0 0 auto;
/* Prevents it from growing */
min-width: 200px;
max-width: 800px;
/* 左边面板最大宽度 */
background-color: lightblue;
overflow: auto;
}
.resizer {
width: 2px;
cursor: col-resize;
background-color: gray;
}
.right-panel {
flex: 1;
/* Allows it to grow */
min-width: 300px;
max-width: 1200px;
/* 右边面板最大宽度 */
background-color: lightgreen;
overflow: auto;
}
</style>
实现效果
今天又发现几个点,进行下补充:
样式可能有点不一样,大概是一致
**问题点4:**确保左侧和右侧的宽度总和为 100%。
在鼠标拖动时,左侧宽度减少时,右侧宽度增加,反之亦然。
**问题点5:**设置左右两侧的最小和最大宽度为相对的百分比。
<template>
<div id="app">
<div class="layout-container">
<div class="left-panel" ref="leftPanel" :style="{ flexBasis: leftWidth + '%' }">
<slot name="leftCon"></slot>
</div>
<div class="resizer" @mousedown="startResize"></div>
<div class="right-panel" ref="rightPanel" :style="{ flexBasis: rightWidth + '%' }">
<slot name="rightCon"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ResizablePanelLayout",
data() {
return {
isResizing: false,
startX: 0,
leftWidth: 50, // 初始左侧宽度为50%
rightWidth: 50, // 初始右侧宽度为50%
};
},
methods: {
startResize(event) {
event.preventDefault();
this.isResizing = true;
this.startX = event.pageX; // 记录鼠标起始位置
document.addEventListener("mousemove", this.resize);
document.addEventListener("mouseup", this.stopResize);
},
resize(event) {
if (this.isResizing) {
const dx = event.pageX - this.startX; // 计算相对移动
const totalWidth = 100; // 总宽度为100%
const minLeftWidth = 10; // 左边面板最小宽度为10%
const minRightWidth = 10; // 右边面板最小宽度为10%
// 计算新的宽度
let newLeftWidth = this.leftWidth + (dx / window.innerWidth) * totalWidth;
let newRightWidth = totalWidth - newLeftWidth;
// 如果新的宽度在限制范围内,则更新
if (newLeftWidth >= minLeftWidth && newRightWidth >= minRightWidth) {
this.leftWidth = newLeftWidth;
this.rightWidth = newRightWidth;
}
// 更新起始位置
this.startX = event.pageX; // 更新起始位置为当前鼠标位置
}
},
stopResize() {
this.isResizing = false;
document.removeEventListener("mousemove", this.resize);
document.removeEventListener("mouseup", this.stopResize);
},
},
};
</script>
<style scoped>
.layout-container {
display: flex;
height: 100vh;
border-radius: 2px;
}
.left-panel {
flex: 0 0 auto;
background-color: rgb(250, 250, 250);
overflow: auto;
}
.resizer {
width: 2px;
cursor: col-resize;
background-color: gray;
}
.right-panel {
flex: 1;
background-color: white;
overflow: auto;
}
</style>
解决问题4:
宽度设置:将 leftWidth 和 rightWidth 的初始值设置为 50%,并在 resize 方法中根据鼠标移动计算新的宽度。
最小宽度:设置最小宽度为 10%(可以根据需要调整)。
解决问题5:
动态宽度:使用 :style 绑定来动态设置左侧和右侧面板的宽度。