Vue.js實(shí)現(xiàn)頁(yè)面后退時(shí)還原滾動(dòng)位置的操作方法
前言
從Vue.js 2.x
發(fā)布之后,陸陸續(xù)續(xù)做了七八個(gè)項(xiàng)目,摸索出來(lái)了一套自己的狀態(tài)管理模式,我將之稱為Vuet。它以規(guī)則來(lái)驅(qū)動(dòng)狀態(tài)更新,它帶來(lái)的是開發(fā)效率上的飆升,它就像草原,而你是野馬,任你隨意馳騁,總之它是為敏捷開發(fā)而誕生。
緣由
在大型的Vue應(yīng)用程序開發(fā)中,多組件通信、多頁(yè)面通信,往往是跨不過(guò)的坎,一個(gè)頁(yè)面組件中往往參雜著頁(yè)面獲取數(shù)據(jù)的代碼和響應(yīng)用戶操作的代碼,稍有不慎,就使得代碼混亂不堪。A、B、C三個(gè)頁(yè)面中,都需要同樣的數(shù)據(jù),然后每一個(gè)頁(yè)面都寫一次、發(fā)送一次請(qǐng)求,不久之后,代碼就十分臃腫了。因此我們就需要vuex
這樣的第三方庫(kù)來(lái)管理狀態(tài)了
Vuet誕生初衷
從列表點(diǎn)擊進(jìn)去到詳情,從詳情返回后,我們期望能顯示回原來(lái)的位置,而不是整個(gè)頁(yè)面重新初始化,重新請(qǐng)求數(shù)據(jù),這樣帶來(lái)的是用戶體驗(yàn)的極度糟糕的,我們期望能有一種規(guī)則來(lái)定義狀態(tài)應(yīng)該如何更新,這便是Vuet.js誕生的初衷。它以規(guī)則來(lái)定義狀態(tài)的更新,它也是一種Vue.js全新的狀態(tài)管理模式。天生的規(guī)則驅(qū)動(dòng),使得本次教程的主題,也將變得異常簡(jiǎn)單,因?yàn)槲覀冎恍枰x好頁(yè)面更新的規(guī)則即可實(shí)現(xiàn)。
有了Vuex還需要Vuet做什么?
Vuex和Vuet的出發(fā)點(diǎn)不一樣,Vuex不建議直接更新狀態(tài),而是通過(guò)提交mutation來(lái)更新狀態(tài),而Vuet則是允許的。因此Vuex和Vuet是可以配合使用的,并且有著不同的應(yīng)用場(chǎng)景,該用
Vuex的地方就用Vuex,可用
Vuet的地方,就可以使用Vuet
開始
上面廢話了那么久,也是因?yàn)?a rel="external nofollow" target="_blank">Vuet.js才剛剛誕生,急需大家的支持。嗯,接下來(lái)我們開始本次的主題!
目錄結(jié)構(gòu)
|-- pages // 頁(yè)面組件 | |-- topic // 主題模塊 | |-- Detail.vue // 主題詳情 | |-- List.vue // 主題列表 |-- router // router相關(guān) | |-- index.js // 入口文件 | |-- router.js // 實(shí)例化VueRouter |-- vuet // vuet相關(guān) | |-- index.js // 入口文件 | |-- topic-detail.js // 主題詳情的狀態(tài) | |-- topic-list.js // 主題列表的狀態(tài) | |-- vuet.js // 實(shí)例化Vuet |- index.html // 程序頁(yè)面入口文件 |- main.js // Vue實(shí)例化入口文件
上面是我們本次項(xiàng)目的基本目錄結(jié)構(gòu)
安裝模塊
npm install vue vue-router vuet --save
這些都是基本的模塊,想必不用多說(shuō),大家都知道的。
route規(guī)則
先給出官方文檔地址本章的主題,核心就是在route
規(guī)則身上,它能幫你獲取、更新、重置頁(yè)面的狀態(tài),配合v-vuet-scroll指令就能幫你處理頁(yè)面的全局滾動(dòng)條和div元素自身的滾動(dòng)條
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, // 請(qǐng)求中 loaderr: false // 請(qǐng)求失敗 } }, 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', // 定義頁(yè)面的更新規(guī)則 data () { return { data: [], tabs: [ { label: '全部', value: 'all' }, { label: '精華', value: 'good' }, { label: '分享', value: 'share' }, { label: '問(wèn)答', 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', // 定義頁(yè)面的更新規(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 router
pages/topic/List.vue
<template> <!-- 設(shè)置指令監(jiān)聽全局滾動(dòng)條, 注意了,光是設(shè)置指令可不行,還需要在組件中使用route規(guī)則, 來(lái)處理頁(yè)面滾動(dòng)的操作, 局部滾動(dòng)條直接去掉.window即可 如果需要同時(shí)記錄全局滾動(dòng)條和div滾動(dòng)條直接設(shè)置.window.self即可 它能做到N多個(gè)滾動(dòng)位置記錄,具體看官方文檔喔! 注:記錄div滾動(dòng)的話,需要設(shè)置一個(gè)name來(lái)識(shí)別 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看起來(lái)也不是很復(fù)雜,只需要定義好模塊狀態(tài),然后在組件中設(shè)置對(duì)應(yīng)的規(guī)則來(lái)更新模塊的狀態(tài)即可。其實(shí)vuet自帶的route規(guī)則能夠支持同時(shí)記錄全局滾動(dòng)條、div自身的滾動(dòng)條,這樣就能大大的提升了我們的用戶體驗(yàn)
到此這篇關(guān)于Vue.js輕松實(shí)現(xiàn)頁(yè)面后退時(shí),還原滾動(dòng)位置的文章就介紹到這了,更多相關(guān)js生成二維碼或條形碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS實(shí)現(xiàn)動(dòng)態(tài)給標(biāo)簽控件添加事件的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)動(dòng)態(tài)給標(biāo)簽控件添加事件的方法,結(jié)合實(shí)例形式分析了javascript簡(jiǎn)單實(shí)現(xiàn)動(dòng)態(tài)添加事件的相關(guān)操作技巧,需要的朋友可以參考下2017-05-05js驗(yàn)證框架之RealyEasy驗(yàn)證詳解
這篇文章主要為大家詳細(xì)介紹了js驗(yàn)證框架之RealyEasy驗(yàn)證,記錄了RealyEasy驗(yàn)證的使用步驟,感興趣的小伙伴們可以參考一下2016-06-06javascript實(shí)現(xiàn)攝像頭拍照預(yù)覽
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)攝像頭拍照預(yù)覽,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09Javascript 寫的簡(jiǎn)單進(jìn)度條控件
2008-01-01Bootstrap 模態(tài)對(duì)話框只加載一次 remote 數(shù)據(jù)的完美解決辦法
前端框架 Bootstrap 的模態(tài)對(duì)話框,可以使用 remote 選項(xiàng)指定一個(gè) URL,這樣對(duì)話框在第一次彈出的時(shí)候就會(huì)自動(dòng)從這個(gè)地址加載數(shù)據(jù)到 .modal-body 中,但是它只會(huì)加載一次,不過(guò)通過(guò)在事件中調(diào)用 removeData() 方法可以解決這個(gè)問(wèn)題,具體操作方法,大家通過(guò)本文了解下吧2017-07-07CryptoJS中AES實(shí)現(xiàn)前后端通用加解密技術(shù)
這篇文章主要為大家詳細(xì)介紹了CryptoJS中AES實(shí)現(xiàn)前后端通用加解密技術(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12使用JS代碼實(shí)現(xiàn)點(diǎn)擊按鈕下載文件
有時(shí)候我們?cè)诰W(wǎng)頁(yè)上需要增加一個(gè)下載按鈕,讓用戶能夠點(diǎn)擊后下載頁(yè)面上的資料,那么怎樣才能實(shí)現(xiàn)功能呢?今天小編給大家分享兩種方法實(shí)現(xiàn)js實(shí)現(xiàn)點(diǎn)擊按鈕下載文件,需要的朋友參考下吧2016-11-11