国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

如何手寫(xiě)簡(jiǎn)易的 Vue Router

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

前言

還是那樣,懂得如何使用一個(gè)常用庫(kù),還得了解其原理或者怎么模擬實(shí)現(xiàn),今天實(shí)現(xiàn)一下 vue-router 。

有一些知識(shí)我這篇文章提到了,這里就不詳細(xì)一步步寫(xiě),請(qǐng)看我 手寫(xiě)一個(gè)簡(jiǎn)易的 Vuex

基本骨架

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

安裝 Vue.js 插件。如果插件是一個(gè)對(duì)象,必須提供 install 方法。如果插件是一個(gè)函數(shù),它會(huì)被作為 install 方法。install 方法調(diào)用時(shí),會(huì)將 Vue 作為參數(shù)傳入。這個(gè)方法的第一個(gè)參數(shù)是 Vue 構(gòu)造器,第二個(gè)參數(shù)是一個(gè)可選的選項(xiàng)對(duì)象。

全局混入

使用 Vue.mixin(mixin)

全局注冊(cè)一個(gè)混入,影響注冊(cè)之后所有創(chuàng)建的每個(gè) Vue 實(shí)例。可以使用混入向組件注入自定義的行為,它將影響每一個(gè)之后創(chuàng)建的 Vue 實(shí)例。

路由用法

比如簡(jiǎn)單的:

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

它是傳入了mode和routes,我們實(shí)現(xiàn)的時(shí)候需要在VueRouter構(gòu)造函數(shù)中接收。

在使用路由標(biāo)題的時(shí)候是這樣:

<p> <!-- 使用 router-link 組件來(lái)導(dǎo)航. --> <!-- 通過(guò)傳入 `to` 屬性指定鏈接. --> <!-- <router-link> 默認(rèn)會(huì)被渲染成一個(gè) `<a>` 標(biāo)簽 --> <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] )注冊(cè)一個(gè)全局組件。

了解了大概,我們就可以寫(xiě)出一個(gè)基本骨架

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 // 把當(dāng)前vue實(shí)例保存到_root上 this._router = this.$options.router // 把router的實(shí)例掛載在_router上 } else if (this.$parent && this.$parent._root) { // 子組件的話就去繼承父組件的實(shí)例,讓所有組件共享一個(gè)router實(shí)例 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 默認(rèn)渲染成 a 標(biāo)簽 }, }, 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’, {}, ’視圖顯示的地方’) // 暫時(shí)置為h1標(biāo)簽,下面會(huì)改 }, })}export default VueRouter

mode

vue-router有兩種模式,默認(rèn)為 hash 模式。

history 模式

通過(guò)window.history.pushStateAPI 來(lái)添加瀏覽器歷史記錄,然后通過(guò)監(jiān)聽(tīng)popState事件,也就是監(jiān)聽(tīng)歷史記錄的改變,來(lái)加載相應(yīng)的內(nèi)容。

popstate 事件

當(dāng)活動(dòng)歷史記錄條目更改時(shí),將觸發(fā) popstate 事件。如果被激活的歷史記錄條目是通過(guò)對(duì) history.pushState()的調(diào)用創(chuàng)建的,或者受到對(duì) history.replaceState()的調(diào)用的影響,popstate 事件的 state 屬性包含歷史條目的狀態(tài)對(duì)象的副本。

History.pushState()方法

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

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

state:一個(gè)與添加的記錄相關(guān)聯(lián)的狀態(tài)對(duì)象,主要用于popstate事件。該事件觸發(fā)時(shí),該對(duì)象會(huì)傳入回調(diào)函數(shù)。也就是說(shuō),瀏覽器會(huì)將這個(gè)對(duì)象序列化以后保留在本地,重新載入這個(gè)頁(yè)面的時(shí)候,可以拿到這個(gè)對(duì)象。如果不需要這個(gè)對(duì)象,此處可以填null。 title:新頁(yè)面的標(biāo)題。但是,現(xiàn)在所有瀏覽器都忽視這個(gè)參數(shù),所以這里可以填空字符串。 url:新的網(wǎng)址,必須與當(dāng)前頁(yè)面處在同一個(gè)域。瀏覽器的地址欄將顯示這個(gè)網(wǎng)址。

hash 模式

使用 URL 的 hash 來(lái)模擬一個(gè)完整的 URL。,通過(guò)監(jiān)聽(tīng)hashchange事件,然后根據(jù)hash值(可通過(guò) window.location.hash 屬性讀取)去加載對(duì)應(yīng)的內(nèi)容的。

繼續(xù)增加代碼,

