摘要:但當(dāng)該元素的位置移出設(shè)置的視圖范圍時(shí),其定位效果將變成,并根據(jù)設(shè)置的等作為其定位參數(shù)。另外,筆者在網(wǎng)上找過相關(guān)的組件。面向人群急于使用組件的同學(xué)。若頁面大小發(fā)現(xiàn)變化,原顯示的位置可能與頁面變化后的不一致。
sticky簡介
sticky的本意是粘的,粘性的,使用其進(jìn)行的布局被稱為粘性布局。
sticky是position屬性新推出的值,屬于CSS3的新特性,常用與實(shí)現(xiàn)吸附效果。
設(shè)置了sticky布局的元素,在視圖窗口時(shí),與靜態(tài)布局的表現(xiàn)一致。
但當(dāng)該元素的位置移出設(shè)置的視圖范圍時(shí),其定位效果將變成fixed,并根據(jù)設(shè)置的left、top等作為其定位參數(shù)。
具體效果如下,當(dāng)頁面滾動(dòng)至下方,原本靜態(tài)布局的「演職員表」將變?yōu)閒ixed布局,固定在頁面頂部。
sticky兼容性下圖可見,除了IE以外,目前絕大部分瀏覽器都是支持sticky布局。
需求背景但是實(shí)際情況并不如上圖展示的那么美好,在360安全瀏覽器上,并不支持sticky布局,即使使用極速模式(使用chrome內(nèi)核運(yùn)行)也不支持。
另外,筆者在網(wǎng)上找過相關(guān)的vue-sticky組件。但是使用起來并不是那么順手,而且看其源碼也是一頭霧水,用著不踏實(shí)。
所以自己寫了一個(gè),希望通過本文能將組件分享出去,也希望將本組件的原理講清楚。讓其他同學(xué)在使用的時(shí)候能更踏實(shí)一些。遇到坑也知道該怎么去填。希望能幫到大家。
面向人群急于使用vue-sticky組件的同學(xué)。直接下載文件,拷貝代碼即可運(yùn)行。
喜歡看源碼,希望了解組件背后原理的同學(xué)。
其實(shí)本sticky組件原理很簡單,看完本文,相信你一定能把背后原理看懂。
剛接觸前端的同學(xué)也可以通過本文章養(yǎng)成看源碼的習(xí)慣。打破對源碼的恐懼,相信自己,其實(shí)看源碼并沒有想象中的那么困難
技術(shù)難點(diǎn)
sticky效果需要解決這么幾個(gè)問題
占位問題,sticky實(shí)現(xiàn)原理,無非是在特定超出視圖時(shí),將內(nèi)容的布局設(shè)為fixed。但將內(nèi)容設(shè)置為fixed布局時(shí),內(nèi)容將脫離文檔流,原本占據(jù)的空間將被釋放掉,這將導(dǎo)致頁面空了一塊后其他內(nèi)容發(fā)生位移。
頁面resize后位置問題。當(dāng)使用fixed定位時(shí),其定位將根據(jù)頁面進(jìn)行。若頁面大小發(fā)現(xiàn)變化,原顯示的位置可能與頁面變化后的不一致。這時(shí)需要重新設(shè)置。
橫向滾動(dòng)條問題。本質(zhì)上和resize是同一個(gè)問題,需要監(jiān)聽scroll事件,當(dāng)頁面發(fā)送無相關(guān)方向的位移時(shí),需要重新計(jì)算其位置,例如前面的sticky效果示例中設(shè)置了「演職員表」的top值,當(dāng)其fixed后,滾動(dòng)X軸,需要重新設(shè)置fixed的left參數(shù)。讓元素始終位于頁面相同位置
實(shí)現(xiàn)思路
組件有兩層容器
一個(gè)是內(nèi)容slot的容器$content
一個(gè)是內(nèi)容容器$content的sticky盒子容器$box
即包圍關(guān)系為$sticky-box($content(slot))
監(jiān)聽vue的mounted事件
這時(shí)內(nèi)容slot已經(jīng)被渲染出來
獲取slot容器$content的寬高,設(shè)置到$box容器上
設(shè)置$box容器寬高是為了當(dāng)后續(xù)$content容器Fixed后,$box容器仍在頁面中占據(jù)空間。
const style = window.getComputedStyle(this.$refs.$content) this.boxStyle.width = style.width this.boxStyle.height = style.height
監(jiān)聽scroll事件
在事件中獲取容器$content在頁面中的位置,并將其與預(yù)設(shè)值進(jìn)行大小比較,判斷$content是否應(yīng)該fixed
怎么便捷地獲取$content在頁面中的位置呢?直接使用Element.getBoundingClientRect()函數(shù),該函數(shù)將返回{left,top}分別表示dom元素距離窗口的距離。詳細(xì)可參看MDN文檔
const { $content, $box } = this.$refs const { contentStyle } = this const boxTop = $box.getBoundingClientRect().top const boxLeft = $box.getBoundingClientRect().left const contentTop = $content.getBoundingClientRect().top const contentLeft = $content.getBoundingClientRect().left
比較boxTop與預(yù)設(shè)值top的大小,當(dāng)boxTop比預(yù)設(shè)值值要小時(shí),即內(nèi)容即將移出規(guī)定的視圖范圍。這時(shí)將內(nèi)容容器$content設(shè)置為fixed。并設(shè)置其top值(即預(yù)設(shè)的top值,吸頂距離),left值與盒子位置相同,故設(shè)置為盒子距離的left值
當(dāng)boxTop比預(yù)設(shè)值值要大時(shí),即內(nèi)容重新返回的視圖范圍。則將內(nèi)容容器$content重新設(shè)置會(huì)靜態(tài)布局,讓其重新回到盒子布局內(nèi)部。由于靜態(tài)布局不受left和top的影響,所以不需要設(shè)置left和top
if (boxTop > parseInt(this.top) && this.isFixedY) { contentStyle.position = "static" } else if (boxTop < parseInt(this.topI) && !this.isFixedY) { contentStyle.position = "fixed" contentStyle.top = this.top contentStyle.left = `${boxLeft}px` }
在scroll事件中,除了Y軸方向上的滾動(dòng),還可能發(fā)生X軸方向的滾動(dòng)。這些需要重新設(shè)置fixed元素的left值,讓其與盒子容器的left值一致
// 當(dāng)位置距左位置不對時(shí),重新設(shè)置fixed對象left的值,防止左右滾動(dòng)位置不對問題 if (contentLeft !== boxLeft && this.left === "unset") { const { $box } = this.$refs const { contentStyle } = this const boxTop = $box.getBoundingClientRect().top const boxLeft = $box.getBoundingClientRect().left if (contentStyle.position === "fixed") { contentStyle.top = this.top contentStyle.left = `${boxLeft}px` } }
最后,是監(jiān)聽頁面的resize事件,防止頁面大小變化時(shí),fixed相對頁面的變化。同樣的,重新設(shè)置left值
// 當(dāng)位置距左位置不對時(shí),重新設(shè)置fixed對象left的值,防止左右滾動(dòng)位置不對問題 const { $box } = this.$refs const { contentStyle } = this const boxTop = $box.getBoundingClientRect().top const boxLeft = $box.getBoundingClientRect().left if (contentStyle.position === "fixed") { contentStyle.top = this.top === "unset" ? `${boxTop}px` : this.top contentStyle.left = this.left === "unset" ? `${boxLeft}px` : this.left }需要注意的地方
目前僅支持top與left值的多帶帶使用,暫不支持同時(shí)設(shè)置
目前僅支持px單位,暫不支持rem及百分比單位
設(shè)置內(nèi)容樣式時(shí)需要注意,設(shè)置定位相關(guān)屬性需要設(shè)置在box容器上,例如設(shè)置"displCy: inline-block;","verticCl-Clign: top;","margin"
設(shè)置外觀樣式,如背景,邊框等,則設(shè)置在slot內(nèi)容中
即內(nèi)容content-box以外的設(shè)置在box容器中,content-box以內(nèi)的樣式,則設(shè)置在slot內(nèi)容中
盒子容器不需要設(shè)置position屬性,即使有也會(huì)被沖刷掉。因?yàn)槌绦驅(qū)?nèi)部重新設(shè)置position的值
同樣的,在樣式中設(shè)置盒子容器的left和top值也是無效的,會(huì)被程序內(nèi)部重新設(shè)置。只能通過dom屬性值傳遞到組件中進(jìn)行設(shè)置
后續(xù)優(yōu)化目前本組件僅實(shí)現(xiàn)了基本功能,后續(xù)還將繼續(xù)優(yōu)化以下功能
slot內(nèi)容中,如果有圖片,如果獲取設(shè)置寬高,(監(jiān)聽所有圖片的load事件,重新設(shè)置容器的高寬)
目前僅在mounted中獲取slot的寬高,這僅僅是dom元素被渲染,但是dom內(nèi)容是否加載完畢并不知道的,如img標(biāo)簽,后續(xù)在slot中,監(jiān)聽所有img標(biāo)簽的load事件,load中,重新設(shè)置組件容器的大小
slot內(nèi)容有變化時(shí),設(shè)置容器
同樣的,當(dāng)slot內(nèi)容變化后,重新設(shè)置$content的寬高
具體如何實(shí)現(xiàn),暫時(shí)還沒有頭緒
移動(dòng)端適配
目前只測試了在PC中的效果,暫未在移動(dòng)端做測試。不排除移動(dòng)端使用存在坑
單位適配
目前只支持PX單位,未支持rem,百分百等單位
left和top值的混合使用,目前只支持單個(gè)屬性的使用,暫不支持同時(shí)設(shè)置
項(xiàng)目源碼及示例 第一稿寫完了,撒花花文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/98139.html
摘要:父子組件通信兄弟組件通信跨級(jí)組件通信父傳子子組件用接收,父組件用發(fā)送父組件紅樓夢西游記三國演義水滸傳子組件子傳父子組件用有的版本名稱只能小寫發(fā)送,父組件自定義事件然后在方法中接收父組件不能加括號(hào)子組件點(diǎn)擊把傳給父組件可以傳 父子組件通信: props、 $parent / $children、 provide / inject 、 ref 、 $attrs / $listeners ...
摘要:在前端基礎(chǔ)進(jìn)階八深入詳解函數(shù)的柯里化一文中,我有分享柯里化相關(guān)的知識(shí)。雖然說高階組件與柯里化都屬于比較難以理解的知識(shí)點(diǎn),但是他們組合在一起使用時(shí)并沒有新增更多的難點(diǎn)。 可能看過我以前文章的同學(xué)應(yīng)該會(huì)猜得到當(dāng)我用New的方法來舉例學(xué)習(xí)高階組件時(shí),接下來要分享的就是柯里化了。高階組件與函數(shù)柯里化的運(yùn)用是非常能夠提高代碼逼格的技巧,如果你有剩余的精力,完全可以花點(diǎn)時(shí)間學(xué)習(xí)一下。 在前端基礎(chǔ)進(jìn)...
摘要:前面有講到過很多頁面會(huì)在初始時(shí)驗(yàn)證登錄狀態(tài)與用戶角色。這個(gè)時(shí)候就涉及到一個(gè)高階組件的嵌套使用。而每一個(gè)高階組件函數(shù)執(zhí)行之后中所返回的組件,剛好可以作為下一個(gè)高階組件的參數(shù)繼續(xù)執(zhí)行,而并不會(huì)影響基礎(chǔ)組件中所獲得的新能力。 前面有講到過很多頁面會(huì)在初始時(shí)驗(yàn)證登錄狀態(tài)與用戶角色。我們可以使用高階組件來封裝這部分驗(yàn)證邏輯。封裝好之后我們在使用的時(shí)候就可以如下: export default w...
摘要:事先將狀態(tài)更新的規(guī)則寫好,然后將規(guī)則注入到組件中,然后狀態(tài)按照預(yù)訂的規(guī)則來進(jìn)行更新。主動(dòng)型和被動(dòng)型規(guī)則內(nèi)置了這幾種常見的規(guī)則,除了規(guī)則外,其他都是屬于主動(dòng)型更新規(guī)則,在達(dá)到一定的條件上會(huì)自動(dòng)觸發(fā)狀態(tài)更新。 Vuet.js是什么? Vuet.js是給Vue.js提供狀態(tài)管理的一個(gè)工具,與vuex不同,它是一種崇尚規(guī)則定制的狀態(tài)管理模式。事先將狀態(tài)更新的規(guī)則寫好,然后將規(guī)則注入到組件中,然...
閱讀 3680·2021-11-24 10:25
閱讀 2677·2021-11-24 09:38
閱讀 1303·2021-09-08 10:41
閱讀 3074·2021-09-01 10:42
閱讀 2726·2021-07-25 21:37
閱讀 2057·2019-08-30 15:56
閱讀 976·2019-08-30 15:55
閱讀 2814·2019-08-30 15:54