hairline.uts
3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert';
export type DrawBorderOptions = {
direction : 'top' | 'bottom' | 'left' | 'right';
color ?: string;
colorKey ?: string; // 在dom中获取颜色
startOffsetKey?: string; // 在dom哪个属性获取
startOffset ?: number | string; // 支持数字或 CSS 字符串(如 '10px')
endOffset ?: number | string;
lineWidth ?: number;
watchSize ?: boolean; // 是否监听尺寸变化自动重绘
immediate ?: boolean; // 是否立即绘制
bordered?: boolean;
}
export type UseDrawBorderReturn = {
color: Ref<string>,
renderBorder: () => void,
clearBorder: () => void;
dispose: () => void,
}
/**
* 在元素上绘制边框,并支持动态监听尺寸变化
* @param elementRef 目标元素的 Ref
* @param options 边框配置
* @returns 清理函数(用于卸载时取消监听)
*/
export function useDrawBorder(
elementRef : Ref<UniElement | null>,
options : DrawBorderOptions
):UseDrawBorderReturn {
let resizeObserver : UniResizeObserver | null = null;
const { watchSize = true, immediate = true } = options;
const defalutColor = '#e7e7e7'
const color = ref(options.color ?? defalutColor)
const bordered = ref(options.bordered ?? true)
let computedStartOffset = 0
let computedEndOffset = 0
// 绘制边框
const renderBorder = () => {
if (elementRef.value == null) return;
const ctx = elementRef.value!.getDrawableContext();
if (ctx == null) return;
const rect = elementRef.value!.getBoundingClientRect();
ctx.reset();
const {
direction,
startOffset = 0,
endOffset = 0,
lineWidth = 0.5,
colorKey,
startOffsetKey,
} = options;
// 转换单位(如果是字符串,如 '10px')
if(computedStartOffset == 0) {
computedStartOffset = unitConvert((startOffsetKey != null ? elementRef.value?.style.getPropertyValue(startOffsetKey!) ?? startOffset : startOffset))
}
if(computedEndOffset == 0) {
computedEndOffset = unitConvert(endOffset)
}
if(color.value == defalutColor && colorKey != null) {
color.value = elementRef.value?.style.getPropertyValue(colorKey!) ?? defalutColor
// if(color.value.length == 0) {
// color.value = defalutColor
// }
}
ctx.strokeStyle = color.value;
ctx.lineWidth = lineWidth;
// 根据方向计算坐标
switch (direction) {
case 'top':
ctx.moveTo(computedStartOffset, 0);
ctx.lineTo(rect.width - computedEndOffset, 0);
break;
case 'bottom':
ctx.moveTo(computedStartOffset, rect.height);
ctx.lineTo(rect.width - computedEndOffset, rect.height);
break;
case 'left':
ctx.moveTo(0, computedStartOffset);
ctx.lineTo(0, rect.height - computedEndOffset);
break;
case 'right':
ctx.moveTo(rect.width, computedStartOffset);
ctx.lineTo(rect.width, rect.height - computedEndOffset);
break;
}
ctx.stroke();
ctx.update();
};
const setupResizeObserver = () => {
// 监听尺寸变化(如果启用)
if (watchSize) {
if (resizeObserver == null) {
resizeObserver = new UniResizeObserver((entries : Array<UniResizeObserverEntry>) => {
if(!bordered.value) return
renderBorder();
})
}
watchEffect(()=>{
if (elementRef.value != null) {
resizeObserver!.observe(elementRef.value!);
}
})
}
}
// 清理函数(卸载时取消监听)
const dispose = () => {
if (resizeObserver != null && elementRef.value != null) {
// resizeObserver.unobserve(elementRef.value!);
resizeObserver!.disconnect();
resizeObserver = null;
}
};
const clearBorder = ()=> {
if (elementRef.value == null) return;
const ctx = elementRef.value!.getDrawableContext();
if (ctx == null) return;
bordered.value = false
ctx.reset()
ctx.update()
}
setupResizeObserver()
// 初始绘制
if(immediate) {
renderBorder();
}
return {
renderBorder, // 手动触发绘制
dispose, // 清理监听
clearBorder,
color
} as UseDrawBorderReturn
}