let Vue = nullclass HistoryRoute { constructor() { this.current = null // 當(dāng)前路徑 }}class VueRouter { constructor(options) { this.mode = options.mode || ’hash’ this.routes = options.routes || [] this.routesMap = this.createMap(this.routes) this.history = new HistoryRoute() // 當(dāng)前路由 this.initRoute() // 初始化路由函數(shù) } createMap(routes) { return routes.reduce((pre, current) => { pre[current.path] = current.component return pre }, {}) } initRoute() { if (this.mode === ’hash’) { // 先判斷用戶打開(kāi)時(shí)有沒(méi)有hash值,沒(méi)有的話跳轉(zhuǎn)到 #/ 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) // 監(jiān)聽(tīng)history路徑變化 } else if (this.$parent && this.$parent._root) { this._root = this.$parent && this.$parent._root } // 當(dāng)訪問(wèn)this.$router時(shí)即返回router實(shí)例 Object.defineProperty(this, ’$router’, { get() { return this._root._router }, }) // 當(dāng)訪問(wèn)this.$route時(shí)即返回當(dāng)前頁(yè)面路由信息 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標(biāo)簽?zāi)J(rèn)跳轉(zhuǎn) 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已經(jīng)是動(dòng)態(tài)響應(yīng) let routesMap = this._self._root._router.routesMap return h(routesMap[current]) // 動(dòng)態(tài)渲染對(duì)應(yīng)組件 }, })}

至此,一個(gè)簡(jiǎn)易的vue-router就實(shí)現(xiàn)完了,案例完整代碼附上:

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() // 當(dāng)前路由 // 初始化路由函數(shù) this.initRoute() } createMap(routes) { return routes.reduce((pre, current) => { pre[current.path] = current.component return pre }, {}) } initRoute() { if (this.mode === ’hash’) { // 先判斷用戶打開(kāi)時(shí)有沒(méi)有hash值,沒(méi)有的話跳轉(zhuǎn)到 #/ 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 // 把當(dāng)前vue實(shí)例保存到_root上 this._router = this.$options.router // 把router的實(shí)例掛載在_router上 Vue.util.defineReactive(this, ’_route’, this._router.history) // 監(jiān)聽(tīng)history路徑變化 } else if (this.$parent && this.$parent._root) { // 子組件的話就去繼承父組件的實(shí)例,讓所有組件共享一個(gè)router實(shí)例 this._root = this.$parent && this.$parent._root } // 當(dāng)訪問(wèn)this.$router時(shí)即返回router實(shí)例 Object.defineProperty(this, ’$router’, { get() { return this._root._router }, }) // 當(dāng)訪問(wèn)this.$route時(shí)即返回當(dāng)前頁(yè)面路由信息 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標(biāo)簽?zāi)J(rèn)跳轉(zhuǎn) event && event.preventDefault && event.preventDefault() // 阻止a標(biāo)簽?zāi)J(rèn)跳轉(zhuǎn) 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已經(jīng)是動(dòng)態(tài) let routesMap = this._self._root._router.routesMap return h(routesMap[current]) // 動(dòng)態(tài)渲染對(duì)應(yīng)組件 }, })}export default VueRouter

ps: 個(gè)人技術(shù)博文 Github 倉(cāng)庫(kù),覺(jué)得不錯(cuò)的話歡迎 star,給我一點(diǎn)鼓勵(lì)繼續(xù)寫(xiě)作吧~

以上就是如何手寫(xiě)簡(jiǎn)易的 Vue Router的詳細(xì)內(nèi)容,更多關(guān)于手寫(xiě)簡(jiǎn)易的 Vue Router的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 国内欧美一区二区三区 | 午夜a一级毛片一.成 | 欧美大片毛片aaa免费看 | 精品中文字幕在线观看 | 欧美国产综合日韩一区二区 | 国产黄色片网站 | 成人免费在线播放 | 91国在线观看 | 精品国产免费人成在线观看 | 韩国毛片基地 | 99久久伊人一区二区yy5o99 | 色老头老太做爰视频在线观看 | 久久久精品一区 | 久久亚洲国产伦理 | 久久99精品久久久久久野外 | 九九手机视频 | 亚洲视频在线免费观看 | 在线成人天天鲁夜啪视频 | 免费看美女无遮掩的软件 | 亚洲一区在线免费观看 | 91视频免费播放 | 亚洲精品无码专区在线播放 | 在线国产日韩 | 性生大片一级毛片免费观看 | 欧美另类精品一区二区三区 | 天堂资源8中文最新版在线 天堂最新版 | 一本久道综合久久精品 | 欧美一级在线毛片免费观看 | 国产三级在线视频观看 | 老头巨大粗长xxxxx | 亚洲一区二区三区影院 | 一区二区三区四区免费视频 | 怡红院日本一道日本久久 | 国产成人精品亚洲一区 | 精品国语_高清国语自产 | 九九香蕉 | 99精品福利 | 亚洲激情视频网站 | 国产短裙黑色丝袜在线观看下 | a毛片毛费观看 | 亚洲视频播放 |