這個標(biāo)題其實不怎么恰當(dāng),這個菜單的實現(xiàn)方式和vue關(guān)系不大,但是因為目前項目用的vue,所以就直接看看在vue項目里面怎么去實現(xiàn)。
[假裝這里有圖]
效果圖就不貼了,場景比較多,例如點餐的app,左側(cè)分類熱菜,涼菜,飲品...右側(cè)菜單,當(dāng)頁面滾動左側(cè)菜單跟著高亮,點擊菜單也會定位右側(cè)的內(nèi)容
梳理實現(xiàn)思路:
1、首先獲取所有的內(nèi)容和菜單
2、渲染內(nèi)容和菜單
3、獲取每一個模塊的渲染高度,從而計算菜單對應(yīng)的高度,存起來
4、監(jiān)聽頁面的滾動,判斷當(dāng)前滾動的距離高亮右側(cè)菜單
5、點擊右側(cè)菜單,獲取它對應(yīng)的高度,滾動
我們假設(shè)獲取的數(shù)據(jù)結(jié)構(gòu)如下:
[{
"menuName" : "菜單一",
"list": [{
"name": "測試一",
"desc": "描述內(nèi)容描述內(nèi)容描述內(nèi)容描述內(nèi)容描述內(nèi)容"
}]
}, {
"menuName" : "菜單二",
"list": [{
"name": "測試二",
"desc": "描述內(nèi)容描述內(nèi)容描述內(nèi)容描述內(nèi)容描述內(nèi)容"
}]
}]
上代碼:
1、首先獲取所有的內(nèi)容和菜單
data () {
return {
list: []
}
},
created () {
this.getList().then(() => {
// 這里是調(diào)用第3步
this.getRenderHeight()
// 這里是調(diào)用第4步
window.addEventListener('scroll', debounce(this.scrollCallback, 100, { 'maxWait': 500 }), false)
})
},
methods: {
getList () {
// 這里請求接口,假設(shè)data為返回的上面的數(shù)據(jù)
this.list = data
}
}
2、渲染內(nèi)容和菜單
<template lang='png'>
.wrap
.left
//- 每個菜單對應(yīng)的一個模塊
.module(v-for='(item, index) in list' :key='index' ref='area')
//- 分類標(biāo)題
h3 {{item.menuName}}
ul
//- 每一個小卡片的內(nèi)容
li(v-for='(card, i) in item' :key='i')
span {{card.name}}
span {{card.desc}}
.right
ul
li(
v-for='(item, index) in list'
ref='menuItem'
:class='{current: currentIndex === index}'
:key='index'
@click='scrollTo(index)'
) {{item.menuName}}
</template>
3、獲取每一個模塊的渲染高度,從而計算菜單對應(yīng)的高度,存起來
data () {
return {
moduleHeights: [],
currentIndex: 0 // 當(dāng)前滾動到第幾個位置
}
},
mounted () {
this.getModuleHeight()
},
methods: {
getModuleHeight () {
this.$nextTick(() => {
this.moduleHeights = []
let areas = this.$refs.area
for (let i = 0; i < areas.length; i++) {
let sum = 0
for (let j = i - 1; j >= 0; j--) {
sum += areas[j].offsetHeight
}
this.moduleHeights.push(sum)
}
})
}
}
到這里我們準(zhǔn)備的數(shù)據(jù)已經(jīng)好了!
4、監(jiān)聽頁面的滾動,判斷當(dāng)前滾動的距離高亮右側(cè)菜單
// 監(jiān)聽的調(diào)用在上面的created函數(shù)里面獲取數(shù)據(jù)之后的then方法里面(注意需要節(jié)流)
scrollCallback () {
let scrollheight = document.body.scrollTop === 0 ? document.documentElement.scrollTop : document.body.scrollTop
for (let i = 0; i < this.moduleHeights.length; i++) {
if (this.moduleHeights[i] >= scrollheight) {
this.currentIndex = i - 1 > 0 ? (i - 1) : 0
break
}
}
}
5、點擊右側(cè)菜單,獲取它對應(yīng)的高度,滾動
methods: {
scrollTo (index) {
window.scrollTo(0, this.moduleHeights[index])
}
}
到這里我們的功能就實現(xiàn)了呢,去項目里面試試吧!當(dāng)然上面的節(jié)流用到的是lodash的debounce函數(shù),如果你不想引用插件也可以自己實現(xiàn)一個簡單的節(jié)流函數(shù)
// 通過節(jié)流的方式減少請求
throttle (func, wait, mustRun) {
let timeout
let startTime = new Date()
return () => {
let args = arguments
let curTime = new Date()
clearTimeout(timeout)
// 如果達到了規(guī)定的觸發(fā)時間間隔,觸發(fā) handler
if (curTime - startTime >= mustRun) {
func.apply(this, args)
startTime = curTime
// 沒達到觸發(fā)間隔,重新設(shè)定定時器
} else {
timeout = setTimeout(func, wait)
}
}
}
好了,到這里我們就實現(xiàn)了這個效果。如果各位看官有更好的實現(xiàn)思路歡迎評論哦