专栏首页solate 杂货铺vue css 滚动楼层导航定位

vue css 滚动楼层导航定位

理解滚动图

左右结构

<template>
  <div>
    <div class="floor-nav">
      <ul class="nav-list">
        <li
            class="nav-list-item"
            v-for="(item, index) in floorList"
            :key="item.id"
            @click="setFloorNavMountClick(index)"
        >{{ item.name }}</li>
      </ul>
    </div>
    <div class="wrap-body">
      <div
          class="floor-item"
          v-for="item in floorList"
          :key="item.id">
        <div class="floor-item-box">
          <h3>{{ item.name }}</h3>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'IFloor',
  data () {
    return {
      element: {
        nav_item: null,
        floor_item: null
      },
      timer: null,
      floorList: [
        { id: 1, name: 'F1' },
        { id: 2, name: 'F2' },
        { id: 3, name: 'F3' },
        { id: 4, name: 'F4' },
        { id: 5, name: 'F5' },
        { id: 6, name: 'F6' }
      ],
      navItemIndex: 0,
    }
  },
  mounted () {
    this.element = {
      nav_item: document.getElementsByClassName('nav-list-item'),
      floor_item: document.getElementsByClassName('floor-item')
    }
    this.element.nav_item[0].classList.add('active')
    // window.addEventListener('scroll', this.floorSrcollEventListener)
  },
  beforeDestroy () {
    // window.removeEventListener('scroll', this.floorSrcollEventListener)
  },
  methods: {
    /**
     * 根据下标改变菜单样式
     * @param {Number} index  楼层下标
     */
    changeNavClass(index) {
      this.element.nav_item[this.navItemIndex].classList.remove('active');
      this.element.nav_item[index].classList.remove('active');
      this.navItemIndex = index;
    },

    /**
     * 设置楼层导航事件驱动方法
     * @param {Number} index  楼层下标
     */
    setFloorNavMountClick (index) {
      const { floor_item } = this.element
      const floor_offsetTop = floor_item[index].offsetTop - floor_item[0].offsetTop,
          window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
          timer = {
            step: 60,
            times: 16,
            FLOOR_OFFSETTOP: floor_offsetTop,
          }
      if (window_scrollTop > floor_offsetTop) {
        this.setFloorScrollArrowUp(timer)
      } else if (window_scrollTop == floor_offsetTop) {
        return false
      } else {
        this.setFloorScrollArrowDown(timer)
      }
    },
    /**
     * 设置楼层向上滚动
     * @param {Object} timer 定时器配置
     */
    setFloorScrollArrowUp (timer) {
      clearInterval(this.timer)
      this.timer = setInterval(() => {
        let window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        if (window_scrollTop <= timer.FLOOR_OFFSETTOP) {
          document.documentElement.scrollTop = timer.FLOOR_OFFSETTOP
          document.body.scrollTop = timer.FLOOR_OFFSETTOP
          clearInterval(this.timer)
        } else {
          document.documentElement.scrollTop = window_scrollTop - timer.step
          document.body.scrollTop = window_scrollTop - timer.step
        }
      }, timer.times)
    },
    /**
     * 设置楼层向下滚动
     * @param {Object} timer 定时器配置
     */
    setFloorScrollArrowDown (timer) {
      clearInterval(this.timer)
      this.timer = setInterval(() => {
        let window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        // 这里多加了一个大一点的值,需要精确的就这里自己算一下,我随便写了个500,
        // 不加会导致window_scrollTop一直小于timer.FLOOR_OFFSETTOP,
        // 退出不了setInterval,导致滑动失效一直在底部。
        if (window_scrollTop + 500 >= timer.FLOOR_OFFSETTOP) {
          document.documentElement.scrollTop = timer.FLOOR_OFFSETTOP
          document.body.scrollTop = timer.FLOOR_OFFSETTOP
          clearInterval(this.timer)
        } else {
          document.documentElement.scrollTop = window_scrollTop + timer.step
          document.body.scrollTop = window_scrollTop - timer.step
        }
      }, timer.times)
    },
    // /**
    //  * 监听窗口滚动楼层导航动态定位
    //  */
    // floorSrcollEventListener () {
    //   const { nav_item, floor_item } = this.element
    //   const window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    //   for (let i = 0, len = floor_item.length; i < len; i++) {
    //     let floor_offsetTop = floor_item[i].offsetTop - floor_item[0].offsetTop
    //     if (window_scrollTop >= floor_offsetTop) {
    //       for (let n = 0, len = nav_item.length; n < len; n++) {
    //         const current_classList = nav_item[n].classList
    //         i === n
    //             ? current_classList.add('active')
    //             : current_classList.remove('active')
    //       }
    //     }
    //   }
    // }
  }
}
</script>

