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

