vue實現(xiàn)定位菜單

這個標(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)思路歡迎評論哦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,082評論 4 61
  • 今冬最強的冷空氣來襲,漆黑的夜里我走向了學(xué)校操場。沒想到操場上正上演一場特殊的接力賽,王燕燕老師正領(lǐng)著愛人以及妹妹...
    如果感到幸福就拍拍手閱讀 415評論 0 0
  • 如果有如果
    不吃糖的發(fā)財哥閱讀 131評論 0 0
  • 三十一號風(fēng)雨狂, 感恩親朋來捧場。 起早摸黑勤經(jīng)營。 多方建議記心房。 悉心改進今勝昔, 贏得一片贊聲揚。 恭迎天...
    跡遠留香閱讀 216評論 2 6
  • 上周末,在跟老公的交流中我知道這次不去上,下次他同樣不會同意我去上的結(jié)果后,我繼續(xù)爭取。最終我以缺半天課的等待去了...
    liangye閱讀 181評論 0 0

友情鏈接更多精彩內(nèi)容