import { customElement, noShadowDOM } from "solid-element"; import { createSignal, onMount, onCleanup, Show } from "solid-js"; customElement("md-pin", { x: 0, y: 0 }, (props, { element }) => { noShadowDOM(); const [position, setPosition] = createSignal<{ top: string; left: string }>({ top: "0", left: "0" }); const [visible, setVisible] = createSignal(false); const [transformStyle, setTransformStyle] = createSignal(""); let pinContainer: HTMLSpanElement | undefined; let targetImage: HTMLImageElement | undefined; let resizeObserver: ResizeObserver | undefined; // 从 element 的 textContent 获取 pin 标签内容 const label = element?.textContent?.trim() || ""; // 隐藏原始文本内容 if (element) { element.textContent = ""; } // 查找上方最近的图片 const findNearestImage = (): HTMLImageElement | null => { if (!element) return null; // 从当前元素向上查找 let current: Element | null = element; while (current) { // 在当前元素的之前兄弟节点中查找图片 let sibling: Element | null = current.previousElementSibling; while (sibling) { // 检查是否是图片元素 const img = sibling.querySelector('img'); if (img) return img; // 检查元素本身是否有图片相关的类或标签 if (sibling.tagName === 'IMG') return sibling as HTMLImageElement; sibling = sibling.previousElementSibling; } current = current.parentElement; } return null; }; // 更新 pin 位置和容器样式 const updatePosition = () => { if (!targetImage || !pinContainer) return; const imgRect = targetImage.getBoundingClientRect(); const containerRect = pinContainer.parentElement.getBoundingClientRect(); // 计算图片左上角相对于容器原始位置的偏移 const offsetX = imgRect.left - containerRect.left; const offsetY = imgRect.top - containerRect.top; // 使用 transform 将容器移动到图片位置 setTransformStyle(`translate(${offsetX}px, ${offsetY}px)`); // 计算 pin 在图片内的相对位置(x/y 是百分比) const x = typeof props.x === 'number' ? props.x : parseFloat(props.x) || 0; const y = typeof props.y === 'number' ? props.y : parseFloat(props.y) || 0; const left = (x / 100) * imgRect.width; const top = (y / 100) * imgRect.height; setPosition({ left: `${left}px`, top: `${top}px` }); }; onMount(() => { // 查找目标图片 targetImage = findNearestImage(); if (targetImage) { // 初始定位 updatePosition(); // 使用 ResizeObserver 监听图片大小变化 resizeObserver = new ResizeObserver(() => { updatePosition(); }); resizeObserver.observe(targetImage); // 延迟显示以等待位置计算完成 requestAnimationFrame(() => { setVisible(true); }); } else { console.warn('md-pin: 未找到目标图片'); } }); onCleanup(() => { if (resizeObserver && targetImage) { resizeObserver.unobserve(targetImage); } }); return (
{label || '📍'}
); });