<style scoped>
.floor-warpper {
  width: 1000px;
  margin: auto;
}
.floor-nav {
  /*position: fixed;*/
  float: left;
  width: 100px;
}
.nav-list {
  width: 100%;
  padding: 0;
  display: inline-block;
  text-align: center;
  /*background-color: #f8f8f8;*/
}
.nav-list-item {
  display: inline-block;
  width: 100%;
  height: 100%;
  line-height: 48px;
  vertical-align: middle;
  align-self: center;
  border-bottom: 1px solid #fff;
  cursor: pointer;
}
.nav-list-item.active,
.nav-list-item:hover {
  /*color: #FFF;*/
  background-color: #C9C9C9;
}
.wrap-body {
  margin-left: 120px;
  border-left: dashed #1c1c1c 1px;
}
.floor-item {
  margin-left: 20px;
  width: 95%;
  /*margin: 60px auto;*/
  min-height: 300px;
  text-align: center;
  color: #FFF;
  background-color: #404040;
}
</style>

原左边固定不变

<template>
  <div class="floor-warpper">
    <section class="floor-nav" id="floorNavList">
      <ul class="nav-list">
        <li
            class="nav-list-item"
            v-for="(item, index) in floorList"
            :key="item.id"
            @click="setFloorNavMountClick(index)"
        >{{ item.name }}</li>
      </ul>
    </section>
    <section
        class="floor-item"
        v-for="item in floorList"
        :key="item.id">
      <div class="floor-item-box">
        <h3>{{ item.name }}</h3>
      </div>
    </section>
  </div>
</template>

<script>
export default {
  name: 'IFloor',
  data () {
    return {
      element: {
        nav_item: null,
        floor_item: null
      },
      timer: null,
      floorList: [
        { id: 1, name: 'F1' },
        { id: 2, name: 'F2' },
        { id: 3, name: 'F3' },
        { id: 4, name: 'F4' },
        { id: 5, name: 'F5' },
        { id: 6, name: 'F6' }
      ]
    }
  },
  mounted () {
    this.element = {
      nav_item: document.getElementsByClassName('nav-list-item'),
      floor_item: document.getElementsByClassName('floor-item')
    }
    this.element.nav_item[0].classList.add('active')
    window.addEventListener('scroll', this.floorSrcollEventListener)
  },
  beforeDestroy () {
    window.removeEventListener('scroll', this.floorSrcollEventListener)
  },
  methods: {
    /**
     * 设置楼层导航事件驱动方法
     * @param {Number} index  楼层下标
     */
    setFloorNavMountClick (index) {
      const { floor_item } = this.element
      const floor_offsetTop = floor_item[index].offsetTop - floor_item[0].offsetTop,
          window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
          timer = {
            step: 60,
            times: 16,
            FLOOR_OFFSETTOP: floor_offsetTop,
          }
      if (window_scrollTop > floor_offsetTop) {
        this.setFloorScrollArrowUp(timer)
      } else if (window_scrollTop == floor_offsetTop) {
        return false
      } else {
        this.setFloorScrollArrowDown(timer)
      }
    },
    /**
     * 设置楼层向上滚动
     * @param {Object} timer 定时器配置
     */
    setFloorScrollArrowUp (timer) {
      clearInterval(this.timer)
      this.timer = setInterval(() => {
        let window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        if (window_scrollTop <= timer.FLOOR_OFFSETTOP) {
          document.documentElement.scrollTop = timer.FLOOR_OFFSETTOP
          document.body.scrollTop = timer.FLOOR_OFFSETTOP
          clearInterval(this.timer)
        } else {
          document.documentElement.scrollTop = window_scrollTop - timer.step
          document.body.scrollTop = window_scrollTop - timer.step
        }
      }, timer.times)
    },
    /**
     * 设置楼层向下滚动
     * @param {Object} timer 定时器配置
     */
    setFloorScrollArrowDown (timer) {
      clearInterval(this.timer)
      this.timer = setInterval(() => {
        let window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        if (window_scrollTop + 500 >= timer.FLOOR_OFFSETTOP) {
          document.documentElement.scrollTop = timer.FLOOR_OFFSETTOP
          document.body.scrollTop = timer.FLOOR_OFFSETTOP
          clearInterval(this.timer)
        } else {
          document.documentElement.scrollTop = window_scrollTop + timer.step
          document.body.scrollTop = window_scrollTop - timer.step
        }
      }, timer.times)
    },
    /**
     * 监听窗口滚动楼层导航动态定位
     */
    floorSrcollEventListener () {
      const { nav_item, floor_item } = this.element
      const window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
      for (let i = 0, len = floor_item.length; i < len; i++) {
        let floor_offsetTop = floor_item[i].offsetTop - floor_item[0].offsetTop
        if (window_scrollTop >= floor_offsetTop) {
          for (let n = 0, len = nav_item.length; n < len; n++) {
            const current_classList = nav_item[n].classList
            i === n
                ? current_classList.add('active')
                : current_classList.remove('active')
          }
        }
      }
    }
  }
}
</script>

