资讯专栏INFORMATION COLUMN

Vue.js轻松实现页面后退时,还原滚动位置

赵连江 / 3021人阅读

摘要:前言从发布之后,陆陆续续做了七八个项目,摸索出来了一套自己的状态管理模式,我将之称为。其实自带的规则能够支持同时记录全局滚动条自身的滚动条,这样就能大大的提升了我们的用户体验例子源码官方

前言

Vue.js 2.x发布之后,陆陆续续做了七八个项目,摸索出来了一套自己的状态管理模式,我将之称为Vuet。它以规则来驱动状态更新,它带来的是开发效率上的飙升,它就像草原,而你是野马,任你随意驰骋,总之它是为敏捷开发而诞生。

缘由

在大型的Vue应用程序开发中,多组件通信、多页面通信,往往是跨不过的坎,一个页面组件中往往参杂着页面获取数据的代码和响应用户操作的代码,稍有不慎,就使得代码混乱不堪。A、B、C三个页面中,都需要同样的数据,然后每一个页面都写一次、发送一次请求,不久之后,代码就十分臃肿了。因此我们就需要vuex这样的第三方库来管理状态了

Vuet诞生初衷

从列表点击进去到详情,从详情返回后,我们期望能显示回原来的位置,而不是整个页面重新初始化,重新请求数据,这样带来的是用户体验的极度糟糕的,我们期望能有一种规则来定义状态应该如何更新,这便是Vuet.js诞生的初衷。它以规则来定义状态的更新,它也是一种Vue.js全新的状态管理模式。天生的规则驱动,使得本次教程的主题,也将变得异常简单,因为我们只需要定义好页面更新的规则即可实现。

有了Vuex还需要Vuet做什么?

Vuex和Vuet的出发点不一样,Vuex不建议直接更新状态,而是通过提交mutation来更新状态,而Vuet则是允许的。因此Vuex和Vuet是可以配合使用的,并且有着不同的应用场景,该用Vuex的地方就用Vuex,可用Vuet的地方,就可以使用Vuet

开始

上面废话了那么久,也是因为Vuet.js才刚刚诞生,急需大家的支持。嗯,接下来我们开始本次的主题!

目录结构
|-- pages                 // 页面组件
|   |-- topic             // 主题模块
|       |-- Detail.vue    // 主题详情
|       |-- List.vue      // 主题列表
|-- router                // router相关
|   |-- index.js          // 入口文件
|   |-- router.js         // 实例化VueRouter
|-- vuet                  // vuet相关
|   |-- index.js          // 入口文件
|   |-- topic-detail.js   // 主题详情的状态
|   |-- topic-list.js     // 主题列表的状态
|   |-- vuet.js           // 实例化Vuet
|- index.html             // 程序页面入口文件
|- main.js                // Vue实例化入口文件

上面是我们本次项目的基本目录结构

安装模块
npm install vue vue-router vuet --save

这些都是基本的模块,想必不用多说,大家都知道的。

route规则

先给出官方文档地址
本章的主题,核心就是在route规则身上,它能帮你获取、更新、重置页面的状态,配合v-route-scroll指令就能帮你处理页面的全局滚动条和div元素自身的滚动条

code社区api为例子

main.js

  import Vue from "vue"
  import router from "./router/"
  import vuet from "./vuet/"
  
  export default new Vue({
    el: "#app",
    vuet,
    router,
    render (h) {
      return h("router-view")
    }
  })

vuet/index.js

  import vuet from "./vuet"
  
  export default vuet

vuet/vuet.js

  import Vue from "vue"
  import Vuet from "vuet"
  import topicList from "./topic-list"
  import topicDetail from "./topic-detail"
  
  Vue.use(Vuet)
  
  const vuet = new Vuet({
    data () {
      return {
        loading: true, // 请求中
        loaderr: false // 请求失败
      }
    },
    pathJoin: "-", // 父子模块的连接路径
    modules: {
      topic: {
        list: topicList,
        detail: topicDetail
      }
    }
  })
  
  vuet.beforeEach(({ path, params, state }) => {
    state.loading = true
    state.loaderr = false
  })
  
  vuet.afterEach((err, { path, params, state }) => {
    state.loading = false
    state.loaderr = !!err
  })
  
  export default vuet

