vue中楼层滚动实现原理解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue中楼层滚动实现原理解析相关的知识,希望对你有一定的参考价值。

参考技术A 楼层效果如上图所示:当点击左边的索引表会跳到对应的模块,同时在滚动模块的时候索引表也跟着变。
这个主要是要利用iScroll的iscroll方法,实时获取滚动的y轴数据,同时获取每个索引对应模块的offsetTop的值,保存到一个数组中,这里我是把这个方法放到watch里面的,监视数据是否有变化,同时这里因为我们要获取dom元素,所以要用$nextTick方法等待dom渲染好再获取每个索引对应模块的高度。

点击索引表,实现滚动到相应的模块就非常简单了。根据当前点击索引的索引,找到this.indexTopOffset里面的scrollTop值,然后利用iscroll里面的scrollTo方法滚动就可以了。

vue实现京东动态楼层效果

页面效果如下
技术图片

<template>
    <div>
        <h1>首页</h1>
        <section class="floor-nav" id="floorNavList">
          <!-- 左侧楼层 -->
            <ul class="nav-list">
                <li class="nav-list-item" v-for="(item, index) in floorNav" :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">
                <h2>{{ item.name }}</h2>
            </div>
        </section>
    </div>
</template>

<script>
    var TIMER = null
export default {
      name: 'home',
      data() {
        return {
          floorNav: [ // 自定义左侧楼层数
            { id: 1, name: 'F1' },
            { id: 2, name: 'F2' },
            { id: 3, name: 'F3' },
            { id: 4, name: 'F4' },
            { id: 5, name: 'F5' },
            { id: 6, name: 'F6' }
          ],
          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' }
          ],
          floorIndex: 1
        }
      },
      methods: {
        /**
             * 设置楼层导航事件驱动方法
             * @params Number index  楼层下标
             */
        // 点击楼层事件
        setFloorNavMountClick(index) {
          console.log('index....', index)
          var _this = this
          let floor_item = document.getElementsByClassName('floor-item'),
            floor_offsetTop = floor_item[index].offsetTop - floor_item[0].offsetTop,
            window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
            timer = {
              step: 50,
              times: 20,
              FLOOR_OFFSETTOP: floor_offsetTop
            }
          console.log('floor_offsetTop', floor_offsetTop)
          console.log({ index, offsetTop: timer.FLOOR_OFFSETTOP })
    
          if (window_scrollTop > floor_offsetTop) {
            _this.setFloorScrollArrowUp(timer)
          } else if (window_scrollTop == floor_offsetTop) {
            return false
          } else {
            _this.setFloorScrollArrowDown(timer)
          }
          console.log('floor_item', floor_item)
          console.log('window_scrollTop', window_scrollTop)
          console.log('floor_offsetTop', floor_offsetTop)
        },
        /**
             * 设置楼层向上滚动
             * @params Object timer 定时器配置
             */
        setFloorScrollArrowUp(timer) {
          var _this = this
          clearInterval(TIMER)
          TIMER = setInterval(() => {
            const 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(TIMER)
            } else {
              document.documentElement.scrollTop = window_scrollTop - timer.step
              document.body.scrollTop = window_scrollTop - timer.step
            }
          }, timer.times)
        },
        /**
             * 设置楼层向下滚动
             * @params Object timer 定时器配置
             */
        setFloorScrollArrowDown(timer) {
          var _this = this
          clearInterval(TIMER)
          TIMER = setInterval(() => {
            const 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(TIMER)
            } else {
              document.documentElement.scrollTop = window_scrollTop + timer.step
              document.body.scrollTop = window_scrollTop - timer.step
            }
          }, timer.times)
        },
        /**
         * 监听窗口滚动楼层导航动态定位
         */
        floorSrcollAddEventListener() {
          var _this = this
          let nav_item = document.getElementById('floorNavList').getElementsByClassName('nav-list-item'),
            floor_item = document.getElementsByClassName('floor-item')
          nav_item[0].className = 'nav-list-item active'
          window.onscroll = function() {
            const window_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
            for (let i = 0, len = floor_item.length; i < len; i++) {
              const 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++) {
                  nav_item[n].className = 'nav-list-item ' + (i === n ? 'active' : '')
                }
              }
            }
          }
    },
        /**
             * 页面初始化
             */
        initPage() {
          var _this = this
          _this.floorSrcollAddEventListener()
        }
      },
      mounted() {
        this.initPage()
  }
    }
</script>

<style scoped>
h1 {
    text-align: center;
}
.setaxios {
    width: 1000px;
    margin: 20px auto;
    text-align: right;
}
.setaxios input[type=button] {
    text-align: center;
}
.floor-nav {
    position: fixed;
    top: 200px;
    /* left: 50px; */
    left:350px;
}
.floor-nav .nav-list {
    width: 48px;
    display: inline-block;
    text-align: center;
    background-color: #f8f8f8;
    padding: 5px 15px;
    /* background-color: red; */
}
.floor-nav .nav-list .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;
}
.floor-nav .nav-list .nav-list-item.active,
.floor-nav .nav-list .nav-list-item:hover {
    color: #FFF;
    background-color: #404040;
    /* color: red; */
}

.floor-item {
    width: 1000px;
    margin: 60px auto;
    min-height: 300px;
    text-align: center;
    color: #FFF;
    background-color: #404040;
}

</style>

直接在页面引用即可
本文学习自:https://www.twblogs.net/a/5bfadb1fbd9eee7aec4dc8ab/zh-cn

以上是关于vue中楼层滚动实现原理解析的主要内容,如果未能解决你的问题,请参考以下文章

vue数据双向绑定原理-解析器Complie

vue中如何使用better-scroll实现横向滚动?

vue.js响应式原理解析与实现

vue.js响应式原理解析与实现

vue.js响应式原理解析与实现

转vue.js响应式原理解析与实现