tab与滚动条联动

搭配vantUI,点击tab滚动到对应位置,滚动时激活对应tab,原生js,纵享丝滑~~~

<template>
  <div class="back_warp">
    <div class="letGodBaike-container" ref="scrollEl" @scroll="onScroll">
      <div class="letGodBaike-header">
        <div class="letGodBaike-header-banner" ref="banner">
          <img
            src="https://img-nos.yiyouliao.com/inforec-20220224-bd38ba5a0bb3e99b610eff52d42a417d.jpg?time=1645704280&signature=BB2E3E5E20460CA4863C2CFD02775E01"
            alt=""
          />
        </div>

        <!-- tabs -->
        <div class="letGodBaike-header-tab" ref="headerTab">
          <van-tabs
            ref="vantab"
            :class="['letGodBaike-header-fixed', fixed]"
            v-model="active"
            title-active-color="#333"
            title-inactive-color="#808080"
            color="#fff"
            @click="elToScroll"
          >
            <van-tab v-for="item in list" :key="item">
              <strong slot="title">{{ item }}</strong>
            </van-tab>
          </van-tabs>
        </div>
      </div>

      <!-- 内容 -->
      <div class="letGodBaike-list">
        <ul
          class="letGodBaike-list-ul"
          v-for="(ul, index) in list"
          :key="ul"
          :ref="'ul' + index"
        >
          <li class="letGodBaike-list-ul-title">{{ ul }}</li>
          <li class="letGodBaike-list-ul-li">
            <div
              class="letGodBaike-list-ul-li-item"
              v-for="li in cList[ul]"
              :key="li"
            >
              {{ li }}
            </div>
          </li>
        </ul>
      </div>

      <!-- 到顶部 -->
      <div v-show="fixed" class="letGodBaike-up" @click="run(0)"></div>
    </div>
  </div>
</template>

<script>
export default {
  head() {
    return {
      title: this.$route.query.title,
    }
  },
  data() {
    return {
      active: 0,
      list: [
        '新手入门',
        '任务查询',
        '地图',
        '图鉴汇总',
        '怪物图鉴',
        '情场高手',
      ],
      cList: {
        新手入门: ['入门tips1', '入门tips2', '入门tips3', '入门tips4'],
        任务查询: ['入门tips1', '入门tips2', '入门tips3', '入门tips4'],
        地图: ['入门tips1', '入门tips2', '入门tips3', '入门tips4'],
        图鉴汇总: ['入门tips1', '入门tips2', '入门tips3', '入门tips4'],
        怪物图鉴: ['入门tips1', '入门tips2', '入门tips3', '入门tips4'],
        情场高手: ['入门tips1', '入门tips2', '入门tips3', '入门tips4'],
      },
      fixed: '',
    }
  },
  mounted() {
    console.log(
      document
        .querySelectorAll('.letGodBaike-list-ul')[0]
        .getBoundingClientRect().top
    )
  },
  methods: {
    // 滚动到对应位置激活tab
    scrollToEl() {
      try {
        let tabHeight = this.$refs.vantab.tabHeight
        let domList = document.querySelectorAll('.letGodBaike-list-ul')
        let list = [...domList].filter((v, i) => {
          // 获取Ul距离屏幕顶部的距离
          let top = v.getBoundingClientRect().top

          // 当距离在tab高度误差范围内,激活tab
          if (tabHeight - 30 < top && top < tabHeight + 30) {
            this.active = i
          }
        })
      } catch (error) {
        throw error
      }
    },

    // 监听滚动事件
    onScroll({ target }) {
      this.$nextTick(() => {
        let bannerHeight = this.$refs.banner.offsetHeight

        // 当滚动距离大于banner的高度时,tabs吸顶
        if (target.scrollTop >= bannerHeight) {
          this.fixed = 'fixed'
          let tabHeight = this.$refs.vantab.tabHeight
          this.$refs.headerTab.style.minHeight = tabHeight + 'px'
          this.scrollToEl()
        } else this.fixed = ''
      })
    },

    // 点击tab滚动到对应的位置
    elToScroll(index) {
      try {
        let screenHeight = window.innerHeight
        let scrollHeight = this.$refs.scrollEl.scrollHeight
        let lastHeight = scrollHeight - screenHeight
        let ulHeight = this.$refs[`ul${index}`][0].offsetTop - 53
        // 当位置在最后一屏时,滚动距离为容器高度减去屏幕高度
        if (ulHeight > lastHeight) {
          this.run(lastHeight)
        } else {
          this.run(ulHeight)
        }
      } catch (error) {
        throw error
      }
    },

    // 滚动速度
    speedFn(time, height) {
      return height / time
    },

    // 滚动函数
    run(ulHeight) {
      // 1s执行速度
      let speed = Math.max(5, this.speedFn(1000, ulHeight))
      this.myIntval(() => {
        // 向上滚动
        if (this.$refs.scrollEl.scrollTop > ulHeight) {
          this.$refs.scrollEl.scrollTop -= speed
          if (this.$refs.scrollEl.scrollTop < ulHeight) {
            return false
          }

          // 向下滚动
        } else {
          this.$refs.scrollEl.scrollTop += speed
          if ((+this.$refs.scrollEl.scrollTop).toFixed(0) >= ulHeight) {
            return false
          }
        }
        return true
      }, 1)
    },

    // Intval
    myIntval(fn, time) {
      setTimeout(() => {
        if (fn()) {
          this.myIntval(fn, time)
        }
      }, time)
    },
  },
}
</script>

<style lang="scss" scoped>
.back_warp {
  background-color: #fff;
  height: 100%;

  .letGodBaike-container {
    background-color: #fff;
    min-height: 100%;
    height: 100%;
    color: #808080;
    overflow-y: auto;
    font-size: 14px;
    overscroll-behavior: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: constant(safe-area-inset-bottom);
    padding-bottom: env(safe-area-inset-bottom);

    .letGodBaike-header {
      // 百科banner
      .letGodBaike-header-banner {
        img {
          width: 375px;
          height: 276px;
        }
      }

      // 百科tab
      .letGodBaike-header-tab {
        .letGodBaike-header-fixed {
          &.fixed {
            position: fixed;
            top: 0;
          }
        }
      }
    }

    // 百科列表
    .letGodBaike-list {
      padding: 0 16px 276px 16px;

      .letGodBaike-list-ul {
        .letGodBaike-list-ul-title {
          width: 67px;
          padding: 3px 0;
          text-align: center;
          background: #f96e31;
          border-radius: 2px;
          font-size: 10px;
          color: #fff;
          margin-top: 18px;
          user-select: none;
        }

        .letGodBaike-list-ul-li {
          display: flex;
          flex-wrap: wrap;
          align-items: center;
          justify-content: space-between;

          .letGodBaike-list-ul-li-item {
            margin-top: 8px;
            width: 110px;
            background: #f6f8f9;
            border-radius: 2px;
            font-size: 14px;
            color: #333333;
            padding: 5px 0;
            display: flex;
            justify-content: center;
            align-items: center;
            user-select: none;

            &:active {
              background: #f2f2f2;
            }
          }
        }
      }
    }

    // 到顶
    .letGodBaike-up {
      width: 112px;
      height: 122px;
      position: fixed;
      bottom: 24px;
      right: 0px;
      background: url('~@/assets/imgs/leiGodApp/leiGodBaike_up.png') center
        center no-repeat;
    }
  }
}
</style>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容