滾動監聽
better-scroll 無法滾動的分析,直接翻到最後,看問題彙總,希望能幫助你解決。
借用一下人家這個好看的項目圖檔,做一個解釋。左邊的内容會跟右邊的内容一起關聯,點選左邊的菜單,右邊會滾動到對應菜單的内容區域;滾動右邊的内容,左邊會滾動到對應的菜單項。 就是這個簡單的左右關聯的項目。方法提供了兩個。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcukDOwYGMkdjZ4QDZhhzYwATNiFGZlRDZ2YzMxU2NkRjNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
jq的方法:
定義兩個方法:滾動的一個方法,和點選的方法。
滾動方法:
const _scrollMethod = function(){
document.addEventListener('scroll', function (e) {
e.preventDefault();
let sectionTitle = $('.icl-section-list-contents'); //擷取到list 的内容 ,下面将對這個 清單做周遊
let screenHeight = $(window).height();
let scrollTop = $(window).scrollTop();
let scrollHeight = $(document).height();
let sectionTitleHeight = $('.icl-section-list-contents').height();
sectionTitle.each(function() { // 周遊裡面的内容,抓取裡面的每個标題的位置,做下面的高度比較邏輯處理
let sectionTitleTop = $(this).offset().top - scrollTop;
if(scrollTop+sectionTitleHeight>screenHeight){
if(sectionTitleTop<(screenHeight/2)) {
var index = sectionTitle.index($(this));
$('.sectionList').find('.list-group-item').removeClass('active');
$('.sectionList').find('.list-group-item').eq(index).addClass(function (index, activeClass) {
activeClass = 'active';
// console.log($(this))
return activeClass;
});
}
}
})
// 滾到最後的内容,如果當節list 标題無法滾動到螢幕中間的位置的時候,給左邊最後一個菜單,追加class
if(scrollTop + screenHeight == scrollHeight){
$('.sectionList').find('.list-group-item').removeClass('active');
$('.sectionList').find('.list-group-item').last().addClass('active');
}
// 給第一個追加class
if ($(window).scrollTop() < 10 ){
$('.sectionList').find('.list-group-item').removeClass('active');
$('.sectionList').find('.list-group-item').eq(0).addClass('active');
}
}, false);
}
點選菜單的方法:
const _scroll =function () {
$('.sectionList .list-group-item').click(function () {
let chapterListTile = $('.list-group-item');
let _this = this;
let chapterIndex = chapterListTile.index(_this);
var _thisScroll = $('.icl-section-list-contents').eq(chapterIndex);
// jq 的animate 的動畫方法,第一個參數滾動的距離,第二個參數 滾動時間 ,第三回掉函數
$('html').animate({scrollTop:_thisScroll.offset().top - '200'}, 1000, function () {
$('.sectionList').find('.list-group-item').removeClass('active');
$(_this).addClass('active');
let sectionId = $(_this).find('.icl-section-name').attr('id');
});
})
}
上面的代碼針對具體的項目,左右分欄,css 忽略。上面的方法,在抓取對應的index的時候,判斷周遊目前的list的标題的位置,在目前螢幕的中間位置以上,才抓取index。 改進方法: 采用區間方法,周遊數組後,擷取高度累加,形成一個數組, listHeigt + = current.clinetHeight
在vue 項目的一個插件方法:
引用一個插件 better-scroll
安裝
npm install better-scroll --save
使用 (導入)
import BScroll from 'better-scroll'
這樣項目中就有了一個 BScroll 的對象。接下來就要初始化這個 BScroll 對象。
代碼如下:
mounted () { // 隻有dom 在頁面顯示完全後,bs 才能抓到高度,如果在那種tab 标簽的形式中,在display:none的情況下,無法抓取高度
this.$nextTick(() => {
this._initScroll(); // 将初始化的方法,封裝在這個方法中,下面就是對應的方法
this.calculateHeight();
})
},
_initScroll () {
this.listScroll = new BScroll(this.$refs.newsListWrapper, {})
this.contentScroll = new BScroll(this.$refs.newsContentWrapper, {
probeType: 3, // 實時位置 暴露出來
});
this.contentScroll.on('scroll', (pos) => { // 這是bs 提供的一個滾動擷取 y 值的方法,這個 y 值怎麼算的
this.scrollY = Math.abs(Math.round(pos.y));
// console.log(this.scrollY,'scrolly的值')
},
在貼上計算高度的方法:
calculateHeight () {
var contentWrapper = this.$refs.foodList; // == $('.el')
let height = 0;
this.listHeight.push(height);
for(var i=0;i<contentWrapper.length;i++) {
let item = contentWrapper[i];
height += item.clientHeight; // 獲得每個區間的高度
this.listHeight.push(height);
// console.log(this.listHeight,'listheight')
}
},
計算屬性的一個方法:
computed: {
currentIndex () {
for (let i = 0; i < this.listHeight.length; i++) {
let height1 = this.listHeight[i];
let height2 = this.listHeight[i + 1];
if (!height2 || (this.scrollY >= height1 && this.scrollY < height2)) {
return i;
}
}
return 0;
},
},
點選菜單的一個方法:
selectMenu(index) {
let foodList = this.$refs.foodList;
let el = foodList[index];
this.contentScroll.scrollToElement(el, 500); // bs 提供的滾動方法
},
這裡左右關聯的思想就是,抓取右邊元素的高度位置,然後看目前的高度在哪個高度區間,就把這個 listHeight 的索引傳回出來,用作 dom 上追加class的判斷。
在vue 執行個體的 mounted 的方法中,初始化這個 bs 對象。
順便解釋一下這的 關于vue的兩個知識點 mounted 和 $nextTick :
$nextTick : 官方api 下面說
也就是 在dom 渲染好後,再執行某個關于dom的 執行方法,比如,要取dom 上的某個資料,這裡可以用 setTimeout 替換這個 $nextTick。
mounted : 官方api 下說
也就是 el 被新建立的 vm.$el 替換,并挂載到執行個體上去之後調用該鈎子,vue的 el 挂載到 dom 上後調用 這個方法
和created的方法不一樣,created 是在 vue執行個體已經建立完成之後被調用。在這一步,執行個體已完成以下的配置:資料觀測(data observer),屬性和方法的運算, watch/event 事件回調, 但是挂載階段還沒開始,$el 屬性目前不可見。
(更多關于 vue 的筆記陸續更新中)
better-scroll 的方法注意事項。
這個插件的作者說:
網上很多同學使用過後,會有發問求助說無法滾動,這時候,不要急先把 自己初始化的bs 列印出來看看。下面是我的:
垂直方向不能滾動的主要三個屬性的 都不是正确的參數,說明,執行個體是初始化了,但是初始化後,相關的參數,它沒有擷取到,比如父級的高度和要滾動子集的高度。作者也強調了這個問題的關鍵,那麼什麼情況會導緻這個 高度沒有擷取到呢?
我遇到的一個坑:在使用tab 标簽裡初始化一個未被激活的tab 項,這個沒有被激活的項 dispaly:none ,高度無法擷取。但是在 vue執行個體 執行後,這個 bs 已經初始化了,隻不過初始化後的bs ,無法擷取相關的高度到而已。然後,我一開始就讓這個使用bs的 tab激活,然後就有了相關的 參數
然後就可以滾動了,是以總結問題呢:
遇到不能滾動的情況以下分析:
1。是否初始化了父級元素,需要滾動的子元素是否是第一個
2。列印bs 對象,檢視是否有bs對象,相關的參數(上面圖中已經畫出),是否正确
3。父子高度是否有,且子高度大于父高度 (使用小訣竅: 先不要初始化這個bs,先看父子高度是否正确,再初始化這個bs 對象,確定執行個體化之前,高度得有)
以上是我個人的一些見解,如有不妥,歡迎指出,一起交流。