第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

如何在只知道它的索引的情況下獲得段落內(nèi)單詞的邊界矩形?

如何在只知道它的索引的情況下獲得段落內(nèi)單詞的邊界矩形?

繁星淼淼 2024-01-11 14:16:34
我正在一個(gè) React 應(yīng)用程序中創(chuàng)建一個(gè)文本轉(zhuǎn)語(yǔ)音功能,該功能可以通過在其后面放置背景來突出顯示當(dāng)前所說的單詞。該功能與Firefox 閱讀器視圖非常相似。我實(shí)現(xiàn)的解決方案只是剪切段落字符串,并在每次渲染時(shí)在口語(yǔ)單詞周圍放置一個(gè)跨度,這使得資源占用很大并且無(wú)法制作動(dòng)畫。這是代碼:(我打算廢棄)export interface SpeakEvent {    start: number;    end: number;    type: string;}export default function TextNode({ content }: TextNodeProps) {    const [highlight, setHighlight] = useState<SpeakEvent | null>(null);    useEffect(() => {        registerText((ev) => {            if (ev?.type === 'word' || !ev)                setHighlight((old) => {                    /* Irrelevant code */                    return ev;                });        }, content);    }, [content]);    const { start, end } = highlight ?? {};    let segments = [content];    if (highlight) {        segments = [            segments[0].slice(0, start),            segments[0].slice(start, end),            segments[0].slice(end),        ];    }    return (        <>            {segments.map((seg, i) =>                i === 1 ? (                    <span key={i} className={'highlight'}>                        {seg}                    </span>                ) : (                    seg                )            )}        </>    );}Firefox 閱讀器使用更智能的方式來做到這一點(diǎn)。它使用放置在口語(yǔ)單詞后面的 div,然后將其四處移動(dòng):包含高亮效果的div直接使用絕對(duì)坐標(biāo)放置。他們?nèi)绾卧谥恢雷址饕那闆r下訪問段落內(nèi)單詞的邊界矩形?
查看完整描述

1 回答

?
慕萊塢森

TA貢獻(xiàn)1810條經(jīng)驗(yàn) 獲得超4個(gè)贊

這是以下解決方案的結(jié)果


編輯2:

正如評(píng)論中提到的,當(dāng)屏幕改變尺寸以及用戶縮放或滾動(dòng)時(shí),固定定位會(huì)導(dǎo)致問題。

要?jiǎng)?chuàng)建相對(duì)定位,可以首先獲取父元素的偏移量:const { offsetTop, offsetLeft } = containerEl.current;

然后將它們減去以獲取 DomRect :

return Array.from(range.getClientRects()).map(

? ? ({ top, left, width, height }) => ({

? ? ? ? top: top - offsetTop,

? ? ? ? left: left - offsetLeft,

? ? ? ? width,

? ? ? ? height,

? ? })

);

只需應(yīng)用于position: relative文本父級(jí),然后position: absolute應(yīng)用于文本疊加即可。


編輯:

下面的解決方案不適用于換行字(例如non-violent下圖中)

https://img1.sycdn.imooc.com/659f882d0001a30306230148.jpg

生成的框占據(jù)一個(gè)矩形,覆蓋單詞的兩個(gè)部分。

相反,使用getClientRects獲取呈現(xiàn)相同字符串的所有框,然后將其映射到相同的覆蓋層:

狀態(tài)類型:const [highlighst, setHighlights] = useState<DOMRect[] | null>(null);

在高亮設(shè)置中:return Array.from(range.getBoundingClientRect());

渲染圖:

{highlights &&

? ? highlights.map(({ top, left, width, height }) => (

? ? ? ? <span

? ? ? ? ? ? className='text-highlight'

? ? ? ? ? ? style={{

? ? ? ? ? ? ? ? top,

? ? ? ? ? ? ? ? left,

? ? ? ? ? ? ? ? width,

? ? ? ? ? ? ? ? height,

? ? ? ? ? ? }}

? ? ? ? ></span>

? ? ))}

結(jié)果 :

https://img1.sycdn.imooc.com/659f88430001e4b606250174.jpg

我最終能夠使用Range API來做到這一點(diǎn)。

setStart和方法setEnd可以接受索引變量作為第二個(gè)參數(shù)。

getBoundingClientRect然后,我獲取范圍本身使用的文本坐標(biāo),并將其放入我的狀態(tài)中。

我現(xiàn)在可以將這些值應(yīng)用到渲染中的固定 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>

? ? );

}

移動(dòng) 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;

}


查看完整回答
反對(duì) 回復(fù) 2024-01-11
  • 1 回答
  • 0 關(guān)注
  • 134 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)