>[success] # vueRouter -- 簡單實現
1. 這里實現按照 `router 3.x` 配合 `vue2.x `的一個簡單實現模型
2. 如果你已經使用過 `vuerouter `或者正在學習如何使用,你要知道第一點就是為什么綁定在根實例上的`vuerouter `可以在任何組件都能調用它,以`vue2.x` 為例
~~~
const router = new VueRouter({
routes // (縮寫) 相當于 routes: routes
});
const vm = new Vue({
router, // vue2 使用路由
ccc: 'ccc',
render: h => h(App)
}).$mount('#app')
~~~
* 此時`router `已經在`vue `實例上

* 注冊組件`$opitions`中可以通過`$opitions`中的`parent `字段一級一級往上推找到最開始的根 `new Vue`這個對象,因此每個組件都能用到`vuerouter `實例

>[info] ## 簡單實現
1. 關于整個類的參數定義介紹
~~~
'data':
options - 記錄構造函數中傳入的對象
data - 是一個對象包含current 記錄當前的路由地址, 調用Vue.observable方法將其設置為響應式對象
routeMap - 記錄路由地址與組件的對應關系,將路由規則解析到這里
'methods': +號是公共方法 _ 是靜態方法
+Constructor(Options): VueRouter - 初始化options
_install(Vue): void - 實現vue插件的機制
+init(): void - 用于調用下面三個方法
+initEvent(): void - 用于實現popState方法, 監聽瀏覽器歷史的變化
+createRouteMap(): void - 初始化routemap屬性,將options轉換成鍵值對存儲到routemap中 ,
鍵為路由地址,值為對應組件
+initComponents(Vue): void - 創建router-link 和 router-view兩個組件
~~~
~~~
// 實現Vue插件機制
static install(Vue) {
// 1. 判斷當前插件是否被安裝 用于是否需要安裝
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
// 2. 把Vue構造函數記錄到全局變量 用于使用Vue構造函數相關方法
_Vue = Vue
// 3. 創建Vue實例時傳入的router對象注入到所有的Vue實例中 可以使用this.$router
// _Vue.prototype.$router = this.$options.router // this指向VueRouter
// 使用混入獲取Vue實例 所有Vue實例混入選項
_Vue.mixin({
// beforeCreate鉤子,實例創建前執行,添加router對象
beforeCreate() {
// Vue實例執行 Vue組件不執行 避免重復執行
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
this.$options.router.init()
}
}
})
}
~~~
>[danger] ##### initComponents
~~~
1.這里還需要創建'router-link'和'router-view
' 兩個組件,配合路由的使用
~~~
~~~
// 創建兩個組件 router-link與router-view
initComponents(Vue) {
// 創建router-link 接收路由地址 并且本質為超鏈接
// 此處超鏈接跳轉會向服務器發送請求 單頁面不需要發送服務器請求
// 因此攔截超鏈接跳轉并修改地址欄中的地址 使用history.pushState 并且將記錄到data中current中
Vue.component('router-link', {
props: {
to: String
},
// 使用插槽,在使用時會將內容填充到插槽中
// 運行時版本 不支持template
// template: '<a :href="to"><slot></slot></a>'
render(h) {
// h函數傳入三個參數 第一個為創建標簽 第二個為標簽屬性或事件 第三個參數為為數組 是生成元素的子元素
return h('a', {
// 標簽屬性
attrs: {
href: this.to
},
// 注冊點擊事件
on: {
click: this.clickHandler
}
// 獲取默認插槽的值 未起名
}, [this.$slots.default])
},
// 事件處理的方法
methods: {
clickHandler(e) {
// 改變地址欄中的地址 不發送服務器請求
history.pushState({}, '', this.to)
// 將地址記錄到當前路由數據中
this.$router.data.current = this.to
// 阻止事件的默認行為
e.preventDefault()
}
}
})
// 存儲vuerouter實例
const self = this
// 創建router-view 占位符 根據當前路由地址渲染相應路由
Vue.component('router-view', {
render(h) {
// 找到當前路由地址 然后再routeMap對象中查找對應的組件
const component = self.routeMap[self.data.current]
// 然后調用h函數轉換為虛擬Dom直接返回
return h(component)
}
})
}
~~~
>[danger] ##### 整體代碼
~~~
// 記錄傳入的Vue 構造函數
let _Vue = null
export default class VueRouter {
// 實現Vue插件機制
static install(Vue) {
// 1. 判斷當前插件是否被安裝 用于是否需要安裝
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
// 2. 把Vue構造函數記錄到全局變量 用于使用Vue構造函數相關方法
_Vue = Vue
// 3. 創建Vue實例時傳入的router對象注入到所有的Vue實例中 可以使用this.$router
// _Vue.prototype.$router = this.$options.router // this指向VueRouter
// 使用混入獲取Vue實例 所有Vue實例混入選項
_Vue.mixin({
// beforeCreate鉤子,實例創建前執行,添加router對象
beforeCreate() {
// Vue實例執行 Vue組件不執行 避免重復執行
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
this.$options.router.init()
}
}
})
}
// Vue Router 構造函數 返回Vue Router
// 初始化vue router 三個屬性
constructor(options) {
// vue router 規則
this.options = options
// 將規則以鍵值對的方式存儲 鍵為路由地址 值為路由組件
// 根據鍵值對查找路由組件進行渲染
this.routeMap = {}
// 響應式對象 current用于記錄當前路由地址 默認為‘/’根目錄
// Vue.observable()將傳入對象轉換為響應式對象
this.data = _Vue.observable({
current: '/'
})
}
// 將下面的初始化方法整合到一起
init() {
this.createRouteMap()
this.initComponents(_Vue)
this.initEvent()
}
// 將options路由規則轉換為鍵值對存儲
createRouteMap() {
// 遍歷所有路由規則,把路由規則解析成鍵值對的形式存儲到routeMap中
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
// 創建兩個組件 router-link與router-view
initComponents(Vue) {
// 創建router-link 接收路由地址 并且本質為超鏈接
// 此處超鏈接跳轉會向服務器發送請求 單頁面不需要發送服務器請求
// 因此攔截超鏈接跳轉并修改地址欄中的地址 使用history.pushState 并且將記錄到data中current中
Vue.component('router-link', {
props: {
to: String
},
// 使用插槽,在使用時會將內容填充到插槽中
// 運行時版本 不支持template
// template: '<a :href="to"><slot></slot></a>'
render(h) {
// h函數傳入三個參數 第一個為創建標簽 第二個為標簽屬性或事件 第三個參數為為數組 是生成元素的子元素
return h('a', {
// 標簽屬性
attrs: {
href: this.to
},
// 注冊點擊事件
on: {
click: this.clickHandler
}
// 獲取默認插槽的值 未起名
}, [this.$slots.default])
},
// 事件處理的方法
methods: {
clickHandler(e) {
// 改變地址欄中的地址 不發送服務器請求
history.pushState({}, '', this.to)
// 將地址記錄到當前路由數據中
this.$router.data.current = this.to
// 阻止事件的默認行為
e.preventDefault()
}
}
})
// 存儲vuerouter實例
const self = this
// 創建router-view 占位符 根據當前路由地址渲染相應路由
Vue.component('router-view', {
render(h) {
// 找到當前路由地址 然后再routeMap對象中查找對應的組件
const component = self.routeMap[self.data.current]
// 然后調用h函數轉換為虛擬Dom直接返回
return h(component)
}
})
}
// 注冊popState事件 處理前進和后退沒有加載相應組件的問題
initEvent() {
window.addEventListener('popstate', () => {
// 此處this指向vuerouter
// 將data中當前路由指向更改
this.data.current = window.location.pathname
})
}
}
~~~
- 官網給的工具
- 聲明vue2 和 vue3
- 指令速覽
- Mustache -- 語法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 顯示原始的Mustache標簽
- v-cloak -- 遮蓋
- v-memo(新)-- 緩存指定值
- v-if/v-show -- 條件渲染
- v-for -- 循環
- v-bind -- 知識
- v-bind -- 修飾符
- v-on -- 點擊事件
- v-model -- 雙向綁定
- 其他基礎知識速覽
- 快速使用
- 常識知識點
- key -- 作用 (后續要更新)
- computed -- 計算屬性
- watch -- 偵聽
- 防抖和節流
- vue3 -- 生命周期
- vue-cli 和 vite 項目搭建方法
- vite -- 導入動態圖片
- 組件
- 單文件組件 -- SFC
- 組件通信 -- porp
- 組件通信 -- $emit
- 組件通信 -- Provide / Inject
- 組件通信 -- 全局事件總線mitt庫
- 插槽 -- slot
- 整體使用案例
- 動態組件 -- is
- keep-alive
- 分包 -- 異步組價
- mixin -- 混入
- v-model-- 組件
- 使用計算屬性
- v-model -- 自定義修飾符
- Suspense -- 實驗屬性
- Teleport -- 指定掛載
- 組件實例 -- $ 屬性
- Option API VS Composition API
- Setup -- 組合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 場景
- api -- toRefs 和 toRef
- api -- readonly
- 判斷性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 簡單使用composition Api
- 響應性語法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 語法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定義指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同點
- $children -- 移除
- v-for 和 ref
- attribute 強制行為
- 按鍵修飾符
- v-if 和 v-for 優先級
- 組件使用 v-model -- 非兼容
- 組件
- h -- 函數
- jsx -- 編寫
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 簡單實現
- 安裝即使用
- 路由懶加載
- router-view
- router-link
- 路由匹配規則
- 404 頁面配置
- 路由嵌套
- 路由組件傳參
- 路由重定向和別名
- 路由跳轉方法
- 命名路由
- 命名視圖
- Composition API
- 路由守衛
- 路由元信息
- 路由其他方法 -- 添加/刪除/獲取
- 服務器配置映射
- 其他
- Vuex -- 狀態管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 數據同步
- 小技巧
- Pinia -- 狀態管理
- 開始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源碼解讀
- 開發感悟
- 練手項目