Vue实现StickyTop效果

最近的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/

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,093评论 4 62
  • 伏魔者必伏其心,心静则群魔退听。 书生是来赴考恩科的。 原本三年一试,因为圣人恩典,又加了这一场。 书生千里迢迢赶...
    陈净植阅读 331评论 2 2
  • 沱江串古城, 角楼立水中。 阿婆河边洗, ...
    f16116f271dd阅读 198评论 0 0
  • 一个女人若是嫁的不好,在以前的农村便是十分可怕的事情。想起以前村里的一个嫂子了。 嫂子叫金霞,当年那个美啊...
    瑀轩阅读 603评论 4 1
  • 命令 command [-options] [parameter1] … 帮助 1,ls--help 2,man ...
    步_尘阅读 476评论 0 0