电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

如何手寫簡易的 Vue Router

瀏覽:23日期:2022-11-16 15:05:40

前言

還是那樣,懂得如何使用一個常用庫,還得了解其原理或者怎么模擬實現,今天實現一下 vue-router 。

有一些知識我這篇文章提到了,這里就不詳細一步步寫,請看我 手寫一個簡易的 Vuex

基本骨架

Vue 里面使用插件的方式是 Vue.use(plugin) ,這里貼出它的用法:

安裝 Vue.js 插件。如果插件是一個對象,必須提供 install 方法。如果插件是一個函數,它會被作為 install 方法。install 方法調用時,會將 Vue 作為參數傳入。這個方法的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象。

全局混入

使用 Vue.mixin(mixin)

全局注冊一個混入,影響注冊之后所有創建的每個 Vue 實例??梢允褂没烊胂蚪M件注入自定義的行為,它將影響每一個之后創建的 Vue 實例。

路由用法

比如簡單的:

// 路由數組const routes = [ { path: ’/’, name: ’Page1’, component: Page1, }, { path: ’/page2’, name: ’Page2’, component: Page2, },]const router = new VueRouter({ mode: ’history’, // 模式 routes,})

它是傳入了mode和routes,我們實現的時候需要在VueRouter構造函數中接收。

在使用路由標題的時候是這樣:

<p> <!-- 使用 router-link 組件來導航. --> <!-- 通過傳入 `to` 屬性指定鏈接. --> <!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 --> <router-link to='/page1'>Go to Foo</router-link> <router-link to='/page2'>Go to Bar</router-link></p><!-- 路由出口 --><!-- 路由匹配到的組件將渲染在這里 --><router-view></router-view>

故我們需要使用Vue.component( id, [definition] )注冊一個全局組件。

了解了大概,我們就可以寫出一個基本骨架

