以下是基于该指令核心逻辑扩展的3个实用案例,覆盖不同场景,附带完整代码和使用说明:
完整笔记直接主页联系,或者B站有完整视频
案例1:左右分栏联动调整(适用于编辑器、后台布局)
场景:在左右分栏布局中(如左侧菜单+右侧内容、编辑区+预览区),拖拽中间手柄同时调整两侧宽度,保持总宽度不变。
指令代码(directive/columnResize.js)
export default {
bind(el) {
// 查找左右分栏元素(需在模板中定义对应类名)
const leftDom = el.querySelector('.left-column');
const rightDom = el.querySelector('.right-column');
if (!leftDom || !rightDom) {
console.error('未找到左右分栏元素,请添加 .left-column 和 .right-column 类名');
return;
}
// 获取父容器总宽度(左右分栏总宽 = 父容器宽)
const parentWidth = el.offsetWidth;
// 创建中间拖拽手柄
const lineEl = document.createElement('div');
lineEl.style = `
width: 5px;
height: 100%;
background: #e0e0e0;
position: absolute;
left: ${leftDom.offsetWidth}px; /* 初始位置在左栏右侧 */
top: 0;
z-index: 10;
cursor: col-resize; /* 水平调整光标 */
transition: background 0.2s;
`;
// 鼠标悬停时高亮手柄
lineEl.onmouseover = () => lineEl.style.background = '#ccc';
lineEl.onmouseout = () => lineEl.style.background = '#e0e0e0';
// 绑定鼠标按下事件
lineEl.addEventListener('mousedown', (e) => {
e.preventDefault();
// 记录鼠标按下时的X坐标和左栏宽度
const startX = e.clientX;
const startLeftWidth = leftDom.offsetWidth;
// 鼠标移动时调整宽度
const handleMouseMove = (e) => {
e.preventDefault();
// 计算左栏宽度变化量(限制最小宽度为200px,最大为父容器的80%)
const deltaX = e.clientX - startX;
const newLeftWidth = Math.max(200, Math.min(parentWidth * 0.8, startLeftWidth + deltaX));
const newRightWidth = parentWidth - newLeftWidth;
// 更新左右分栏宽度和手柄位置
leftDom.style.width = `${newLeftWidth}px`;
rightDom.style.width = `${newRightWidth}px`;
lineEl.style.left = `${newLeftWidth}px`;
};
// 鼠标松开时移除事件
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
// 绑定全局事件(确保拖拽不中断)
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}, false);
// 将手柄添加到父容器
el.appendChild(lineEl);
}
};
使用示例(ColumnDemo.vue)
<template>
<!-- 父容器:相对定位,包含左右分栏 -->
<div class="column-container" v-columnResize>
<!-- 左分栏 -->
<div class="left-column">
<h3>左侧菜单</h3>
<p>拖拽中间手柄可调整宽度</p>
</div>
<!-- 右分栏 -->
<div class="right-column">
<h3>右侧内容区</h3>
<p>总宽度固定,左侧变宽时右侧自动变窄</p>
</div>
</div>
</template>
<style scoped>
.column-container {
position: relative;
width: 1000px;
height: 500px;
margin: 20px auto;
border: 1px solid #ccc;
}
.left-column {
float: left;
width: 300px; /* 初始宽度 */
height: 100%;
background: #f5f5f5;
box-sizing: border-box;
padding: 20px;
}
.right-column {
float: left;
width: 700px; /* 初始宽度 = 总宽 - 左栏宽 */
height: 100%;
background: #fff;
box-sizing: border-box;
padding: 20px;
}
</style>
<script>
import columnResize from '@/directive/columnResize.js';
export default {
directives: {
columnResize // 局部注册指令
}
};
</script>
效果:拖拽中间灰色手柄,左侧宽度增加时右侧自动减少,且两侧宽度不会小于200px或超过总宽的80%。
案例2:表格容器高度调整(解决表格内容过多问题)
场景:表格数据过多时,用户可拖拽表格底部手柄调整容器高度,避免频繁滚动。
指令代码(directive/tableHeightResize.js)
export default {
bind(el) {
// 查找表格容器(需在模板中定义 .table-container 类名)
const tableContainer = el.querySelector('.table-container');
if (!tableContainer) {
console.error('未找到表格容器,请添加 .table-container 类名');
return;
}
// 创建底部拖拽手柄
const lineEl = document.createElement('div');
lineEl.style = `
height: 5px;
width: 100%;
background: #f0f0f0;
position: absolute;
bottom: 0;
left: 0;
cursor: s-resize; /* 垂直调整光标 */
`;
// 鼠标悬停时显示深色提示
lineEl.onmouseover = () => lineEl.style.background = '#e0e0e0';
lineEl.onmouseout = () => lineEl.style.background = '#f0f0f0';
// 绑定鼠标按下事件
lineEl.addEventListener('mousedown', (e) => {
e.preventDefault();
// 记录鼠标按下时的Y坐标和容器当前高度
const startY = e.clientY;
const startHeight = tableContainer.offsetHeight;
// 鼠标移动时调整高度
const handleMouseMove = (e) => {
e.preventDefault();
// 计算高度变化量(限制最小高度300px,最大800px)
const deltaY = e.clientY - startY;
const newHeight = Math.max(300, Math.min(800, startHeight + deltaY));
tableContainer.style.height = `${newHeight}px`;
};
// 鼠标松开时移除事件
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
// 绑定全局事件
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}, false);
// 将手柄添加到表格容器(容器需设为相对定位)
tableContainer.appendChild(lineEl);
}
};
使用示例(TableDemo.vue)
<template>
<div class="table-page">
<h3>可调整高度的表格</h3>
<!-- 表格容器:相对定位,溢出时显示滚动条 -->
<div class="table-container" v-tableHeightResize>
<table border="1" width="100%" cellpadding="10">
<thead>
<tr><th>ID</th><th>名称</th><th>状态</th></tr>
</thead>
<tbody>
<!-- 模拟100行数据 -->
<tr v-for="i in 100" :key="i">
<td>{{ i }}</td>
<td>数据项 {{ i }}</td>
<td>正常</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<style scoped>
.table-page {
width: 800px;
margin: 20px auto;
}
.table-container {
position: relative; /* 确保手柄绝对定位生效 */
height: 400px; /* 初始高度 */
overflow: auto; /* 内容超出时显示滚动条 */
border: 1px solid #ddd;
}
</style>
<script>
import tableHeightResize from '@/directive/tableHeightResize.js';
export default {
directives: {
tableHeightResize
}
};
</script>
效果:拖拽表格底部灰色手柄,可上下调整容器高度(300px~800px),内容超出时自动显示滚动条。
案例3:图片透明度调整(可视化交互)
场景:图片预览页面中,用户可通过拖拽滑块直观调整图片透明度。
指令代码(directive/imgOpacityResize.js)
export default {
bind(el) {
// 查找图片和控制区(需在模板中定义对应类名)
const imgDom = el.querySelector('.target-img');
const controlDom = el.querySelector('.opacity-controls');
if (!imgDom || !controlDom) {
console.error('未找到图片或控制区,请添加 .target-img 和 .opacity-controls 类名');
return;
}
// 创建透明度滑块容器
const sliderContainer = document.createElement('div');
sliderContainer.style = `
width: 200px;
height: 6px;
background: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,1));
margin: 10px 0;
position: relative;
border-radius: 3px;
`;
// 创建滑块按钮
const sliderBtn = document.createElement('div');
sliderBtn.style = `
width: 16px;
height: 16px;
background: #409eff;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%; /* 初始在中间(透明度0.5) */
transform: translate(-50%, -50%);
box-shadow: 0 0 3px rgba(0,0,0,0.3);
cursor: pointer;
`;
sliderContainer.appendChild(sliderBtn);
// 显示当前透明度值
const valueText = document.createElement('span');
valueText.style = 'margin-left: 10px; color: #666;';
valueText.textContent = '透明度:50%';
// 组合控制区
controlDom.appendChild(sliderContainer);
controlDom.appendChild(valueText);
// 绑定鼠标按下事件
sliderBtn.addEventListener('mousedown', (e) => {
e.preventDefault();
const sliderWidth = sliderContainer.offsetWidth;
const btnWidth = sliderBtn.offsetWidth;
// 计算滑块可移动的最大范围(容器宽 - 按钮宽)
const maxLeft = sliderWidth - btnWidth;
// 鼠标移动时调整滑块位置和透明度
const handleMouseMove = (e) => {
e.preventDefault();
// 计算滑块相对容器的left值(限制在0~maxLeft之间)
const sliderRect = sliderContainer.getBoundingClientRect();
let left = e.clientX - sliderRect.left - btnWidth / 2;
left = Math.max(0, Math.min(maxLeft, left));
// 更新滑块位置
sliderBtn.style.left = `${left}px`;
// 计算透明度(0~1)并应用到图片
const opacity = left / maxLeft;
imgDom.style.opacity = opacity;
// 更新显示文本
valueText.textContent = `透明度:${Math.round(opacity * 100)}%`;
};
// 鼠标松开时移除事件
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
// 绑定全局事件
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}, false);
}
};
使用示例(ImageDemo.vue)
<template>
<div class="image-container" v-imgOpacityResize>
<h3>图片透明度调整</h3>
<!-- 图片元素 -->
<img
class="target-img"
src="https://picsum.photos/800/400"
alt="示例图片"
>
<!-- 控制区(滑块会被插入到这里) -->
<div class="opacity-controls">
<p>拖动滑块调整透明度:</p>
</div>
</div>
</template>
<style scoped>
.image-container {
width: 800px;
margin: 20px auto;
text-align: center;
}
.target-img {
max-width: 100%;
border: 1px solid #eee;
opacity: 0.5; /* 初始透明度 */
}
.opacity-controls {
margin-top: 20px;
}
</style>
<script>
import imgOpacityResize from '@/directive/imgOpacityResize.js';
export default {
directives: {
imgOpacityResize
}
};
</script>
效果:拖拽滑块时,图片透明度随滑块位置变化(左→右:透明→不透明),同时显示当前透明度百分比。
扩展逻辑总结
这三个案例均基于原指令的核心逻辑(手柄+鼠标事件+样式修改),通过以下调整实现不同功能:
- 手柄位置/样式:从弹窗右侧→分栏中间→表格底部→图片控制区,样式适配场景(垂直条→水平条→滑块)。
- 目标元素:从弹窗→分栏容器→表格容器→图片,只要能通过类名查找即可扩展。
- 修改的样式属性:从
width→width(联动)→height→opacity,覆盖尺寸和非尺寸调整。
根据实际需求,还可进一步扩展(如调整字体大小、边框粗细等),核心是保持“用户交互→事件监听→样式更新”的逻辑链。