Vue.js實現(xiàn)頁面后退時還原滾動位置的操作方法
前言
從Vue.js 2.x發(fā)布之后,陸陸續(xù)續(xù)做了七八個項目,摸索出來了一套自己的狀態(tài)管理模式,我將之稱為Vuet。它以規(guī)則來驅(qū)動狀態(tài)更新,它帶來的是開發(fā)效率上的飆升,它就像草原,而你是野馬,任你隨意馳騁,總之它是為敏捷開發(fā)而誕生。
緣由
在大型的Vue應(yīng)用程序開發(fā)中,多組件通信、多頁面通信,往往是跨不過的坎,一個頁面組件中往往參雜著頁面獲取數(shù)據(jù)的代碼和響應(yīng)用戶操作的代碼,稍有不慎,就使得代碼混亂不堪。A、B、C三個頁面中,都需要同樣的數(shù)據(jù),然后每一個頁面都寫一次、發(fā)送一次請求,不久之后,代碼就十分臃腫了。因此我們就需要vuex這樣的第三方庫來管理狀態(tài)了
Vuet誕生初衷
從列表點擊進去到詳情,從詳情返回后,我們期望能顯示回原來的位置,而不是整個頁面重新初始化,重新請求數(shù)據(jù),這樣帶來的是用戶體驗的極度糟糕的,我們期望能有一種規(guī)則來定義狀態(tài)應(yīng)該如何更新,這便是Vuet.js誕生的初衷。它以規(guī)則來定義狀態(tài)的更新,它也是一種Vue.js全新的狀態(tài)管理模式。天生的規(guī)則驅(qū)動,使得本次教程的主題,也將變得異常簡單,因為我們只需要定義好頁面更新的規(guī)則即可實現(xiàn)。
有了Vuex還需要Vuet做什么?
Vuex和Vuet的出發(fā)點不一樣,Vuex不建議直接更新狀態(tài),而是通過提交mutation來更新狀態(tài),而Vuet則是允許的。因此Vuex和Vuet是可以配合使用的,并且有著不同的應(yīng)用場景,該用Vuex的地方就用Vuex,可用Vuet的地方,就可以使用Vuet
開始
上面廢話了那么久,也是因為Vuet.js才剛剛誕生,急需大家的支持。嗯,接下來我們開始本次的主題!
目錄結(jié)構(gòu)
|-- pages // 頁面組件 | |-- topic // 主題模塊 | |-- Detail.vue // 主題詳情 | |-- List.vue // 主題列表 |-- router // router相關(guān) | |-- index.js // 入口文件 | |-- router.js // 實例化VueRouter |-- vuet // vuet相關(guān) | |-- index.js // 入口文件 | |-- topic-detail.js // 主題詳情的狀態(tài) | |-- topic-list.js // 主題列表的狀態(tài) | |-- vuet.js // 實例化Vuet |- index.html // 程序頁面入口文件 |- main.js // Vue實例化入口文件
上面是我們本次項目的基本目錄結(jié)構(gòu)
安裝模塊
npm install vue vue-router vuet --save
這些都是基本的模塊,想必不用多說,大家都知道的。
route規(guī)則
先給出官方文檔地址本章的主題,核心就是在route規(guī)則身上,它能幫你獲取、更新、重置頁面的狀態(tài),配合v-vuet-scroll指令就能幫你處理頁面的全局滾動條和div元素自身的滾動條
code社區(qū)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 vuetvuet/topic-list.js
export default {
routeWatch: 'query', // 定義頁面的更新規(guī)則
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', // 定義頁面的更新規(guī)則
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 routerpages/topic/List.vue
<template>
<!--
設(shè)置指令監(jiān)聽全局滾動條,
注意了,光是設(shè)置指令可不行,還需要在組件中使用route規(guī)則,
來處理頁面滾動的操作,
局部滾動條直接去掉.window即可
如果需要同時記錄全局滾動條和div滾動條直接設(shè)置.window.self即可
它能做到N多個滾動位置記錄,具體看官方文檔喔!
注:記錄div滾動的話,需要設(shè)置一個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: [
// 設(shè)置模塊的更新規(guī)則
mapRules({
route: 'topic-list'
}),
// 連接模塊的狀態(tài)
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: [
// 設(shè)置模塊的更新規(guī)則
mapRules({
route: 'topic-detail'
}),
// 連接模塊的狀態(tài)
mapModules({
detail: 'topic-detail'
})
]
}
</script>
<style scoped>
</style>總結(jié)
咋的一看,Vuet看起來也不是很復(fù)雜,只需要定義好模塊狀態(tài),然后在組件中設(shè)置對應(yīng)的規(guī)則來更新模塊的狀態(tài)即可。其實vuet自帶的route規(guī)則能夠支持同時記錄全局滾動條、div自身的滾動條,這樣就能大大的提升了我們的用戶體驗
到此這篇關(guān)于Vue.js輕松實現(xiàn)頁面后退時,還原滾動位置的文章就介紹到這了,更多相關(guān)js生成二維碼或條形碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript學(xué)習(xí)網(wǎng)址備忘
javascript學(xué)習(xí)網(wǎng)址備忘...2007-05-05
JavaScript對象與數(shù)組的幾種常見復(fù)制方法
在 JavaScript 開發(fā)中,對象和數(shù)組的復(fù)制是一個非常常見的操作,無論是函數(shù)參數(shù)傳遞、狀態(tài)管理,還是避免不必要的副作用,了解和掌握各種復(fù)制方式至關(guān)重要,我們將系統(tǒng)梳理 JavaScript 中的幾種常見復(fù)制方法,并對其應(yīng)用場景進行詳細(xì)說明,需要的朋友可以參考下2024-10-10
JavaScript中的console.time()函數(shù)詳細(xì)介紹
這篇文章主要介紹了JavaScript中的console.time()函數(shù)詳細(xì)介紹,console.time()函數(shù)主要用來統(tǒng)計程序執(zhí)行時間,需要的朋友可以參考下2014-12-12