let Vue = nullclass VueRouter { constructor(options) { this.mode = options.mode || ’hash’ this.routes = options.routes || [] }}VueRouter.install = function (_Vue) { Vue = _Vue Vue.mixin({ beforeCreate() { // 根組件 if (this.$options && this.$options.router) { this._root = this // 把當前vue實例保存到_root上 this._router = this.$options.router // 把router的實例掛載在_router上 } else if (this.$parent && this.$parent._root) { // 子組件的話就去繼承父組件的實例,讓所有組件共享一個router實例 this._root = this.$parent && this.$parent._root } }, }) Vue.component(’router-link’, { props: { to: { type: [String, Object], required: true, }, tag: { type: String, default: ’a’, // router-link 默認渲染成 a 標簽 }, }, render(h) { let tag = this.tag || ’a’ return <tag href={this.to}>{this.$slots.default}</tag> }, }) Vue.component(’router-view’, { render(h) { return h(’h1’, {}, ’視圖顯示的地方’) // 暫時置為h1標簽,下面會改 }, })}export default VueRouter

mode

vue-router有兩種模式,默認為 hash 模式。

history 模式

通過window.history.pushStateAPI 來添加瀏覽器歷史記錄,然后通過監聽popState事件,也就是監聽歷史記錄的改變,來加載相應的內容。

popstate 事件

當活動歷史記錄條目更改時,將觸發 popstate 事件。如果被激活的歷史記錄條目是通過對 history.pushState()的調用創建的,或者受到對 history.replaceState()的調用的影響,popstate 事件的 state 屬性包含歷史條目的狀態對象的副本。

History.pushState()方法

window.history.pushState(state, title, url)

該方法用于在歷史中添加一條記錄,接收三個參數,依次為:

state:一個與添加的記錄相關聯的狀態對象,主要用于popstate事件。該事件觸發時,該對象會傳入回調函數。也就是說,瀏覽器會將這個對象序列化以后保留在本地,重新載入這個頁面的時候,可以拿到這個對象。如果不需要這個對象,此處可以填null。 title:新頁面的標題。但是,現在所有瀏覽器都忽視這個參數,所以這里可以填空字符串。 url:新的網址,必須與當前頁面處在同一個域。瀏覽器的地址欄將顯示這個網址。

hash 模式

使用 URL 的 hash 來模擬一個完整的 URL。,通過監聽hashchange事件,然后根據hash值(可通過 window.location.hash 屬性讀取)去加載對應的內容的。

繼續增加代碼,

let Vue = nullclass HistoryRoute { constructor() { this.current = null // 當前路徑 }}class VueRouter { constructor(options) { this.mode = options.mode || ’hash’ this.routes = options.routes || [] this.routesMap = this.createMap(this.routes) this.history = new HistoryRoute() // 當前路由 this.initRoute() // 初始化路由函數 } createMap(routes) { return routes.reduce((pre, current) => { pre[current.path] = current.component return pre }, {}) } initRoute() { if (this.mode === ’hash’) { // 先判斷用戶打開時有沒有hash值,沒有的話跳轉到 #/ location.hash ? ’’ : (location.hash = ’/’) window.addEventListener(’load’, () => { this.history.current = location.hash.slice(1) }) window.addEventListener(’hashchange’, () => { this.history.current = location.hash.slice(1) }) } else { // history模式 location.pathname ? ’’ : (location.pathname = ’/’) window.addEventListener(’load’, () => { this.history.current = location.pathname }) window.addEventListener(’popstate’, () => { this.history.current = location.pathname }) } }}VueRouter.install = function (_Vue) { Vue = _Vue Vue.mixin({ beforeCreate() { if (this.$options && this.$options.router) { this._root = this this._router = this.$options.router Vue.util.defineReactive(this, ’_route’, this._router.history) // 監聽history路徑變化 } else if (this.$parent && this.$parent._root) { this._root = this.$parent && this.$parent._root } // 當訪問this.$router時即返回router實例 Object.defineProperty(this, ’$router’, { get() { return this._root._router }, }) // 當訪問this.$route時即返回當前頁面路由信息 Object.defineProperty(this, ’$route’, { get() { return this._root._router.history.current }, }) }, })}export default VueRouter

router-link 和 router-view 組件

VueRouter.install = function (_Vue) { Vue = _Vue Vue.component(’router-link’, { props: { to: { type: [String, Object], required: true, }, tag: { type: String, default: ’a’, }, }, methods: { handleClick(event) { // 阻止a標簽默認跳轉 event && event.preventDefault && event.preventDefault() let mode = this._self._root._router.mode let path = this.to this._self._root._router.history.current = path if (mode === ’hash’) { window.history.pushState(null, ’’, ’#/’ + path.slice(1)) } else { window.history.pushState(null, ’’, path.slice(1)) } }, }, render(h) { let mode = this._self._root._router.mode let tag = this.tag || ’a’ let to = mode === ’hash’ ? ’#’ + this.to : this.to console.log(’render’, this.to) return ( <tag on-click={this.handleClick} href={to}> {this.$slots.default} </tag> ) // return h(tag, { attrs: { href: to }, on: { click: this.handleClick } }, this.$slots.default) }, }) Vue.component(’router-view’, { render(h) { let current = this._self._root._router.history.current // current已經是動態響應 let routesMap = this._self._root._router.routesMap return h(routesMap[current]) // 動態渲染對應組件 }, })}

至此,一個簡易的vue-router就實現完了,案例完整代碼附上:

let Vue = nullclass HistoryRoute { constructor() { this.current = null }}class VueRouter { constructor(options) { this.mode = options.mode || ’hash’ this.routes = options.routes || [] this.routesMap = this.createMap(this.routes) this.history = new HistoryRoute() // 當前路由 // 初始化路由函數 this.initRoute() } createMap(routes) { return routes.reduce((pre, current) => { pre[current.path] = current.component return pre }, {}) } initRoute() { if (this.mode === ’hash’) { // 先判斷用戶打開時有沒有hash值,沒有的話跳轉到 #/ location.hash ? ’’ : (location.hash = ’/’) window.addEventListener(’load’, () => { this.history.current = location.hash.slice(1) }) window.addEventListener(’hashchange’, () => { this.history.current = location.hash.slice(1) }) } else { // history模式 location.pathname ? ’’ : (location.pathname = ’/’) window.addEventListener(’load’, () => { this.history.current = location.pathname }) window.addEventListener(’popstate’, () => { this.history.current = location.pathname }) } }}VueRouter.install = function(_Vue) { Vue = _Vue Vue.mixin({ beforeCreate() { // 根組件 if (this.$options && this.$options.router) { this._root = this // 把當前vue實例保存到_root上 this._router = this.$options.router // 把router的實例掛載在_router上 Vue.util.defineReactive(this, ’_route’, this._router.history) // 監聽history路徑變化 } else if (this.$parent && this.$parent._root) { // 子組件的話就去繼承父組件的實例,讓所有組件共享一個router實例 this._root = this.$parent && this.$parent._root } // 當訪問this.$router時即返回router實例 Object.defineProperty(this, ’$router’, { get() { return this._root._router }, }) // 當訪問this.$route時即返回當前頁面路由信息 Object.defineProperty(this, ’$route’, { get() { return this._root._router.history.current }, }) }, }) Vue.component(’router-link’, { props: { to: { type: [String, Object], required: true, }, tag: { type: String, default: ’a’, }, }, methods: { handleClick(event) { // 阻止a標簽默認跳轉 event && event.preventDefault && event.preventDefault() // 阻止a標簽默認跳轉 let mode = this._self._root._router.mode let path = this.to this._self._root._router.history.current = path if (mode === ’hash’) { window.history.pushState(null, ’’, ’#/’ + path.slice(1)) } else { window.history.pushState(null, ’’, path.slice(0)) } }, }, render(h) { let mode = this._self._root._router.mode let tag = this.tag || ’a’ let to = mode === ’hash’ ? ’#’ + this.to : this.to return ( <tag on-click={this.handleClick} href={to}> {this.$slots.default} </tag> ) // return h(tag, { attrs: { href: to }, on: { click: this.handleClick } }, this.$slots.default) }, }) Vue.component(’router-view’, { render(h) { let current = this._self._root._router.history.current // current已經是動態 let routesMap = this._self._root._router.routesMap return h(routesMap[current]) // 動態渲染對應組件 }, })}export default VueRouter

ps: 個人技術博文 Github 倉庫,覺得不錯的話歡迎 star,給我一點鼓勵繼續寫作吧~

以上就是如何手寫簡易的 Vue Router的詳細內容,更多關于手寫簡易的 Vue Router的資料請關注好吧啦網其它相關文章!

標簽: Vue
相關文章:
主站蜘蛛池模板: 吸音板,隔音板,吸音材料,吸音板价格,声学材料 - 佛山诺声吸音板厂家 | 河南卓美创业科技有限公司-河南卓美防雷公司-防雷接地-防雷工程-重庆避雷针-避雷器-防雷检测-避雷带-避雷针-避雷塔、机房防雷、古建筑防雷等-山西防雷公司 | 探鸣起名网-品牌起名-英文商标起名-公司命名-企业取名包满意 | 福州甲醛检测-福建室内空气检测_环境检测_水质检测-福建中凯检测技术有限公司 | 大型果蔬切片机-水果冬瓜削皮机-洗菜机切菜机-肇庆市凤翔餐饮设备有限公司 | 矿用履带式平板车|探水钻机|气动架柱式钻机|架柱式液压回转钻机|履带式钻机-启睿探水钻机厂家 | 手表腕表维修保养鉴定售后服务中心网点 - 名表维修保养 | 根系分析仪,大米外观品质检测仪,考种仪,藻类鉴定计数仪,叶面积仪,菌落计数仪,抑菌圈测量仪,抗生素效价测定仪,植物表型仪,冠层分析仪-杭州万深检测仪器网 | 餐饮加盟网_特色餐饮加盟店_餐饮连锁店加盟| 垃圾处理设备_餐厨垃圾处理设备_厨余垃圾处理设备_果蔬垃圾处理设备-深圳市三盛环保科技有限公司 | 宏源科技-房地产售楼系统|线上开盘系统|售楼管理系统|线上开盘软件 | 塑胶地板-商用PVC地板-pvc地板革-安耐宝pvc塑胶地板厂家 | 一体化污水处理设备-一体化净水设备-「山东梦之洁水处理」 | 沧州友城管业有限公司-内外涂塑钢管-大口径螺旋钢管-涂塑螺旋管-保温钢管生产厂家 | 精密五金冲压件_深圳五金冲压厂_钣金加工厂_五金模具加工-诚瑞丰科技股份有限公司 | 嘉兴泰东园林景观工程有限公司_花箱护栏 | 篮球架_乒乓球台_足球门_校园_竞技体育器材_厂家_价格-沧州浩然体育器材有限公司 | 泰国专线_泰国物流专线_广州到泰国物流公司-泰廊曼国际 | 真空乳化机-灌装封尾机-首页-温州精灌 | 变频器维修公司_plc维修_伺服驱动器维修_工控机维修 - 夫唯科技 变位机,焊接变位机,焊接变位器,小型变位机,小型焊接变位机-济南上弘机电设备有限公司 | 仓储笼_仓储货架_南京货架_仓储货架厂家_南京货架价格低-南京一品仓储设备制造公司 | 液氮罐_液氮容器_自增压液氮罐-北京君方科仪科技发展有限公司 | EPK超声波测厚仪,德国EPK测厚仪维修-上海树信仪器仪表有限公司 | PE拉伸缠绕膜,拉伸缠绕膜厂家,纳米缠绕膜-山东凯祥包装 | 浙江栓钉_焊钉_剪力钉厂家批发_杭州八建五金制造有限公司 | 全自动真空上料机_粉末真空上料机_气动真空上料机-南京奥威环保科技设备有限公司 | LED太阳能中国结|发光红灯笼|灯杆造型灯|节日灯|太阳能灯笼|LED路灯杆装饰造型灯-北京中海轩光电 | 小型铜米机-干式铜米机-杂线全自动铜米机-河南鑫世昌机械制造有限公司 | 土壤有机碳消解器-石油|表层油类分析采水器-青岛溯源环保设备有限公司 | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 小港信息港-鹤壁信息港 鹤壁老百姓便民生活信息网站 | 蔬菜清洗机_环速洗菜机_异物去除清洗机_蔬菜清洗机_商用洗菜机 - 环速科技有限公司 | 砂尘试验箱_淋雨试验房_冰水冲击试验箱_IPX9K淋雨试验箱_广州岳信试验设备有限公司 | 窖井盖锯圆机_锯圆机金刚石锯片-无锡茂达金刚石有限公司 | 东莞市踏板石餐饮管理有限公司_正宗桂林米粉_正宗桂林米粉加盟_桂林米粉加盟费-东莞市棒子桂林米粉 | 北京三友信电子科技有限公司-ETC高速自动栏杆机|ETC机柜|激光车辆轮廓测量仪|嵌入式车道控制器 | 优考试_免费在线考试系统_培训考试系统_题库系统_组卷答题系统_匡优考试 | 定量包装机,颗粒定量包装机,粉剂定量包装机,背封颗粒包装机,定量灌装机-上海铸衡电子科技有限公司 | 比士亚-专业恒温恒湿酒窖,酒柜,雪茄柜的设计定制 | 上海办公室装修公司_办公室设计_直营办公装修-羚志悦装 | 车间除尘设备,VOCs废气处理,工业涂装流水线,伸缩式喷漆房,自动喷砂房,沸石转轮浓缩吸附,机器人喷粉线-山东创杰智慧 |