vue實現(xiàn)吸頂、錨點和滾動高亮按鈕效果
因公司后臺管理系統(tǒng)很多功能技術(shù)老舊,最近在用vue重構(gòu)公司的后臺管理系統(tǒng),在做商品管理添加商品這一塊,借鑒淘寶的添加商品的交互,需要實現(xiàn)一個簡單的吸頂、錨點和滾動高亮按鈕的效果。
需求
- 滾動頁面到頂部,實現(xiàn)某元素固定到頂部效果
- 點擊某個按鈕,頁面滾動到相應(yīng)的位置
- 滾動頁面,當(dāng)?shù)竭_(dá)某個位置時,高亮對應(yīng)的相關(guān)按鈕
元素吸頂實現(xiàn)方式
關(guān)于元素吸頂效果,通過查閱相關(guān)資料和相關(guān)測試,有三種方式(還有一種是jquery的方法,這里就不介紹了)
一、使用position:sticky
1. 什么是position:sticky?
粘性定位元素相當(dāng)于position:relative和position:sticky的結(jié)合體,受限于父級元素,在不同的條件下呈現(xiàn)出不同的頁面效果
2. 如何使用sticky?
sticky元素效果完全受限于父級元素,使用條件:
1.sticky元素的父元素的overflow只能設(shè)置為visible,否則會導(dǎo)致沒有粘滯效果
2.sticky元素的父元素不能設(shè)置固定的高度,否則會導(dǎo)致沒有粘滯效果
3.sticky滿足條件變成fixed定位時,與標(biāo)準(zhǔn)fixed元素不一樣,不會脫離文檔流
4.sticky 定位的元素不能添加一個只包含自身的父元素,會導(dǎo)致沒有粘滯效果
5.同一個父級元素中的sticky元素,如果定位值相等,則會重疊,如果屬于不同父級元素中,則會擠掉之前的元素,形成依次占位的效果 具體實現(xiàn)效果如下:
.sticky-box{
position: sticky;
position: -webkit-sticky;
top: 60px; //可通過js動態(tài)設(shè)置
}
3.兼容性
通過查看can i use 可以看到相關(guān)的兼容性:
可以看出這個屬性的兼容性不是那么好,如果項目需要兼容到ie11等的話,就不是那么適用了
二、使用offsetTop**
HTMLElement.offsetTop 為只讀屬性,它返回當(dāng)前元素相對于其 offsetParent 元素的頂部內(nèi)邊距的距離。因此我們需要注意的是,在監(jiān)聽頁面滾動的過程中,需要將定位父級元素的偏移量也計算在內(nèi),可以如下寫法:
//獲取當(dāng)前元素的offsetTop
getOffsetTop(obj) {
let offsetTop = 0;
while (obj != window.document.body && obj != null) {
offsetTop += obj.offsetTop;
obj = obj.offsetParent;
}
return offsetTop;
}
通過在vue的mounted生命周期函數(shù)中添加監(jiān)聽事件滾動的事件:
mounted() {
/**通過給變成固定定位的元素添加一個同等高度的父元素,防止該元素變成固定定位時,脫離文檔流導(dǎo)致的頁面抖動 */
this.tabsHeight = this.$refs.elTabs.offsetHeight;
window.addEventListener("scroll", this.handleScroll);
},
destroyed() {
//離開該頁面需要移除這個監(jiān)聽的事件
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
/**滾動事件 */
handleScroll() {
//獲取頁面滾動條的高度
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
let offsetTop = this.getOffsetTop(this.$refs.elTabs);
this.isFixed = scrollTop > offsetTop;
}
}
同時如果這種吸頂方式在項目中會多次用到,就可以封裝成組件的形式
三、使用getBoundingClientRect().top**
還有一種更為直接的方式,可以實現(xiàn)吸頂效果,就是使用getBoundingClientRect().top來獲取元素相對于視口(瀏覽器窗口)的位置,相對于offsetTop,該方法不用考慮到吸頂元素的父級元素和頁面滾動條的高度,直接對該元素進(jìn)行處理即可,實現(xiàn)如下: /* 滾動事件 / handleScroll() { / * getBoundingClientRect().top 獲取某元素距離瀏覽器頂部的高度,不包含滾動的距離 */ let tabOffsetTop = this.$refs.stickyBox.getBoundingClientRect().top; this.isFixed = tabOffsetTop < this.offsetTop }
/**滾動事件 */
handleScroll() {
/**
* getBoundingClientRect().top 獲取某元素距離瀏覽器頂部的高度,不包含滾動的距離
this.offsetTop 表示的是吸頂元素距離頂部的條件值(一般項目需求是0)
*/
let tabOffsetTop = this.$refs.stickyBox.getBoundingClientRect().top;
this.isFixed = tabOffsetTop < this.offsetTop
}
錨點定位
點擊相應(yīng)的按鈕,頁面滾動到相應(yīng)的位置,目前我知道實現(xiàn)該功能的方式有兩種:
1. 使用a標(biāo)簽定位 2. 使用js模擬錨點定位
使用a標(biāo)簽定位
這是一種常見的定位方式,它有兩種實現(xiàn)方式:
1. 通過href屬性鏈接到指定元素的id
2.另一種是添加一個 a 標(biāo)簽,再將 href 屬性鏈接到這個 a 標(biāo)簽的 name 屬性
<a href="#view1">按鈕1</a> <a href="#view2">按鈕1</a> <div id="view1">視圖1</div> <div><a name="view2">視圖2</a></div>
這種定位方式很簡單,支持任意標(biāo)簽的定位,但是a標(biāo)簽的定位會改變路由的hash,如果有相關(guān)路由會進(jìn)行路由跳轉(zhuǎn)
使用js模擬錨點定位
通過js獲取元素的scrollTop值,使其滾動到指定的位置,就能實現(xiàn)錨點定位效果,這里的tab切換選項,用到是的element-ui的el-tabs組件,具體實現(xiàn)如下:
<!-- html -->
<el-tabs v-model="activeName" type="card" @tab-click="tabClick">
<el-tab-pane :label="item.name" :name="item.key" v-for="item in tabList" :key="item.key"></el-tab-pane>
</el-tabs>
<!-- js -->
methods:{
//獲取當(dāng)前元素的offsetTop
getOffsetTop(obj) {
let offsetTop = 0;
while (obj != window.document.body && obj != null) {
offsetTop += obj.offsetTop;
obj = obj.offsetParent;
}
return offsetTop;
},
<!--錨點點擊事件-->
<!--fixedHeight 滾動的位置上方固定的高度-->
tabClick(e) {
let _this = this;
//獲取當(dāng)前選中的index以便后面滾動高亮
this.index = parseInt(e.index);
//給定一個標(biāo)識,錨點事件不觸發(fā)滾動
this.isScroll = false;
this.isChange = false;
//獲取當(dāng)前選中元素的top值(給元素綁定對應(yīng)的ref值)
let offsetTop = this.getOffsetTop(this.$refs[this.activeName]);
let scrollTop = offsetTop - this.fixedHeight;
window.scrollTo({
top: scrollTop
});
}
不得不提的一個方法就是scrollIntoView,Element.scrollIntoView() 方法讓當(dāng)前的元素滾動到瀏覽器窗口的可視區(qū)域內(nèi),同時還支持動態(tài)效果,但是不支持配置滾動到距離頂部的距離,會出現(xiàn)遮罩現(xiàn)象,但是很適合做會到頂部的功能
滾動高亮按鈕
當(dāng)用戶滾動內(nèi)容區(qū)時,高亮距離按鈕組件最近的那個元素所對應(yīng)的按鈕。 通過監(jiān)聽滾動事件,獲取當(dāng)前選中的tab的offsetTop值和當(dāng)前頁面的scrollTop值,判斷向上或者向下滾動,做出不同的處理,具體如下:
//頁面滾動要做的事情
handleScroll() {
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
this.scrollTop = scrollTop;
<!--isScroll 用于避免錨點事件觸發(fā)頁面滾動-->
if (!this.isScroll) return;
/**
* scrollTop 頁面的滾動條的高度
* offsetTop 當(dāng)前選中的tab元素的offsetTop
* offsetHeight 當(dāng)前選中元素的高度
*/
let offsetTop = this.getOffsetTop(this.$refs[this.activeName]);
let offsetHeight = this.$refs[this.activeName].offsetHeight;
let actuaTop = scrollTop + this.fixedHeight;
let length = this.tabList.length;
/**
* 頁面滾動中根據(jù)相應(yīng)位置變換選中tab
*/
if (actuaTop < offsetTop && this.index > 0) {
this.index = this.index - 1;
this.activeName = this.tabList[this.index].key;
} else if (this.index < length && actuaTop > offsetTop + offsetHeight) {
this.index = this.index + 1;
this.activeName = this.tabList[this.index].key;
}
}
性能優(yōu)化
頁面中讀取屬性會導(dǎo)致頁面reflow(下次會對導(dǎo)致頁面reflow和repaint 的操作做一個總結(jié)),過度的reflow會導(dǎo)致頁面性能下降,所以我們應(yīng)該盡量減少reflow的次數(shù),以便給用戶更好的體驗。 如果產(chǎn)品可以接受效果有延遲,就可以使用節(jié)流函數(shù)控制在一定時間內(nèi)只執(zhí)行一次函數(shù)(節(jié)流函數(shù)可以使用lodash.js 封裝好的 throttle 方法)
總結(jié)
寫到這里,需求中的三個功能都已經(jīng)實現(xiàn),也許還存在更好的方案,但是通過這次實現(xiàn)這三個需求,如果大家有其他更好的方法,歡迎留言補充,但我也從中學(xué)習(xí)到了一些東西 1.position:sticky的用法和使用條件
2.scrollTop、offsetTop等元素的相關(guān)屬性、getBoundingClientRect()用法和 scrollTo、scrollIntoView的用法 3.錨點時間和滾動高亮事件導(dǎo)致的沖突處理等
以上所述是小編給大家介紹的vue實現(xiàn)吸頂、錨點和滾動高亮按鈕效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
vue點擊Dashboard不同內(nèi)容 跳轉(zhuǎn)到同一表格的實例
這篇文章主要介紹了vue點擊Dashboard不同內(nèi)容 跳轉(zhuǎn)到同一表格的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
vue微信分享的實現(xiàn)(在當(dāng)前頁面分享其他頁面)
這篇文章主要介紹了vue微信分享,在當(dāng)前頁面分享其他頁面,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04
Vue3中SetUp函數(shù)的參數(shù)props、context詳解
我們知道setup函數(shù)是組合API的核心入口函數(shù),下面這篇文章主要給大家介紹了關(guān)于Vue3中SetUp函數(shù)的參數(shù)props、context的相關(guān)資料,需要的朋友可以參考下2021-07-07

