Vue.js实现页面后退时还原滚动位置的操作方法

目录
  • 开始
    • 目录结构
    • 安装模块
    • route规则
    • code社区api为例子
    • 总结

前言

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-vuet-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

<template>
  <!--
      设置指令监听全局滚动条,
      注意了,光是设置指令可不行,还需要在组件中使用route规则,
      来处理页面滚动的操作,
      局部滚动条直接去掉.window即可
      如果需要同时记录全局滚动条和div滚动条直接设置.window.self即可
      它能做到N多个滚动位置记录,具体看官方文档喔!
      注:记录div滚动的话,需要设置一个name来识别
      v-vuet-scroll="{ path: 'topic-detail', name: 'xxx' }"
  -->
  <div v-vuet-scroll.window="{ path: 'topic-list' }">
    <header>
      <ul>
        <li v-for="item in list.tabs">
          <router-link :to="{ name: 'topic-list', query: { tab: item.value } }">{{ item.label }}</router-link>
        </li>
      </ul>
    </header>
    <ul class="list">
      <li v-for="item in list.data">
          <router-link :to="{ name: 'topic-detail', params: { id: item.id } }">{{ item.title }}</router-link>
      </li>
    </ul>
  </div>
</template>
<script>
  import { mapRules, mapModules } from 'vuet'

  export default {
    mixins: [
      // 设置模块的更新规则
      mapRules({
        route: 'topic-list'
      }),
      // 连接模块的状态
      mapModules({
        list: 'topic-list'
      })
    ]
  }
</script>
<style scoped>

</style>

pages/topic/Detail.vue

<template>
  <div v-vuet-scroll.window="{ path: 'topic-detail' }">
    <h3>{{ detail.data.title }}</h3>
    <div v-html="detail.data.content"></div>
  </div>
</template>
<script>
  import { mapRules, mapModules } from 'vuet'

  export default {
    mixins: [
      // 设置模块的更新规则
      mapRules({
        route: 'topic-detail'
      }),
      // 连接模块的状态
      mapModules({
        detail: 'topic-detail'
      })
    ]
  }
</script>
<style scoped>
</style>

总结

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

