vue中兩種路由模式的實現(xiàn)詳解
平時我們編寫路由時,通常直接下載插件使用,在main.js文件中引入直接通過引入vue-router中的Router通過Vue.use使用以后定義一個routeMap數(shù)組,里邊是我們編寫路由的地方,最后通過實例化一個 Router實例 將routes=我們定義的routeMao路由數(shù)組。
但是我們并不知道它是如何實現(xiàn)的,因此我們可以通過自己編寫插件的形式,實現(xiàn)一個vue-router
常用路由步驟:
//router/index.js import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export const routeMap= [ { path: '/home', component: () => import('../components/Home/Home.vue') }, { path: '/list', component: () => import('../components/List/List.vue') }, ] const router = new Router({ routes: constantRouterMap }) export default router //main.js import router from './router' new Vue({ router, store, render: h => h(App), }).$mount('#app')
我們來實現(xiàn)一下如何實現(xiàn)一個hash模式的路由
由于我們不適用插件形式實現(xiàn),因此我們使用步驟與平常實現(xiàn)有一些差異。
router/index.js是我們的路由文件,里面放置我們的路由
plugin/router.js是我們的自定義插件文件,里面放置我們自定義插件內(nèi)容
components是我們組件目錄,放置我們的路由組件(通常使用view定義路由組件)
main.js是我們的入口文件,需要在該文件引入router并且實例化vue的時候需要將引入的router使用
1、首先我們在App.vue文件中,通過<router-view/>以及<router-link/>定義聲明式導航和路由占位
<div> <router-link to="/home">首頁</router-link> <router-link to="/list">列表</router-link> <hr> <router-view></router-view> </div>
這里我們會發(fā)現(xiàn)使用以后會報錯,因為我們沒有下載插件,因此沒有這兩個組件。
我們需要配置plugin插件
由于沒有這兩個全局組件因此我們需要配置兩個全局組件
install方法是為了將我們的路由掛載在我們的組件實例上,通過mixin全局混入,將我們的實例上掛載$router屬性
然后定義兩個全局組件,router-link由于它渲染出來相當于html中的a標簽,使用render方法,參數(shù)為一個createElement方法接收三個參數(shù)(第一個參數(shù)創(chuàng)建的元素,第二個參數(shù)元素具有的屬性, 第三個參數(shù)元素的內(nèi)容)
router-view由于是一個路由占位符,因此返回的是個組件,渲染組件。
通過routesMap是我們存放的路由,current是我們的當前的path路由,因此可以通過查找路由中key值為我們當前path路徑的,查找到我們的組件。通過return渲染我們的組件
VueRouter.install = function (_Vue) { //1、保存Vue Vue = _Vue //2、將以下代碼延遲到vue實例初始化完畢執(zhí)行 Vue.mixin({ beforeCreate() { //判斷如果有router屬性就執(zhí)行下方代碼 if (this.$options.router) { Vue.prototype.$router = this.$options.router; } } }) //創(chuàng)建全局組件router-link和router-view //創(chuàng)建router-link組件 Vue.component('router-link', { props: { to: { type: String | Object, required: true } }, render(h) {// h 有三個參數(shù),第一個參數(shù)創(chuàng)建的元素,第二個參數(shù)元素具有的屬性, 第三個參數(shù)元素的內(nèi)容 return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default) } }) //創(chuàng)建router-view組件 Vue.component('router-view', { // 組件要重新渲染,必須要讓數(shù)據(jù)發(fā)生改變的時候,重新去執(zhí)行render函數(shù) render(h) { const router = this.$router console.log(router.routesMap, 'routesMap'); let component = router.routesMap[router.current];//組件 //獲取到外部傳遞的路由表 return h(component) } }) }
2、我們定義一個路由類,該類會獲取到我們的路由信息從而進行路由監(jiān)聽以及組件渲染。
(1)、該類中constructor是我們通過實例化vueRouter傳入的數(shù)據(jù),我們需要通過將數(shù)據(jù)保存在vueRouter實例上,獲取到當前的url path路徑。
(2)、通過監(jiān)聽方法hashchange監(jiān)聽我們hash值的變化,通過方法進行監(jiān)聽,但是一定要注意這里方法的this指向必須是vueRouter實例不可以是window,因此需要通過bind改變this指向
(3)、通過defineReactive來講我們的path路徑變?yōu)轫憫?yīng)式,這樣每次路徑發(fā)生變化可以監(jiān)測到變化。
(4)、定義routesMap為我們的路由對象,遍歷我們傳入的路由數(shù)組,將我們每個path路徑對應(yīng)組件,為一組一組的鍵值對。
這樣可以實現(xiàn)一套hash路由模式的路由跳轉(zhuǎn)。
全部代碼如下:
//plugin/router.js let Vue; class VueRouter { constructor(options) { //保存選項 this.options = options; // console.log(options, '路由數(shù)據(jù)'); // 定義一個響應(yīng)式的變量current,保存當前的hash值 let url = location.hash.slice(1,) || '/'; // defineReactive定義響應(yīng)式的對象 Vue.util.defineReactive(this, 'current', url) // hashchange事件來監(jiān)聽hash值的變化, 注意this指向問題 addEventListener('hashchange', this.changeHash.bind(this)) this.routesMap = {}; //對routes中的對象做一個映射:routesMap = {'/home':component,'/list': component} this.options.routes.forEach(route => { this.routesMap[route.path] = route.component }) } //監(jiān)聽hash值變化的函數(shù) changeHash() { //通過location.hash來獲取到hash值 this.current = location.hash.slice(1,) console.log(this.routesMap, '555'); // console.log(this.current);//當前path路徑 } } VueRouter.install = function (_Vue) { //1、保存Vue Vue = _Vue //2、將以下代碼延遲到vue實例初始化完畢執(zhí)行 Vue.mixin({ beforeCreate() { //判斷如果有router屬性就執(zhí)行下方代碼 if (this.$options.router) { Vue.prototype.$router = this.$options.router; } } }) //創(chuàng)建全局組件router-link和router-view //創(chuàng)建router-link組件 Vue.component('router-link', { props: { to: { type: String | Object, required: true } }, render(h) {// h 有三個參數(shù),第一個參數(shù)創(chuàng)建的元素,第二個參數(shù)元素具有的屬性, 第三個參數(shù)元素的內(nèi)容 return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default) } }) //創(chuàng)建router-view組件 Vue.component('router-view', { // 組件要重新渲染,必須要讓數(shù)據(jù)發(fā)生改變的時候,重新去執(zhí)行render函數(shù) render(h) { const router = this.$router console.log(router.routesMap, 'routesMap'); let component = router.routesMap[router.current];//組件 console.log(component, 'component'); //獲取到外部傳遞的路由表 return h(component) } }) } export default VueRouter;
接下來實現(xiàn)歷史路由模式
我們知道歷史路由模式和hash路由模式區(qū)別是域名是否存在#因此我們可以通過在路由文件中定義mode屬性判斷是歷史路由模式還是hash路由模式。
先大白話來說一下大概的實現(xiàn)思路(hash和history實現(xiàn)區(qū)別):
1、我們通過我們定義的mode判斷是hash路由模式還是history路由模式,router-link點擊跳轉(zhuǎn)的時候如果是hash路由模式,我們通過render方法返回我們渲染到瀏覽器域名的數(shù)據(jù),hash模式是帶#的,因此我們定義href屬性需要+#,但是history模式是不帶#的,因此我們不需要加#。其次,因為hash模式自動檢測我們的域名,因此我們實現(xiàn)歷史模式需要手動加一個點擊事件,并且需要阻止a鏈接默認跳轉(zhuǎn)的行為(preventDefault取消默認行為),并且通過pushState方法,實現(xiàn)跳轉(zhuǎn),這是歷史路由模式的方法pushState(obj,title,url),最后設(shè)置我們的路由當前path路徑為我們跳轉(zhuǎn)的路徑。
2、當我們定義好它的router-link全局組件以后,這時我們hash路由模式和history路由模式已經(jīng)可以基本實現(xiàn),hash模式帶#,history路由模式不帶#。但是我們?nèi)砸x一個監(jiān)聽歷史路由模式變化的監(jiān)聽事件。這里我們通過mode判斷是什么模式從而監(jiān)聽不同的事件,歷史路由模式監(jiān)聽需要通過監(jiān)聽popState方法,來判斷是否發(fā)生變化,它堅挺的是我們?yōu)g覽器的前進后退的變化。
歷史路由模式監(jiān)聽事件為hashchange方法,這個事件是用來監(jiān)聽我們hash值的變化,通過設(shè)置兩個方法從而設(shè)置我們當前路徑為對應(yīng)的path路徑。hash模式會通過slice剪切到#,歷史路由模式則通過location.pathname獲取到當前path路徑。
實現(xiàn)如下:
let Vue; class VueRouter { constructor(options) { //保存選項 this.options = options; // console.log(options, '路由數(shù)據(jù)'); // 定義一個響應(yīng)式的變量current,保存當前的hash值 let url = location.hash.slice(1,) || '/'; // defineReactive定義響應(yīng)式的對象 Vue.util.defineReactive(this, 'current', url) //判斷當前的路由模式 if (this.options.mode === 'hash') { // hashchange事件來監(jiān)聽hash值的變化, 注意this指向問題 addEventListener('hashchange', this.changeHash.bind(this)) } else if (this.options.mode === 'history') { // history模式監(jiān)聽的事件叫做:popstate, 監(jiān)聽的是瀏覽器左上角的兩個小箭頭的變化 addEventListener('popstate', this.changeHistory.bind(this)) } this.routesMap = {}; //對routes中的對象做一個映射:routesMap = {'/home':component,'/list': component} this.options.routes.forEach(route => { this.routesMap[route.path] = route.component }) } //監(jiān)聽hash值變化的函數(shù) changeHash() { //通過location.hash來獲取到hash值 this.current = location.hash.slice(1,) console.log(this.routesMap, '555'); // console.log(this.current);//當前path路徑 } // history changeHistory() { // console.log(location.pathname) this.current = location.pathname; } }
VueRouter.install = function (_Vue) { //1、保存Vue Vue = _Vue //2、將以下代碼延遲到vue實例初始化完畢執(zhí)行 Vue.mixin({ beforeCreate() { //判斷如果有router屬性就執(zhí)行下方代碼 if (this.$options.router) { Vue.prototype.$router = this.$options.router; } } }) //創(chuàng)建全局組件router-link和router-view //創(chuàng)建router-link組件 Vue.component('router-link', { props: { to: { type: String | Object, required: true } }, render(h) {// h 有三個參數(shù),第一個參數(shù)創(chuàng)建的元素,第二個參數(shù)元素具有的屬性, 第三個參數(shù)元素的內(nèi)容 const router = this.$router; if (router.options.mode === 'hash') { return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default) } else if (router.options.mode === 'history') { return h('a', { attrs: { href: this.to }, on: { 'click': ev => { // 1. 阻止a鏈接的默認跳轉(zhuǎn)行為 ev.preventDefault() // 2. 調(diào)用pushState方法來實現(xiàn)跳轉(zhuǎn): pushState(obj, title, url) history.pushState({}, '', this.to) // 3. 設(shè)置current的值 router.current = this.to; } } }, this.$slots.default) } } }) //創(chuàng)建router-view組件 Vue.component('router-view', { // 組件要重新渲染,必須要讓數(shù)據(jù)發(fā)生改變的時候,重新去執(zhí)行render函數(shù) render(h) { const router = this.$router console.log(router.routesMap, 'routesMap'); let component = router.routesMap[router.current];//組件 console.log(component, 'component'); //獲取到外部傳遞的路由表 return h(component) } }) }
這一期我們講解了,如何實現(xiàn)一個基本的hash路由模式以及history路由模式,但是我們通常使用情況下路由嵌套通過一級路由下定義children屬性來定義二級路由,這并沒有實現(xiàn),下一期來實現(xiàn)路由嵌套。
到此這篇關(guān)于vue中兩種路由模式的實現(xiàn)詳解的文章就介紹到這了,更多相關(guān)vue路由模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli2.x項目優(yōu)化之引入本地靜態(tài)庫文件的方法
這篇文章主要介紹了vue-cli2.x項目優(yōu)化之引入本地靜態(tài)庫文件的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06vue?模板循環(huán)繪制多行上傳文件功能實現(xiàn)
這篇文章主要為大家介紹了vue?模板循環(huán)繪制多行上傳文件功能實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07vue項目中如何實現(xiàn)網(wǎng)頁的截圖功能?(html2canvas)
這篇文章主要介紹了vue項目中如何實現(xiàn)網(wǎng)頁的截圖功能?(html2canvas),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02網(wǎng)站國際化多語言處理工具i18n安裝使用方法圖文詳解
國際化是設(shè)計軟件應(yīng)用的過程中應(yīng)用被使用與不同語言和地區(qū),下面這篇文章主要給大家介紹了關(guān)于網(wǎng)站國際化多語言處理工具i18n安裝使用方法的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-09-09Vue2.0結(jié)合webuploader實現(xiàn)文件分片上傳功能
這篇文章主要介紹了Vue2.0結(jié)合webuploader實現(xiàn)文件分片上傳功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-03-03vue2中provide/inject的使用與響應(yīng)式傳值詳解
Vue中 Provide/Inject實現(xiàn)了跨組件的通信,下面這篇文章主要給大家介紹了關(guān)于vue2中provide/inject的使用與響應(yīng)式傳值的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-09-09