1 回答

TA貢獻1810條經驗 獲得超4個贊
這是以下解決方案的結果
編輯2:
正如評論中提到的,當屏幕改變尺寸以及用戶縮放或滾動時,固定定位會導致問題。
要創建相對定位,可以首先獲取父元素的偏移量:const { offsetTop, offsetLeft } = containerEl.current;
然后將它們減去以獲取 DomRect :
return Array.from(range.getClientRects()).map(
? ? ({ top, left, width, height }) => ({
? ? ? ? top: top - offsetTop,
? ? ? ? left: left - offsetLeft,
? ? ? ? width,
? ? ? ? height,
? ? })
);
只需應用于position: relative
文本父級,然后position: absolute
應用于文本疊加即可。
編輯:
下面的解決方案不適用于換行字(例如non-violent
下圖中)
生成的框占據一個矩形,覆蓋單詞的兩個部分。
相反,使用getClientRects
獲取呈現相同字符串的所有框,然后將其映射到相同的覆蓋層:
狀態類型:const [highlighst, setHighlights] = useState<DOMRect[] | null>(null);
在高亮設置中:return Array.from(range.getBoundingClientRect());
渲染圖:
{highlights &&
? ? highlights.map(({ top, left, width, height }) => (
? ? ? ? <span
? ? ? ? ? ? className='text-highlight'
? ? ? ? ? ? style={{
? ? ? ? ? ? ? ? top,
? ? ? ? ? ? ? ? left,
? ? ? ? ? ? ? ? width,
? ? ? ? ? ? ? ? height,
? ? ? ? ? ? }}
? ? ? ? ></span>
? ? ))}
結果 :
我最終能夠使用Range API來做到這一點。
setStart
和方法setEnd
可以接受索引變量作為第二個參數。
getBoundingClientRect
然后,我獲取范圍本身使用的文本坐標,并將其放入我的狀態中。
我現在可以將這些值應用到渲染中的固定 div 上:
const range = document.createRange();
export default function TextNode({ content, footnote }: TextNodeProps) {
? ? const [highlight, setHighlight] = useState<DOMRect | null>(null);
? ? const containerEl = useRef<HTMLSpanElement>(null);
? ? useEffect(() => {
? ? ? ? registerText((ev) => {
? ? ? ? ? ? if (!ev) {
? ? ? ? ? ? ? ? setHighlight(null);
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? if (ev.type === 'sentence') {
? ? ? ? ? ? ? ? (textEl.current as HTMLSpanElement | null)?.scrollIntoView(
? ? ? ? ? ? ? ? ? ? scrollOptions
? ? ? ? ? ? ? ? );
? ? ? ? ? ? }
? ? ? ? ? ? if (ev.type === 'word')
? ? ? ? ? ? ? ? setHighlight((old) => {
? ? ? ? ? ? ? ? ? ? const txtNode = containerEl.current?.firstChild as Node;
? ? ? ? ? ? ? ? ? ? range.setStart(txtNode, ev.start);
? ? ? ? ? ? ? ? ? ? range.setEnd(txtNode, ev.end);
? ? ? ? ? ? ? ? ? ? if (!old) {
? ? ? ? ? ? ? ? ? ? ? ? (containerEl.current as HTMLSpanElement | null)?.scrollIntoView(
? ? ? ? ? ? ? ? ? ? ? ? ? ? scrollOptions
? ? ? ? ? ? ? ? ? ? ? ? );
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? return range.getBoundingClientRect();
? ? ? ? ? ? ? ? });
? ? ? ? }, content);
? ? }, [content]);
? ? return (
? ? ? ? <span ref={containerEl}>
? ? ? ? ? ? {content}
? ? ? ? ? ? {highlight && (
? ? ? ? ? ? ? ? <div
? ? ? ? ? ? ? ? ? ? className='text-highlight'
? ? ? ? ? ? ? ? ? ? style={{
? ? ? ? ? ? ? ? ? ? ? ? top: highlight.top,
? ? ? ? ? ? ? ? ? ? ? ? left: highlight.left,
? ? ? ? ? ? ? ? ? ? ? ? width: highlight.width,
? ? ? ? ? ? ? ? ? ? ? ? height: highlight.height,
? ? ? ? ? ? ? ? ? ? }}
? ? ? ? ? ? ? ? ></div>
? ? ? ? ? ? )}
? ? ? ? </span>
? ? );
}
移動 div 的 CSS :
.text-highlight {
? ? position: fixed;
? ? border-bottom: 4px solid blue;
? ? opacity: 0.7;
? ? transition-property: top, left, height, width;
? ? transition-duration: 0.2s;
? ? transform-style: ease-in-out;
}
- 1 回答
- 0 關注
- 122 瀏覽
添加回答
舉報