到此这篇关于Vue.js轻松实现页面后退时,还原滚动位置的文章就介绍到这了,更多相关js生成二维码或条形码内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 解决vue页面刷新或者后退参数丢失的问题

    在toB的项目中,会经常遇到列表数据筛选查询的情景,当要打开某一项的详情页或者暂时离开列表页,再返回(后退时),选择的筛选条件会全部丢失,辛辛苦苦选择好的条件全没了,还得重新选择,如果有分页的更头大,还得重新一页页翻到之前看到的那一页,用户体验极度不友好. 我的解决有两种: 第一种方法:用vue 的<keep-alive>,即在<router-view>外套一层<keep-alive>. 虽然可以达到一定效果,但是控制起来比较麻烦,比如项目中并不是所有页面都需要缓存,代

  • Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置

    前提: 之前写过关于keep-Alive组件,来实现在列表页进入详情页后,后退,返回列表,显示上次访问的位置(原理就是缓存列表页数据来实现),目前发现另外一个问题,就是如果后台操作改变数据的状态,缓存的办法就会导致数据更新不及时导致一些页面错误(例如:商品疑问,在后台答复之后,不可以修改内容,前台更新不及时就会导致,前台显示可编辑,但实际状态是不可编辑了),所以又继续研究另外一种解决办法,scrollBehavior 来实现. 简介: 使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持

  • Vue.js实现页面后退时还原滚动位置的操作方法

    目录 开始 目录结构 安装模块 route规则 code社区api为例子 总结 前言 从Vue.js 2.x发布之后,陆陆续续做了七八个项目,摸索出来了一套自己的状态管理模式,我将之称为Vuet.它以规则来驱动状态更新,它带来的是开发效率上的飙升,它就像草原,而你是野马,任你随意驰骋,总之它是为敏捷开发而诞生. 缘由 在大型的Vue应用程序开发中,多组件通信.多页面通信,往往是跨不过的坎,一个页面组件中往往参杂着页面获取数据的代码和响应用户操作的代码,稍有不慎,就使得代码混乱不堪.A.B.C三个

  • 详解Vue.js在页面加载时执行某个方法

    jQuery中可以这样写 vue中,如果要达到相同效果,可以使用vue的生命周期函数,如create或者mounted 附上vue.js的生命周期函数执行流程 总结 以上所述是小编给大家介绍的Vue.js在页面加载时执行某个方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的.在此也非常感谢大家对我们网站的支持!

  • 解决使用Vue.js显示数据的时,页面闪现原始代码的问题

    今天开始学习Vue.js的使用,但是在学习过程中发现一个问题,那就是页面加载数据时,原始代码会闪现一下.查访各方资料,终的解决方法. 第一步.加入一段css代码 <style type="text/css"> [v-cloak] { display: none; } </style> 第二步.在view上引用css模块 <div id="app" v-cloak> <h1>{{message}}</h1>

  • 利用webstrom调试Vue.js单页面程序的方法教程

    前言 使用 webstrom 调试 Vue.js 单页面程序,理论上来说应该是支持所有用 webpack 构建的应用程序 webstrom 版本:2017.1 代码:使用 vue-cli 构建的基础单页面应用 修改 webpack 配置 由于 webpack 把所有文件全部打包到一起,所以我们需要 webpack 提供给我们一个源地图 修改 devtool 为 source-map 这是我的开发配置文件 webpack.dev.conf.js module.exports = merge(bas

  • Vue.js 单页面多路由区域操作的实例详解

    单页面多路由区域操作 在一个页面中有两个及以上的<router-view>区域,需要通过设置路由的index.js,来操作这些区域的内容 App.vue 中设置: <router-view></router-view> <router-view name="left" style="float: left;width: 50%; height: 300px;background-color: #ccc;"></r

  • vue axios 在页面切换时中断请求方法 ajax

    如下所示: Vue.prototype.$ajax=axios; const CancelToken = axios.CancelToken; let cancel; let cancelAjaxText = '中断成功'; Vue.prototype.post = function(url,data,loading){ var ajax = Vue.prototype.$ajax({ method: 'post', url:url, data: data, cancelToken: new C

  • 使用vue.js在页面内组件监听scroll事件的方法

    思路:scroll在哪儿个组件内,就在获取那个dom元素.网上好多思路是 window.addEventListener("scroll", function(){ console.log('scrolling'); }); 这是监听不到的!如果你整个网页可以滑动,或许还可以试试! 对于像我这样,只在页面的内的一个div内要监听的. 实现代码如下: 第一步:滑动的组件外层的div加 ref="viewBox" 为了通过$refs获取dom元素 <!--设备列表

  • vue/js实现页面自动往上滑动效果

    本文实例为大家分享了vue/js实现页面自动往上滑动的具体代码,供大家参考,具体内容如下 最近做的新项目中要求让看不见的内容自动往上滑动一定的距离,使之可以看到,下面我来分享一下. 效果图: 我主要是使用 scrollTop 来做的往上滑动的功能,使用 animate 函数使之有一定的动画效果.有一个注意点就是要滚动的元素是父级标签,比如我下面列举的代码:id=“scrollbody” 是放在父级标签那里的,它包裹着多项 class=“item” ,如果还是不懂的话,就看使用了v-for在哪个标

  • JS实现页面载入时随机显示图片效果

    本文实例讲述了JS实现页面载入时随机显示图片效果.分享给大家供大家参考,具体如下: <html> <head> <title>JS 随机图片效果</title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <style type="text/css"> <!-- img { b

  • js实现鼠标经过时图片滚动停止的方法

    本文实例讲述了js实现鼠标经过时图片滚动停止的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml

随机推荐