美文网首页技术文档
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