vue实现手动标尺模块
实现思路
手动标尺模块的核心在于绘制刻度线、数字标签以及实现交互逻辑(如拖动、缩放)。Vue 的响应式特性和计算属性非常适合动态调整标尺的显示范围和样式。
基础结构设计
使用 Vue 单文件组件(SFC)组织代码,模板部分负责渲染标尺的 DOM 结构,样式部分使用 CSS 实现刻度线和标签的布局,逻辑部分处理用户交互和数据计算。
<template>
<div class="ruler-container" ref="rulerRef">
<div class="ruler" :style="rulerStyle">
<div
v-for="tick in visibleTicks"
:key="tick.value"
class="tick"
:class="{ 'major-tick': tick.isMajor }"
:style="getTickStyle(tick)">
<span v-if="tick.isMajor" class="tick-label">{{ tick.label }}</span>
</div>
</div>
</div>
</template>
刻度计算逻辑
通过计算属性动态生成可见刻度数据,根据当前缩放比例和偏移量过滤非显示区域的刻度。

export default {
props: {
scale: { type: Number, default: 1 },
offset: { type: Number, default: 0 },
width: { type: Number, default: 1000 }
},
computed: {
visibleTicks() {
const ticks = [];
const start = Math.floor(this.offset / 10) * 10;
const end = start + this.width / this.scale + 20;
for (let i = start; i <= end; i += 10) {
ticks.push({
value: i,
isMajor: i % 100 === 0,
label: i.toString()
});
}
return ticks;
},
rulerStyle() {
return {
transform: `translateX(${-this.offset}px) scaleX(${this.scale})`
};
}
},
methods: {
getTickStyle(tick) {
return {
left: `${tick.value}px`
};
}
}
}
样式实现
使用绝对定位布局刻度线,通过 CSS 区分主次刻度线样式。
.ruler-container {
position: relative;
overflow: hidden;
height: 30px;
background: #f5f5f5;
}
.ruler {
position: absolute;
height: 100%;
transform-origin: left center;
}
.tick {
position: absolute;
bottom: 0;
width: 1px;
height: 10px;
background: #999;
}
.major-tick {
height: 15px;
background: #333;
}
.tick-label {
position: absolute;
transform: translateX(-50%);
font-size: 12px;
}
交互功能扩展
添加鼠标事件处理逻辑实现拖动和缩放功能,通过 Vue 的自定义事件机制通知父组件状态变化。

export default {
data() {
return {
isDragging: false,
startX: 0,
startOffset: 0
}
},
methods: {
handleMouseDown(e) {
this.isDragging = true;
this.startX = e.clientX;
this.startOffset = this.offset;
document.addEventListener('mousemove', this.handleMouseMove);
document.addEventListener('mouseup', this.handleMouseUp);
},
handleMouseMove(e) {
if (!this.isDragging) return;
const delta = e.clientX - this.startX;
this.$emit('update:offset', this.startOffset - delta);
},
handleMouseUp() {
this.isDragging = false;
document.removeEventListener('mousemove', this.handleMouseMove);
document.removeEventListener('mouseup', this.handleMouseUp);
}
},
mounted() {
this.$refs.rulerRef.addEventListener('mousedown', this.handleMouseDown);
},
beforeDestroy() {
this.$refs.rulerRef.removeEventListener('mousedown', this.handleMouseDown);
}
}
缩放控制
添加滚轮事件监听实现缩放功能,限制缩放范围避免过度缩放。
export default {
methods: {
handleWheel(e) {
e.preventDefault();
const delta = e.deltaY > 0 ? -0.1 : 0.1;
const newScale = Math.min(Math.max(this.scale + delta, 0.1), 10);
this.$emit('update:scale', newScale);
}
},
mounted() {
this.$refs.rulerRef.addEventListener('wheel', this.handleWheel);
}
}
性能优化
对于大型标尺场景,使用虚拟滚动技术减少 DOM 节点数量,通过动态计算只渲染可见区域的刻度。
export default {
computed: {
visibleTicks() {
const ticks = [];
const start = Math.max(0, Math.floor(this.offset / 100) * 100 - 100);
const end = start + this.width / this.scale + 200;
for (let i = start; i <= end; i += 10) {
if (i < 0) continue;
ticks.push({
value: i,
isMajor: i % 100 === 0,
label: i.toString()
});
}
return ticks;
}
}
}
组件使用示例
父组件通过 v-model 管理标尺状态,实现与其他组件的联动。
<template>
<div>
<RulerComponent
v-model:offset="offset"
v-model:scale="scale"
:width="containerWidth"
/>
<!-- 其他关联组件 -->
</div>
</template>
<script>
export default {
data() {
return {
offset: 0,
scale: 1,
containerWidth: 800
}
}
}
</script>






