亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript markdown 編輯器實(shí)現(xiàn)雙屏同步滾動(dòng)

 更新時(shí)間:2022年08月11日 11:39:17   作者:譚光志  
這篇文章主要介紹了JavaScript markdown 編輯器實(shí)現(xiàn)雙屏同步滾動(dòng),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

由于一直在使用 markdown 編輯器寫技術(shù)文章,所以對于編寫體驗(yàn)很敏感。我發(fā)現(xiàn)各大社區(qū)的 markdown 編輯器基本都有同步滾動(dòng)功能。只不過有些做得好,有些做得馬馬虎虎。出于好奇,我就打算自己親自實(shí)現(xiàn)一下這個(gè)功能。

思考了一段時(shí)間,最后想出來了三種方案:

  • 百分比滾動(dòng)
  • 雙屏同時(shí)渲染占用面積大的元素
  • 每一行的元素都賦上一個(gè)索引,根據(jù)索引來精確同步每一行的滾動(dòng)高度

百分比滾動(dòng)

假設(shè)現(xiàn)在正在滾動(dòng) a 屏,那 a 屏的滾動(dòng)百分比計(jì)算方式為:a 屏的滾動(dòng)高度 / a 屏的內(nèi)容總高度,用代碼表示 a.scrollTop / a.scrollHeight。當(dāng)滾動(dòng) a 屏?xí)r,需要手動(dòng)同步 b 屏的滾動(dòng)高度,也就是根據(jù) a 屏的滾動(dòng)百分比算出 b 屏的滾動(dòng)高度:

a.onscroll = () => {
	b.scrollTo({ top: a.scrollTop / a.scrollHeight * b.scrollHeight })
}

原理就是這么簡單,可惜實(shí)現(xiàn)效果不太好。

從上面的動(dòng)圖可以看出,當(dāng)我在第二個(gè)大標(biāo)題處停留的時(shí)候,左右雙屏的內(nèi)容是同步的。但當(dāng)我滾動(dòng)到第三個(gè)大標(biāo)題時(shí),左右雙屏的內(nèi)容高度已經(jīng)差了將近 300 像素了。所以說這個(gè)方案勉勉強(qiáng)強(qiáng)能用吧,聊勝于無。

雙屏同時(shí)渲染占用面積大的元素

雙屏內(nèi)容高度不一致,是因?yàn)?markdown 同一個(gè)元素渲染后的高度和渲染前會有差別。例如一個(gè)圖片,用 markdown 寫就一行代碼的事,但渲染出來的圖片有大有小,高度幾十、幾百像素的都有。如果 markdown 的圖片代碼雙屏同時(shí)渲染,倒是能解決這個(gè)問題。

但是除了圖片仍然有不少元素渲染前后的高度是有差距的,雖然沒有圖片這么夸張。譬如 h1 h2 這種,當(dāng)文章內(nèi)容越長,這種小差異帶來的問題會越來越大,導(dǎo)致雙屏內(nèi)容高度的差距也會越來越大。所以說這種方案也不是很靠譜。

賦上一個(gè)索引

每一行的元素都賦上一個(gè)索引,根據(jù)索引來精確精確同步每一行的滾動(dòng)高度

之前兩個(gè)方案都屬于勉強(qiáng)能用,不夠好。現(xiàn)在這個(gè)第三方案就比前面兩個(gè)強(qiáng)多了,幾乎能做到精確同步每一行的內(nèi)容。具體怎么做呢?

第一步,監(jiān)聽 markdown 編輯框的內(nèi)容變化,為每一個(gè)元素賦上一個(gè)索引,空行空文本除外。

當(dāng)把編輯框的 HTML 傳給右邊的框渲染時(shí),需要把 data-index 賦值給渲染后的元素。這樣就能通過 data-index 精確定位渲染前后的同一元素了。

第二步,根據(jù) a 屏的元素滾動(dòng)高度計(jì)算 b 屏上同一索引的元素滾動(dòng)高度

在 a 屏進(jìn)行滾動(dòng)時(shí),需要從上到下遍歷 a 屏的所有元素,并且找到第一個(gè)在屏幕內(nèi)的元素。找到第一個(gè)在屏幕內(nèi)的元素 這句話的意思是因?yàn)樵跐L動(dòng)過程中,有些元素會因?yàn)闈L動(dòng)跑到屏幕外面(原來在屏幕內(nèi),滾動(dòng)到屏幕外),這些元素我們是不需要計(jì)算的。

