153 lines
3.9 KiB
Plaintext
153 lines
3.9 KiB
Plaintext
|
|
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 - 0.25);
|
|||
|
|
ctx.lineTo(rect.width - computedEndOffset, rect.height - 0.25);
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
}
|