深入了解vue-router原理并實(shí)現(xiàn)一個(gè)小demo
插件編寫的基本方法
推薦大家先看看官方給出的插件使用和開發(fā)方法
https://vuejs.bootcss.com/guide/plugins.html?
需求分析
我們先看看vue-router的使用步驟
1.use
Vue.use(VueRouter)
注意??:
Vue.use()主要是調(diào)用插件內(nèi)部的install方法,并將Vue實(shí)例作為參數(shù)傳入?
2.new 一個(gè)router實(shí)例
const router = new VueRouter({
// 實(shí)例化router傳入的參數(shù)
mode: 'history',
base: process.env.BASE_URL,
routes
})
3.new Vue() ,把實(shí)例放在vue的配置項(xiàng)里面
new Vue({
router, // 注意router的實(shí)例也往里傳
render: h => h(App)
}).$mount('#app')
4.使用路由組件<router-view/>、<router-link></router-link>或者在組件中使用this.$router
由此我們看看vue-router內(nèi)部做了什么?
將$router掛載到全局上實(shí)現(xiàn)并聲明了兩個(gè)組件:<router-view/>、<router-link></router-link>?
實(shí)現(xiàn)思路
首先我們看看如何將$router掛載到組件上?
let Vue; // 保存vue的構(gòu)造函數(shù),避免打包將其打進(jìn)去
VueRouter.install = function (_Vue) {
Vue = _Vue;
console.log("options", Vue.$options);
Vue.mixin({
beforeCreate() {
console.log("inner", this);
console.log(" this.$options.router", this.$options.router);
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
console.log("end");
};

可以看到:
1、第一次執(zhí)行的時(shí)候,即在Vue.use(Router)時(shí),還沒有實(shí)例化vue(因?yàn)?code>Vue.use()發(fā)生在 new Vue()之前),所以Vue.$option本身是拿不到的(ps: option就是new Vue()時(shí)傳入的參數(shù),router也往里面?zhèn)鳎?,此時(shí)既然拿不到router的實(shí)例,所以不能直接在install方法里面掛載;?
?2、我們可以在use的時(shí)候做一個(gè)全局混入,在合適的時(shí)間點(diǎn),獲取到Vue根實(shí)例配置項(xiàng)中的router實(shí)例, 執(zhí)行掛載。緊接著在new Vue()根實(shí)例創(chuàng)建的時(shí)候,因?yàn)樽⑷肓藃outer實(shí)例,所以再執(zhí)行全局混入(mixin)中的生命周期時(shí),這個(gè)時(shí)候根實(shí)例的配置項(xiàng)this.$options已經(jīng)包含了router實(shí)例,可以此時(shí)把router掛載到Vue的原型上。之后所有Vue實(shí)例擴(kuò)展來的VueCompont都可以通過this.$router訪問到這個(gè)屬性
?如何實(shí)現(xiàn)那兩個(gè)路由組件
先看看路由組件如何使用
<div id="app">
<div id="nav">
<!-- a標(biāo)簽控制跳轉(zhuǎn) -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<!-- 路由出口 -->
<router-view />
</div>
由上面可以看出,點(diǎn)擊router-link,就相當(dāng)于點(diǎn)了a標(biāo)簽,然后a標(biāo)簽的href屬性控制頁(yè)面路由發(fā)生了變化;監(jiān)聽路由變化,然后仔router-view里面輸出不同的模板;?
先來看看router-link
class VueRouter {
constructor(options) {
// 接受傳入的參數(shù)
this.$options = options;
const initial = "/";
// 將current變成響應(yīng)式數(shù)據(jù),
//這樣在hashchange的回掉中修改curent時(shí),
//用到current的router-view的render函數(shù)就會(huì)重新渲染
Vue.util.defineReactive(this, "current", initial);
// 監(jiān)聽路由變化
window.addEventListener("hashchange", () => {
// 獲取當(dāng)前url中的hash
this.current = window.location.hash.slice(1);
});
}
}
VueRouter.install = function (_Vue) {
Vue = _Vue;
Vue.component("router-view", {
render(h) {
// 獲取當(dāng)前路由所對(duì)應(yīng)的組件,然后把它渲染出來
const { current, $options } = this.$router;
// 這里要注意 我們傳進(jìn)來的routes是一個(gè)路由表,如下圖一
// 所以這里我們是找出匹配到當(dāng)前current路由的項(xiàng),然后直接渲染組件
const route = $options.routes.find((item) => {
return item.path === current;
});
let component = route ? route.component : null;
return h(component);
},
});
}
?再來看看router-view
class VueRouter {
constructor(options) {
// 接受傳入的參數(shù)
this.$options = options;
const initial = "/";
// 將current變成響應(yīng)式數(shù)據(jù),
//這樣在hashchange的回掉中修改curent時(shí),
//用到current的router-view的render函數(shù)就會(huì)重新渲染
Vue.util.defineReactive(this, "current", initial);
// 監(jiān)聽路由變化
window.addEventListener("hashchange", () => {
// 獲取當(dāng)前url中的hash
this.current = window.location.hash.slice(1);
});
}
}
VueRouter.install = function (_Vue) {
Vue = _Vue;
Vue.component("router-view", {
render(h) {
// 獲取當(dāng)前路由所對(duì)應(yīng)的組件,然后把它渲染出來
const { current, $options } = this.$router;
// 這里要注意 我們傳進(jìn)來的routes是一個(gè)路由表,如下圖一
// 所以這里我們是找出匹配到當(dāng)前current路由的項(xiàng),然后直接渲染組件
const route = $options.routes.find((item) => {
return item.path === current;
});
let component = route ? route.component : null;
return h(component);
},
});
}
圖一

完整demo代碼
// 我們要實(shí)現(xiàn)什么
// 1、插件
// 2、兩個(gè)組件
// 保存vue的構(gòu)造函數(shù),避免打包將其打進(jìn)去
let Vue;
class VueRouter {
constructor(options) {
this.$options = options;
const initial = "/";
Vue.util.defineReactive(this, "current", initial);
this.current = "/";
window.addEventListener("hashchange", () => {
// 獲取當(dāng)前url中的hash
this.current = window.location.hash.slice(1);
});
}
}
// 參數(shù)1在Vue.use()調(diào)用時(shí)傳進(jìn)來,
VueRouter.install = function (_Vue) {
Vue = _Vue;
console.log("options", this);
// 全局混入
// 目的:延遲下面的邏輯 到 router創(chuàng)建完畢并且附加到選項(xiàng)上時(shí)才執(zhí)行
Vue.mixin({
// 在每個(gè)組件創(chuàng)建實(shí)例時(shí)都會(huì)執(zhí)行
beforeCreate() {
// this.$options.router ;即new Vue時(shí)放進(jìn)去的router實(shí)例
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
// 注冊(cè)并且實(shí)現(xiàn)兩個(gè)組件
Vue.component("router-link", {
props: {
to: {
required: true,
},
},
render(h) {
return h(
"a",
{
attrs: { href: "#" + this.to },
},
this.$slots.default
);
},
});
Vue.component("router-view", {
render(h) {
// 獲取當(dāng)前路由所對(duì)應(yīng)的組件,然后把它渲染出來
const { current, $options } = this.$router;
const route = $options.routes.find((item) => {
return item.path === current;
});
let component = route ? route.component : null;
return h(component);
},
});
};
export default VueRouter;
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
vue 對(duì)axios get pust put delete封裝的實(shí)例代碼
在本篇文章里我們給各位整理的是一篇關(guān)于vue 對(duì)axios get pust put delete封裝的實(shí)例代碼內(nèi)容,有需要的朋友們可以參考下。2020-01-01
Vue使用Axios庫(kù)請(qǐng)求數(shù)據(jù)時(shí)跨域問題的解決方法詳解
在 VUE 項(xiàng)目開發(fā)時(shí),遇到個(gè)問題,正常設(shè)置使用 Axios 庫(kù)請(qǐng)求數(shù)據(jù)時(shí),報(bào)錯(cuò)提示跨域問題,那在生產(chǎn)壞境下,該去怎么解決呢?下面小編就來和大家詳細(xì)講講2024-01-01
詳解mpvue中使用vant時(shí)需要注意的onChange事件的坑
這篇文章主要介紹了詳解mpvue中使用vant時(shí)需要注意的onChange事件的坑,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05
vue中el-autocomplete支持分頁(yè)上拉加載功能
最近在項(xiàng)目中使用了ElementUI的el-autocomplete,下面這篇文章主要介紹了vue中el-autocomplete支持分頁(yè)上拉加載功能的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11
實(shí)現(xiàn)一個(gè)Vue版Upload組件
這篇文章主要介紹了實(shí)現(xiàn)一個(gè)Vue版Upload組件,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
Vue+ElementUI?封裝簡(jiǎn)易PaginationSelect組件的詳細(xì)步驟
這篇文章主要介紹了Vue+ElementUI?封裝簡(jiǎn)易PaginationSelect組件,這里簡(jiǎn)單介紹封裝的一個(gè)Pagination-Select組件幾個(gè)步驟,結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08