<style scoped>
.floor-warpper {
  width: 1000px;
  margin: auto;
}
.floor-nav {
  position: fixed;
  top: 200px;
  left: 50px;
}
.nav-list {
  width: 48px;
  padding: 0;
  display: inline-block;
  text-align: center;
  background-color: #f8f8f8;
}
.nav-list-item {
  display: inline-block;
  width: 100%;
  height: 100%;
  line-height: 48px;
  vertical-align: middle;
  align-self: center;
  border-bottom: 1px solid #fff;
  cursor: pointer;
}
.nav-list-item.active,
.nav-list-item:hover {
  color: #FFF;
  background-color: #404040;
}

.floor-item {
  width: 100%;
  margin: 60px auto;
  min-height: 300px;
  text-align: center;
  color: #FFF;
  background-color: #404040;
}
</style>

参考

滚动楼层导航定位

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 神奇的position:sticky

    position:sticky定义, eg:CSS中position属性介绍(新增sticky)

    Rattenking
  • 如何用uni-app快速将Vue项目输出到小程序和H5

    随着微信小程序的火爆及百度、头条小程序的持续推进,跨端开发的需求愈发迫切,业界随之出现了一系列的跨端框架,但对于H5平台跨端支持的都不太彻底:

    极乐君
  • 侧边栏导航(移动端商品--评论--详情)随楼层滑动高亮显示

    接触前端一年时间,开始还能感觉到自己的进步,随着时间的推移,开始不知道方向。因为各种前端的框架和插件在网上都能够找到现成的,直接下载下来用就好了。

    Rattenking
  • jquery+原生的javascript实现网站右侧导航定位--来自慕课课程

    xiaohejun
  • 2019年最全的web前端知识体系汇总

    · HTML: https://developer.mozilla.org/zh-CN/docs/Web/HTML

    用户5827212
  • MPM 卖场可视化搭建系统 — 要素设计

    当组织团队达到一定的开发规模时,页面可视化搭建是一个减少冗复开发、释放生产力的最有效方案。由于专人专责,在平时的实际工作中,我们接触的大多都是一些比较固定的业务...

    WecTeam
  • vue移动端开发总结

    相对于PC端来说,移动端设备分辨率百花齐放,千奇百怪,对于每一个开发者来说,移动端适配是我们进行移动端开发第一个需要面对的问题。

    前端老道
  • 导航栏滚动吸顶并自动高亮和点击跳转锚点

    在阿里云的云市场页面上有一个效果,就是api导航栏当滚动条滚动到其所在位置时,自动吸顶,当滚动到下方所在导航栏指定的介绍时,自动高亮其导航栏。点击时则会滑动至其...

    OECOM
  • 从项目中由浅入深的学习vue,微信小程序和快应用 (1)

    2.技术栈 vue+vue-router+vuex+axios+element-UI+iconfont(阿里)

    火狼1
  • Web-第五天 BootStrap学习

    将使用Bootstrap重写首页,整个案例中将使用到Bootstrap各种模块,为了方便编程,将采用拆分的原则,各个模块单独编写,最后组合。

    Java帮帮
  • Vue:Vue中的导航浮顶

    MrTreasure
  • 【面试需要-Vue全家桶】一文带你看透Vue前端路由

    掘金 | https://juejin.im/user/5a16e1f3f265da43128096cb

    达达前端
  • 基于JQuery实现电梯导航特效

    越陌度阡
  • Vue Router 4.0 正式发布!焕然一新。

    在经历了 14 个 Alpha,13 个 Beta 和 6 个 RC 版本之后,Vue Router v4 闪亮登场,为你带来了 TypeScript 集成、新...

    若川
  • Vue Router 4.0 正式发布!焕然一新。

    在经历了 14 个 Alpha,13 个 Beta 和 6 个 RC 版本之后,Vue Router v4 闪亮登场,为你带来了 TypeScript 集成、新...

    lucifer210
  • Vue.js开发移动端经验总结

    相对于PC端来说,移动端设备分辨率百花齐放,千奇百怪,对于每一个开发者来说,移动端适配是我们进行移动端开发第一个需要面对的问题。

    coder_koala
  • 适合 JS 新手学习的开源项目——在 GitHub 学编程

    这里是 HelloGitHub 的《GitHub 上适合新手的开源项目》系列的最后一篇,系列文章:

    HelloGitHub
  • 商品添加到购物车动画getBoundingClientRect获取元素位置

    3. IE67的left、top会少2px,并且没有width、height属性。

    javascript.shop
  • 滚动视差让你不相信“眼见为实”

    视差滚动(Parallax Scrolling)是指让多层背景以不同的速度移动,形成立体的运动效果。

    前端森林

扫码关注云+社区

领取腾讯云代金券