vue錨點雙向繫結
阿新 • • 發佈:2021-10-08
- 需求描述:
頭部固定吸頂,右側選單,左側長頁面,要求左側滾動右側選單對應高亮,點選右側選單,左側頁面滾動到對應位置。(這個對應位置就是模組頭部剛好在固定頭部下面)
- 需求分析:
頭部和右側可使用fixed定位,左側長頁面不限制高度。有兩件事需要處理:監聽滾動事件,實現滾動效果。
- 解決問題
// 監聽事件新增和銷燬 mounted() { document.addEventListener('scroll', this.handleScroll) }, beforeDestroy() { document.removeEventListener('scroll', this.handleScroll) } // 滾動事件 handleScroll() { // 滾動高度 const sTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop // 最大值,當頁面滾動到最大值後,下面的模組不會再向上滾動了 const max = this.sArea[8] + 10 // 滾動停止後執行函式 runLastFn(_ => { this.initSArea() if (sTop < max) { // 判讀頁面滾動對應的選單index const idx = this.findAreaIndex(sTop) if (!this.mFlag) return this.currentFloor = 'block' + idx } }) }, // 初始化不同模組(12個)滾動間距,注意每個模組都設定一個ref,每個模組滾動的距離組成一個數組,與選單對應 initSArea() { const arr = [] for (let i = 1; i < 12; i++) { const height = this.$refs[`block${i}`].offsetTop - 240 // 240 是所有模組滾動目標位置 arr.push(height > 0 ? height : 0) } this.sArea = arr this.boxScreenHeight = this.$refs.boxRef.scrollHeight }, // 滾動距離在陣列中位置,以此判讀哪個選單應該在選擇狀態 findAreaIndex(val) { const sArea = this.sArea const len = sArea.length if (val < sArea[1]) return 1 if (val > sArea[len - 1]) return len - 1 let idx = 0 let i = 0 for (i; i < len; i++) { if (sArea[i] > val) { idx = i break } } return idx } // 點選選單滾動到對應模組 gotoBlock(el, speed) { const idx = Number(el.slice(5)) const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop // 滾動條距離頂部高度 let currentTop = scrollTop // 預設滾動位置為當前滾動條位置,若改為0,則每次都會從頂部滾動到指定位置 let top = 0 // 需要滾動到的位置 if (idx < 9) { this.mFlag = true const i = idx - 1 > 0 ? idx - 1 : 0 // 有個回到頂部選單,所以第一個和第二個滾動位置一樣 top = this.sArea[i] + 1 // 模組需要滾動的位置 } else { this.mFlag = false // 頁面無需滾動了,但是選單被點選後仍要選中狀態 top = this.boxScreenHeight this.currentFloor = el setTimeout(_ => { this.mFlag = true }, 1200) } let requestId function step() { // 如果需要滾動的位置和當前位置之差小於步長speed,直接滾動到目標位置,否則按照步長滾動 if (Math.abs(currentTop - top) < speed) { window.scrollTo(0, top) } else { if (scrollTop < top) { // 如果滾動條的高度小於元素距離頂部的高度 if (currentTop <= top) { window.scrollTo(0, currentTop) requestId = window.requestAnimationFrame(step) } else { window.cancelAnimationFrame(requestId) } // 向下滾動 currentTop += speed } else { if (top <= currentTop) { window.scrollTo(0, currentTop - speed) requestId = window.requestAnimationFrame(step) } else { window.cancelAnimationFrame(requestId) } // 向上滾動 currentTop -= speed } } } window.requestAnimationFrame(step) },