基於vue監聽滾動事件,實現錨點鏈接平滑滾動


基於vue監聽滾動事件,實現錨點鏈接平滑滾動

近日在做一個vue項目的餐飲模塊,小編需要實現一個菜單列表顯示的功能(如圖所示:左邊為菜單類別,右邊顯示相對應的菜品)

小編將此分為三個功能模塊來實現(本來一張動畫就清晰明了,小編太笨,只得口述一下):

  1. 左邊點擊類別,右邊顯示相應類別的菜品列表(平滑滾動)
  2. 滾動右邊的滾動條,左邊對應的顯示當前樣式
  3. 若從別的頁面點擊菜品進來該頁面,則該菜品為指定效果

小編也是vue的初學者,在閱讀了大量的文章后,其中借鑒 http://www.cnblogs.com/wisewrong/p/6495726.html 該文章,受到了很多啟發后,結合我們的功能加以完善。小編的和借鑒的文章側重點不同,建議大家在看之前可以先看一下上面的,以便於梳理的更清楚。

:scrollTop(滾動之根本)

在初寫項目的嘗試過程中,小編一直改變的是document.body.scrollTop的值來實現滾動,但是后來逐漸發現很邪門,有時給其賦值並沒有作用,而且過程也很麻煩,又查閱了一些資料也沒有解決辦法,所以不得已放棄。

之后無意中看到:scrollTop, 便嘗試開始使用vue中的屬性直接進行綁定滾動的變量值,功能實現反而簡單了。下面詳細講述:

一、組件html結構:

結構布局很簡單,在此多說是想給大家講述清楚一點兒右邊菜品的結構,方便綁定:scrollTop屬性,小編就踩了這個坑...

注意看注釋::scrollTop 的位置改變菜品列表的scrollTop值,來實現相應的滾動

二、實現錨鏈接平滑滾動

該功能是參考之前博主的文章的,方法基本沒改什么,簡單易懂,直接放代碼

jump(index){
                const cateItem = document.querySelectorAll('.cate-item');
                let total = cateItem[index].offsetTop;
                let distance = this.container.scrollTop // 獲取到頂部的距離(this.container便是.cate-list,為了方便存起來了)
                let step = total / 50;
                this.isActive = index; // 菜單列表顯示當前樣式
                const _this = this;
                if (total > distance) {
                	smoothDown()
                } else {
                    let newTotal = distance - total
                    step = newTotal / 50
                    smoothUp()
                }
                function smoothDown () {
                  if (distance < total) {
                    distance += step
                    _this.scrollTop = distance;
                    setTimeout(smoothDown, 10);
                  } else {
                    _this.scrollTop = total
                  }
                }
                function smoothUp () {
                  if (distance > total) {
                    distance -= step
                    _this.scrollTop = distance
                  	setTimeout(smoothUp, 10)
                  } else {
                  	_this.scrollTop = total
                  }
                } 
             }

三、監聽滾動事件,修改錨點狀態

在vue中鈎子函數監聽菜品列表(this.container)的滾動事件,

  mounted(){
            // 監聽scroll事件
            const _this = this;
            setTimeout(function(){
                _this.currentStick();    
                const rightItem = document.querySelectorAll('.cate-item');
                const catelist = document.querySelectorAll('.cate-list')[0];
                var length = rightItem.length;
                var height = rightItem[length-1].offsetHeight;
                var scrollHeight = document.querySelectorAll('.cate-menu-wrapper')[0].offsetHeight;
              // 設置最后一個類別菜品列表的高度(小於適配器高度的話與適配器等高),不然點擊錨點不能夠置頂
                if(height < scrollHeight){
                    rightItem[length-1].style.height = scrollHeight+'px';
                } 
                var arr =[];
                rightItem.forEach(function(v, i){
                    arr.push({top: v.offsetTop, height: v.offsetHeight, index: i});
                })
                _this.itemVal = arr;  
                const cateList = document.querySelectorAll('.cate-list')[0];
                cateList.addEventListener('scroll', _this.onScroll);
                _this.container = cateList;
            }, 500)
        },

這里寫的有點啰嗦了,設置setTimeout延遲是為了能夠獲取到元素(誰有好辦法快推薦給我),為了在滾動中能夠對應列表顯示錨點當前狀態,存了一個數據itemAll,存了該菜品類別區域的scrollTop,索引,高度。(啰嗦,太啰嗦了)

methods: {
   onScroll () {
                var _this = this;
                _this.itemVal.forEach(function(obj, i){
                    _this.scrollTop = _this.container.scrollTop;
                    if(_this.scrollTop >= obj.top && _this.scrollTop < (obj.top + obj.height-10)){
                      // scrollTop的移動位置要在類別的菜品列表中才顯示對應錨點的當前狀態
                        _this.isActive = obj.index;
                    }
                })
            },
}

三、點擊菜品進入頁面,該菜品置頂的聯動效果(該功能其實有隱藏性的bug,我們項目已取消該功能)

currentStick(){
                    const {dishId} = this.$route.query;
                    const cateContent = document.querySelectorAll('.cate-content');
                    const _this =  this;
                    cateContent.forEach(function(v, i){
                        if(v.id == dishId){
                            _this.scrollTop = v.offsetTop; 
                        }
                    })
            },

該功能用:scrollTop綁定的話便簡單了許多,之前用document.body.scrollTop 設置值一直沒有作用。

好了,基本上所有的代碼都帖出來了,說的應該也詳細吧(我盡力了),該方法感覺其實還是在操作dom元素和js,枉用vue。但是一時也沒有更好的辦法來實現。大家誰有更好的解決辦法的話,也歡迎來分享。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM