vue-router
Vue Router 是 Vue.js 官?的路由管理器,它和 Vue.js 的核?深度集成,讓構建單頁面應用變得易如反掌,
- 嵌套的路由/視圖表
- 模塊化的、基于組件的路由配置
- 路由引數、查詢、通配符
- 基于 Vue.js 過渡系統的視圖過渡效果
- 細粒度的導航控制
- 帶有自動激活的 CSS class 的鏈接
- HTML5 歷史模式或 hash 模式,在 IE9 中自動降級
- 自定義的滾動條行為
安裝: vue add router
核?步驟:
步驟?:使?vue-router插件,router.js
import Router from 'vue-router'
Vue.use(Router)
步驟二: 宣告一個路由表(是一個映射表,path和組件是一個映射關系)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
步驟三:創建Router實體,router.js(然后匯出)
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
步驟四: 在根組件上添加該實體,main.js
import router from './router'
new Vue({
router,
}).$mount("#app")
步驟五: 添加路由視圖,App.vue
<router-view></router-view>
導航鏈接
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
以上大概是vue-router的基本使用,下面進入簡版原始碼實作部分
vue-router原始碼實作
需求分析
- spa 頁面不能重繪
- hash方式 例如: #/home
- 或者History api 例如: /about
- 根據url顯示對應的內容
- router-view
- 資料回應式: current變數持有url地址,一旦變化,動態重新執行render
任務
- 實作一個插件(創建VueRouter類和install?法)
- 實作VueRouter類
- 處理路由選項
- 監控url的變化
- 相應變化
- 實作一個install 方法
- $router的注冊
- 兩個全域組件
- 實作VueRouter類
創建kvue-router.js
let Vue; // 引?建構式,VueRouter中要使?
// 保存選項
class VueRouter {
constructor(options) {
this.$options = options;
}
}
// 插件:實作install?法,注冊$router
VueRouter.install = function(_Vue) {
// 引?建構式,VueRouter中要使?
Vue = _Vue;
// 任務1:掛載$router
Vue.mixin({
beforeCreate() {
// 只有根組件擁有router選項
if (this.$options.router) {
// vm.$router
Vue.prototype.$router = this.$options.router;
}
}
});
// 任務2:實作兩個全域組件router-link和router-view
Vue.component('router-link', Link)
Vue.component('router-view', View)
};
export default VueRouter;
為什么要?混??式寫?主要原因是use代碼在前,Router實體創建在后,?install邏輯?需要? 到該實體,這里是一個比較巧妙的方法(主要是為了延遲執行)
創建router-view和router-link
創建krouter-link.js
export default {
// 定義傳入的引數
props: {
to: {
type: String,
require: true
}
},
render(h) {
// <router-link to="/home"/>
// <a href="#/home">XXX</a>
// 通用性更好
return h('a',{
attrs: {
href: '#' + this.to
}
}, this.$slots.default)
// 需要當前環境支持jsx
// return <a href={'#' + this.to}> {this.$slots.default}</a>
}
}
創建krouter-view.js
export default {
render(h) {
// 暫時先不渲染任何內容
return h(null);
}
}
監控url變化
定義回應式的current屬性,監聽hashchange事件
class VueRouter {
constructor(options) {
// current應該是回應式的
Vue.util.defineReactive(this, 'current', '/')
// 定義回應式的屬性current
const initial = window.location.hash.slice(1) || '/'
Vue.util.defineReactive(this, 'current', initial)
// 監聽hashchange事件
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
}
onHashChange() {
this.current = window.location.hash.slice(1)
}
}
動態獲取對應組件,krouter-view.js
export default {
render(h) {
// 動態獲取對應組件
let component = null;
this.$router.$options.routes.forEach(route => {
if (route.path === this.$router.current) {
component = route.component
}
});
return h(component);
}
}
提前處理路由表
提前處理路由表避免每次都回圈
class VueRouter {
constructor(options) {
// 快取path和route映射關系
this.routeMap = {}
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
});
}
}
使?,krouter-view.js
export default {
render(h) {
const {routeMap, current} = this.$router
const component = routeMap[current] ? routeMap[current].component : null;
return h(component);
}
}
下面附上完整代碼
// 實作一個插件
// 1. 回傳一個函式
// 2. 或者回傳一個物件,它有一個install方法
let _Vue = null
/**
* @class VueRouter
* @param options 選項
*/
class VueRouter {
constructor(options) {
// options 配置選項: router - 路由表
this.$options = options
// 快取path 和route的映射關系
this.routeMap = {}
// 找到當前url對于的組件
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
})
// 需要定義一個回應式的current屬性
const initial = window.location.hash.slice(1) || '/'
// defineReactive 給一個物件定義回應式資料
_Vue.util.defineReactive(this, 'current', initial)
// 監控url的變化
window.addEventListener('hashchange', this.onHashChange.bind(this))
}
onHashChange () {
this.current = window.location.hash.slice(1)
console.log(this.current)
}
}
VueRouter.install = function(Vue) {
// 參考Vue建構式,在上面的VueRouter中使用
_Vue= Vue
// 1. 掛載$router
// 利用混入,延遲執行
Vue.mixin({
// 此處的this 指的是vue根實體
beforeCreate() {
if(this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
// 2. 定義兩個全域組件router-link, router-view
Vue.component('router-link', {
// 定義傳入的引數
props: {
to: {
type: String,
require: true
}
},
render(h) {
// <router-link to="/home"/>
// <a href="#/home">XXX</a>
// 通用性更好
return h('a',{
attrs: {
href: '#' + this.to
}
}, this.$slots.default)
// 需要當前環境支持jsx
// return <a href={'#' + this.to}> {this.$slots.default}</a>
}
})
Vue.component('router-view', {
render(h) {
// 找到當前的url對應的組件
const { routeMap, current } = this.$router
const component = routeMap[current] ? routeMap[current].component : null
return h(component)
}
})
}
export default VueRouter
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/210128.html
標籤:其他
下一篇:原生JS實作彈幕的簡單操作速成