vuet/topic-list.js

  export default {
    routeWatch: "query", // 定义页面的更新规则
    data () {
      return {
        data: [],
        tabs: [
          {
            label: "全部",
            value: "all"
          },
          {
            label: "精华",
            value: "good"
          },
          {
            label: "分享",
            value: "share"
          },
          {
            label: "问答",
            value: "ask"
          },
          {
            label: "招聘",
            value: "job"
          }
        ]
      }
    },
    async fetch ({ route }) {
      const { tab = "" } = route.query
      const { data } = await window.fetch(`https://cnodejs.org/api/v1/topics?mdrender=false&tab=${tab}`).then(response => response.json())
      return {
        data
      }
    }
  }

vuet/topic-detail.js

  export default {
    routeWatch: "params.id", // 定义页面的更新规则
    data () {
      return {
        data: {
          id: null,
          author_id: null,
          tab: null,
          content: null,
          title: null,
          last_reply_at: null,
          good: false,
          top: false,
          reply_count: 0,
          visit_count: 0,
          create_at: null,
          author: {
            loginname: null,
            avatar_url: null
          },
          replies: [],
          is_collect: false
        }
      }
    },
    async fetch ({ route }) {
      const { data } = await window.fetch(`https://cnodejs.org/api/v1/topic/${route.params.id}`).then(response => response.json())
      return {
        data
      }
    }
  }

router/index.js

  import router from "./router"
  
  export default router

router/router.js

  import Vue from "vue"
  import VueRouter from "vue-router"
  import TopicList from "../pages/topic/List"
  import TopicDetail from "../pages/topic/Detail"
  
  Vue.use(VueRouter)
  
  const RouterView = {
    render (h) {
      return h("router-view")
    }
  }
  
  const router = new VueRouter({
    routes: [
      {
        path: "/",
        component: RouterView,
        children: [
          {
            path: "",
            name: "topic-list",
            component: TopicList
          },
          {
            path: "/:id",
            name: "topic-detail",
            component: TopicDetail
          }
        ]
      }
    ]
  })
  
  export default router

pages/topic/List.vue

  
  
  

pages/topic/Detail.vue

  
  
  

总结

咋的一看,Vuet看起来也不是很复杂,只需要定义好模块状态,然后在组件中设置对应的规则来更新模块的状态即可。其实vuet自带的route规则能够支持同时记录全局滚动条、div自身的滚动条,这样就能大大的提升了我们的用户体验

例子源码

Vuet官方

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87047.html

相关文章

  • Vue.js项目重构,轻松实现上拉加载滚动位置还原

    摘要:这是基于进行状态管理的完整项目,包含了用户的登录退出,路由页面,滚动位置还原,帖子编辑状态保存等等,麻雀虽小,却是五脏俱全。 前言 上一篇《Vue.js轻松实现页面后退时,还原滚动位置》只是简单的实现了路由切换时进行的滚动位置还原,很多朋友就来问上拉加载怎么实现啊!于是我想起了以前做过一个叫vue-cnode的项目,于是花了两天时间进行了重构,完全的移除了Vuex,使用了Vuet来做为...

    junbaor 评论0 收藏0
  • Ajax局部页面刷新和History API结合的陷阱

    摘要:对于那些老网站或者老项目来说全盘改造成并不现实,于是就有了局部页面刷新这个解决方案。如果不知道局部页面刷新是何物请看这里,这里和这里。但实际上,第一次后退无法还原的内容陷阱,第二次后退页面刷新了一切恢复最初的样子。 ajax在现代网站已经得到非常普遍地应用,主要的好处大家都知道(异步加载数据,不用刷新整个浏览器,更小的数据传输尺寸)。对于那些老网站或者老项目来说全盘改造成ajax并不现...

    JasinYip 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0

发表评论

0条评论

赵连江

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<