hairline.uts 3.9 KB
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
	
}