美文网首页技术文档
Vue实现StickyTop效果

Vue实现StickyTop效果

作者: fehysunny | 来源:发表于2017-12-10 18:43 被阅读461次

    最近的wap项目开发中有这么一个需求:

    1. 初始情况下页面布局如下图所示:
    1. 当页面滚动距离大于header时,switch-bar将固定在顶部
    1. 3个列表可以来回切换

    2. 切换列表时保持switch-bar状态,即当switch-bar固定在顶部时,切换列表后switch-bar仍然固定在顶部,当switch-bar不固定在顶部时,切换列表后页面回跳到顶部。

    3. 3个列表数据均为异步获取

    最后的实现效果(简单示例)如下:

    下面我们来看下如果实现这个stickyTop效果。

    首先说一下这个示例使用的技术栈:Vue + Vue-router + lodash + axios

      使用`Vue-router`: 实现嵌套路由
      使用`lodash`的`throttle`: 节流监听滚动事件,降低性能消耗
      使用`axios`: 发起异步请求
    

    实现思路:

    1. 页面使用流式布局,整个页面可分为4个组件(Home, Products, Orders, Docs
    const Home = {
      template: `
        <div class="home">
            <header class="header">header</header>
          <div class="switch-bar">
            <router-link to="/products">产品</router-link>
            <router-link to="/orders">订单</router-link>
            <router-link to="/docs">文档</router-link>
          </div>
          <div class="content">
            <router-view></router-view>
          </div>
        </div>`
    }  
    
    const Products = {
      template: 
      `
        <ul class="list products">
            <li v-for="item in list" :key="item.id">
                {{ item.name }}
            </li>
        </ul>
      `
    }
    
    const Orders = {
      template: 
      `
        <ul class="list products">
            <li v-for="item in list" :key="item.id">
                {{ item.name }}
            </li>
        </ul>
      `
    }
    
    const Docs = {
      template: 
      `
        <ul class="list products">
            <li v-for="item in list" :key="item.id">
                {{ item.name }}
            </li>
        </ul>
      `
    }
          
    
    1. 使用嵌套路由
    const routes = [{
      path: '/',
      component: Home,
      children: [{
        path: '',
        component: Products
      }, {
        path: 'products',
        component: Products
      }, {
        path: 'orders',
        component: Orders
      }, {
        path: 'docs',
        component: Docs
      }]
    }]
    
    1. 节流监听window滚动事件,当页面滚动高度 >= header高度时,设置switch-barposition属性为fixd,反之取消(实际通过一个变量isFix来控制样式)。
    .home.fix .switch-bar {
        position: fixed;
        left: 0;
        top: 0;
        z-index: 10;
    }
    <div class="home" :class="{'fix': isFix}">
        ...
        <div class="switch-bar">
            ...
        </div>
        ...
    </div>
    
    
    // 判断是否吸顶效果
    if (this.scrollTop >= this.headerHeight) {
      this.isFix = true
    } else {
      this.isFix = false
    }
    

    做完以上3点其实大部分工作就完成了,这时的运行效果如下:

    有两个问题:

    1. 切换列表时并没有保持switch-bar状态,因为示例中Products列表数比较少,导致页面的高度 <= 屏幕的高度,没有滚动条,所以当switch-bar固定在顶部并且从订单或文档切换过来时,由于document.body.scrollTop = 0,页面将跳到顶部
    2. switch-bar固定在顶部时,切换列表,列表数据第一条并没有显示到正确的位置。

    为了解决第一个问题,给content加了两个计算属性:contentMinHeightcontentMarginTop,动态计算contentheightmargin-top

    <div class="content" :style="{
        'minHeight': contentMinHeight + 'px',
        'marginTop': contentMarginTop + 'px'
        }">
    <router-view></router-view>
    </div>
    
    computed: {
        contentMinHeight() {
            const windowHeight = document.documentElement.clientHeight
            return this.isFix ? windowHeight - this.switchBarHeight : windowHeight - this.headerHeight - this.switchBarHeight
        },
        contentMarginTop() {
            return this.isFix ? this.switchBarHeight : 0
        }
    }
    

    为了解决第二个问题,watch $route的变化,手动将滚动条滚动至正确的位置

    watch: {
        '$route'(to, from) {
            this.$nextTick(() => {
               if (this.isFix) {
                  window.scrollTo(0, 0)  // 兼容chrome
                  window.scrollTo(0, this.headerHeight)
               } else {
                  window.scrollTo(0, 0)
                }
            })
        }
    }
    

    到这里,整个示例就完成啦~

    想要查看完整代码可前往:https://github.com/hysunny/Vue-dev-note/blob/master/vue-stickyTop/index.html

    或查看在线示例:https://jsfiddle.net/hysunny/yvzyp4kk/2/

    相关文章

      网友评论

        本文标题:Vue实现StickyTop效果

        本文链接:https://www.haomeiwen.com/subject/lmpvixtx.html