判斷一個(gè)元素是否在屏幕內(nèi):

// dom 是否在屏幕內(nèi)
function isInScreen(dom) {
    const { top, bottom } = dom.getBoundingClientRect()
    return bottom >= 0 && top < window.innerHeight
}

除了判斷元素是否在屏幕內(nèi),還需要判斷這個(gè)元素在屏幕內(nèi)的部分占整個(gè)元素高度的百分比。譬如說一個(gè)圖片的 markdown 字符串,由于滾動(dòng)的原因,導(dǎo)致一半在屏幕內(nèi),一半在屏幕外。為了精確同步,那么渲染后的圖片也必須有一半在屏幕內(nèi)一半在屏幕外。

 計(jì)算元素在屏幕內(nèi)的百分比代碼:

// dom 在當(dāng)前屏幕展示內(nèi)容的百分比
function percentOfdomInScreen(dom) {
	// 已經(jīng)通過另一個(gè)函數(shù) isInScreen() 確定了這個(gè) dom 在屏幕內(nèi),所以只需要計(jì)算它在屏幕內(nèi)的百分比,而不需要考慮它是否在屏幕外
    const { height, bottom } = dom.getBoundingClientRect()
    if (bottom <= 0) return 0 // 不在屏幕內(nèi)
    if (bottom >= height) return 1 // 完全在屏幕內(nèi)
    return bottom / height // 部分在屏幕內(nèi)
}

現(xiàn)在我們就可以從上到下遍歷 a 屏的所有元素,找到第一個(gè)在屏幕內(nèi)的元素了:

// scrollContainer 即上面說的 a 屏,ShowContainer 是 b 屏
const nodes = Array.from(scrollContainer.children)
for (const node of nodes) {
    // 從上往下遍歷,找到第一個(gè)在屏幕內(nèi)的元素
    if (isInScreen(node) && percentOfdomInScreen(node) >= 0) {
        const index = node.dataset.index
        // 根據(jù)滾動(dòng)元素的索引,找到它在渲染框中對應(yīng)的元素
        const dom = ShowContainer.querySelector(`[data-index="${index}"]`)

		// 獲取滾動(dòng)元素在 a 屏中展示的內(nèi)容百分比
		const percent = percentOfdomInScreen(node)
		// 計(jì)算這個(gè)對等元素在 b 屏中距離容器頂部的高度
        const heightToTop = getHeightToTop(dom)
        // 根據(jù) percent 算出對等元素在 b 屏中需要隱藏的高度
        const domNeedHideHeight = dom.offsetHeight * (1 - percent)
		// scrollTo({ top: heightToTop }) 會把對等元素滾動(dòng)到在 b 屏中恰好完全展示整個(gè)元素的位置
		// 然后再滾動(dòng)它需要隱藏的高度 domNeedHideHeight,組合起來就是 scrollTo({ top: heightToTop + domNeedHideHeight })
        ShowContainer.scrollTo({ top: heightToTop + domNeedHideHeight })
        break
    }
}

從動(dòng)圖來看,目前已經(jīng)做到行內(nèi)容的精確同步了。

踩坑

有一些元素渲染后會變成嵌套元素,例如表格 table,渲染后的內(nèi)容層級為:

<table>
	<tbody>
		<tr>
			<td></td>
		</tr>
	</tbody>
</table>

按照目前的渲染邏輯,假如我寫了個(gè)表格:

|1|b|
...

那么 |1|b| 上的 data-index 會對應(yīng)到 table 上。

那這就會有個(gè) bug,當(dāng) |1|b| 滾動(dòng)到 50% 的時(shí)候,整個(gè) table 也會滾動(dòng)到 50%。

這個(gè)現(xiàn)象如下圖所示:

這和我們相要的效果不一樣。a 屏連一行的內(nèi)容都沒滾完,b 屏整個(gè)內(nèi)容已經(jīng)滾動(dòng)到一半了。

所以像這種嵌套的元素,在打 data-index 標(biāo)記時(shí),要把它打到真正的內(nèi)容上。用表格 table 來做示例,就得把 data-index 的標(biāo)記打在 tr 上。

這樣一來,同步滾動(dòng)就正常了。同理,其他的嵌套元素也一樣(譬如 ul ol)。

到此這篇關(guān)于JavaScript markdown 編輯器實(shí)現(xiàn)雙屏同步滾動(dòng)的文章就介紹到這了,更多相關(guān)JS markdown 雙屏同步滾動(dòng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論