亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue中兩種路由模式的實(shí)現(xiàn)詳解

 更新時(shí)間:2023年08月13日 10:17:24   作者:閩南,  
這篇文章主要為大家詳細(xì)介紹了vue中兩種路由模式的實(shí)現(xiàn),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下

平時(shí)我們編寫(xiě)路由時(shí),通常直接下載插件使用,在main.js文件中引入直接通過(guò)引入vue-router中的Router通過(guò)Vue.use使用以后定義一個(gè)routeMap數(shù)組,里邊是我們編寫(xiě)路由的地方,最后通過(guò)實(shí)例化一個(gè) Router實(shí)例 將routes=我們定義的routeMao路由數(shù)組。

但是我們并不知道它是如何實(shí)現(xiàn)的,因此我們可以通過(guò)自己編寫(xiě)插件的形式,實(shí)現(xiàn)一個(gè)vue-router

常用路由步驟:

//router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const routeMap= [
     {
         path: '/home',
         component: () => import('../components/Home/Home.vue')
     },
     {
         path: '/list',
         component: () => import('../components/List/List.vue')
    },
]
const router = new Router({
    routes: constantRouterMap
})
export default router
//main.js
import router from './router'
new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app')

我們來(lái)實(shí)現(xiàn)一下如何實(shí)現(xiàn)一個(gè)hash模式的路由

由于我們不適用插件形式實(shí)現(xiàn),因此我們使用步驟與平常實(shí)現(xiàn)有一些差異。

router/index.js是我們的路由文件,里面放置我們的路由

plugin/router.js是我們的自定義插件文件,里面放置我們自定義插件內(nèi)容

components是我們組件目錄,放置我們的路由組件(通常使用view定義路由組件)

main.js是我們的入口文件,需要在該文件引入router并且實(shí)例化vue的時(shí)候需要將引入的router使用

1、首先我們?cè)贏pp.vue文件中,通過(guò)<router-view/>以及<router-link/>定義聲明式導(dǎo)航和路由占位

<div>
    <router-link to="/home">首頁(yè)</router-link>
    <router-link to="/list">列表</router-link>
    <hr>
    <router-view></router-view>
</div>

這里我們會(huì)發(fā)現(xiàn)使用以后會(huì)報(bào)錯(cuò),因?yàn)槲覀儧](méi)有下載插件,因此沒(méi)有這兩個(gè)組件。

我們需要配置plugin插件

由于沒(méi)有這兩個(gè)全局組件因此我們需要配置兩個(gè)全局組件

install方法是為了將我們的路由掛載在我們的組件實(shí)例上,通過(guò)mixin全局混入,將我們的實(shí)例上掛載$router屬性

然后定義兩個(gè)全局組件,router-link由于它渲染出來(lái)相當(dāng)于html中的a標(biāo)簽,使用render方法,參數(shù)為一個(gè)createElement方法接收三個(gè)參數(shù)(第一個(gè)參數(shù)創(chuàng)建的元素,第二個(gè)參數(shù)元素具有的屬性, 第三個(gè)參數(shù)元素的內(nèi)容)

router-view由于是一個(gè)路由占位符,因此返回的是個(gè)組件,渲染組件。

通過(guò)routesMap是我們存放的路由,current是我們的當(dāng)前的path路由,因此可以通過(guò)查找路由中key值為我們當(dāng)前path路徑的,查找到我們的組件。通過(guò)return渲染我們的組件

VueRouter.install = function (_Vue) {
    //1、保存Vue
    Vue = _Vue
    //2、將以下代碼延遲到vue實(shí)例初始化完畢執(zhí)行
    Vue.mixin({
        beforeCreate() {
            //判斷如果有router屬性就執(zhí)行下方代碼
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    //創(chuàng)建全局組件router-link和router-view
    //創(chuàng)建router-link組件
    Vue.component('router-link', {
        props: {
            to: {
                type: String | Object,
                required: true
            }
        },
        render(h) {// h 有三個(gè)參數(shù),第一個(gè)參數(shù)創(chuàng)建的元素,第二個(gè)參數(shù)元素具有的屬性, 第三個(gè)參數(shù)元素的內(nèi)容
            return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
        }
    })
    //創(chuàng)建router-view組件
    Vue.component('router-view', {
        // 組件要重新渲染,必須要讓數(shù)據(jù)發(fā)生改變的時(shí)候,重新去執(zhí)行render函數(shù)
        render(h) {
            const router = this.$router
            console.log(router.routesMap, 'routesMap');
            let component = router.routesMap[router.current];//組件
            //獲取到外部傳遞的路由表
            return h(component)
        }
    })
}

2、我們定義一個(gè)路由類(lèi),該類(lèi)會(huì)獲取到我們的路由信息從而進(jìn)行路由監(jiān)聽(tīng)以及組件渲染。

(1)、該類(lèi)中constructor是我們通過(guò)實(shí)例化vueRouter傳入的數(shù)據(jù),我們需要通過(guò)將數(shù)據(jù)保存在vueRouter實(shí)例上,獲取到當(dāng)前的url path路徑。

(2)、通過(guò)監(jiān)聽(tīng)方法hashchange監(jiān)聽(tīng)我們hash值的變化,通過(guò)方法進(jìn)行監(jiān)聽(tīng),但是一定要注意這里方法的this指向必須是vueRouter實(shí)例不可以是window,因此需要通過(guò)bind改變this指向

(3)、通過(guò)defineReactive來(lái)講我們的path路徑變?yōu)轫憫?yīng)式,這樣每次路徑發(fā)生變化可以監(jiān)測(cè)到變化。

(4)、定義routesMap為我們的路由對(duì)象,遍歷我們傳入的路由數(shù)組,將我們每個(gè)path路徑對(duì)應(yīng)組件,為一組一組的鍵值對(duì)。

這樣可以實(shí)現(xiàn)一套hash路由模式的路由跳轉(zhuǎn)。

全部代碼如下:

//plugin/router.js
let Vue;
class VueRouter {
    constructor(options) {
        //保存選項(xiàng)
        this.options = options;
        // console.log(options, '路由數(shù)據(jù)');
        // 定義一個(gè)響應(yīng)式的變量current,保存當(dāng)前的hash值
        let url = location.hash.slice(1,) || '/';
        // defineReactive定義響應(yīng)式的對(duì)象
        Vue.util.defineReactive(this, 'current', url)
        // hashchange事件來(lái)監(jiān)聽(tīng)hash值的變化, 注意this指向問(wèn)題
        addEventListener('hashchange', this.changeHash.bind(this))
        this.routesMap = {};
        //對(duì)routes中的對(duì)象做一個(gè)映射:routesMap = {'/home':component,'/list': component}
        this.options.routes.forEach(route => {
            this.routesMap[route.path] = route.component
        })
    }
    //監(jiān)聽(tīng)hash值變化的函數(shù)
    changeHash() {
        //通過(guò)location.hash來(lái)獲取到hash值
        this.current = location.hash.slice(1,)
        console.log(this.routesMap, '555');
        // console.log(this.current);//當(dāng)前path路徑
    }
}
VueRouter.install = function (_Vue) {
    //1、保存Vue
    Vue = _Vue
    //2、將以下代碼延遲到vue實(shí)例初始化完畢執(zhí)行
    Vue.mixin({
        beforeCreate() {
            //判斷如果有router屬性就執(zhí)行下方代碼
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    //創(chuàng)建全局組件router-link和router-view
    //創(chuàng)建router-link組件
    Vue.component('router-link', {
        props: {
            to: {
                type: String | Object,
                required: true
            }
        },
        render(h) {// h 有三個(gè)參數(shù),第一個(gè)參數(shù)創(chuàng)建的元素,第二個(gè)參數(shù)元素具有的屬性, 第三個(gè)參數(shù)元素的內(nèi)容
            return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
        }
    })
    //創(chuàng)建router-view組件
    Vue.component('router-view', {
        // 組件要重新渲染,必須要讓數(shù)據(jù)發(fā)生改變的時(shí)候,重新去執(zhí)行render函數(shù)
        render(h) {
            const router = this.$router
            console.log(router.routesMap, 'routesMap');
            let component = router.routesMap[router.current];//組件
            console.log(component, 'component');
            //獲取到外部傳遞的路由表
            return h(component)
        }
    })
}
export default VueRouter;

接下來(lái)實(shí)現(xiàn)歷史路由模式

我們知道歷史路由模式和hash路由模式區(qū)別是域名是否存在#因此我們可以通過(guò)在路由文件中定義mode屬性判斷是歷史路由模式還是hash路由模式。

先大白話(huà)來(lái)說(shuō)一下大概的實(shí)現(xiàn)思路(hash和history實(shí)現(xiàn)區(qū)別):

1、我們通過(guò)我們定義的mode判斷是hash路由模式還是history路由模式,router-link點(diǎn)擊跳轉(zhuǎn)的時(shí)候如果是hash路由模式,我們通過(guò)render方法返回我們渲染到瀏覽器域名的數(shù)據(jù),hash模式是帶#的,因此我們定義href屬性需要+#,但是history模式是不帶#的,因此我們不需要加#。其次,因?yàn)閔ash模式自動(dòng)檢測(cè)我們的域名,因此我們實(shí)現(xiàn)歷史模式需要手動(dòng)加一個(gè)點(diǎn)擊事件,并且需要阻止a鏈接默認(rèn)跳轉(zhuǎn)的行為(preventDefault取消默認(rèn)行為),并且通過(guò)pushState方法,實(shí)現(xiàn)跳轉(zhuǎn),這是歷史路由模式的方法pushState(obj,title,url),最后設(shè)置我們的路由當(dāng)前path路徑為我們跳轉(zhuǎn)的路徑。

2、當(dāng)我們定義好它的router-link全局組件以后,這時(shí)我們hash路由模式和history路由模式已經(jīng)可以基本實(shí)現(xiàn),hash模式帶#,history路由模式不帶#。但是我們?nèi)砸x一個(gè)監(jiān)聽(tīng)歷史路由模式變化的監(jiān)聽(tīng)事件。這里我們通過(guò)mode判斷是什么模式從而監(jiān)聽(tīng)不同的事件,歷史路由模式監(jiān)聽(tīng)需要通過(guò)監(jiān)聽(tīng)popState方法,來(lái)判斷是否發(fā)生變化,它堅(jiān)挺的是我們?yōu)g覽器的前進(jìn)后退的變化。

歷史路由模式監(jiān)聽(tīng)事件為hashchange方法,這個(gè)事件是用來(lái)監(jiān)聽(tīng)我們hash值的變化,通過(guò)設(shè)置兩個(gè)方法從而設(shè)置我們當(dāng)前路徑為對(duì)應(yīng)的path路徑。hash模式會(huì)通過(guò)slice剪切到#,歷史路由模式則通過(guò)location.pathname獲取到當(dāng)前path路徑。

實(shí)現(xiàn)如下:

let Vue;
class VueRouter {
    constructor(options) {
        //保存選項(xiàng)
        this.options = options;
        // console.log(options, '路由數(shù)據(jù)');
        // 定義一個(gè)響應(yīng)式的變量current,保存當(dāng)前的hash值
        let url = location.hash.slice(1,) || '/';
        // defineReactive定義響應(yīng)式的對(duì)象
        Vue.util.defineReactive(this, 'current', url)
        //判斷當(dāng)前的路由模式
        if (this.options.mode === 'hash') {
            // hashchange事件來(lái)監(jiān)聽(tīng)hash值的變化, 注意this指向問(wèn)題
            addEventListener('hashchange', this.changeHash.bind(this))
        } else if (this.options.mode === 'history') {
            // history模式監(jiān)聽(tīng)的事件叫做:popstate, 監(jiān)聽(tīng)的是瀏覽器左上角的兩個(gè)小箭頭的變化
            addEventListener('popstate', this.changeHistory.bind(this))
        }
        this.routesMap = {};
        //對(duì)routes中的對(duì)象做一個(gè)映射:routesMap = {'/home':component,'/list': component}
        this.options.routes.forEach(route => {
            this.routesMap[route.path] = route.component
        })
    }
    //監(jiān)聽(tīng)hash值變化的函數(shù)
    changeHash() {
        //通過(guò)location.hash來(lái)獲取到hash值
        this.current = location.hash.slice(1,)
        console.log(this.routesMap, '555');
        // console.log(this.current);//當(dāng)前path路徑
    }
    // history
    changeHistory() {
        // console.log(location.pathname)
        this.current = location.pathname;
    }
}
 VueRouter.install = function (_Vue) {
    //1、保存Vue
    Vue = _Vue
    //2、將以下代碼延遲到vue實(shí)例初始化完畢執(zhí)行
    Vue.mixin({
        beforeCreate() {
            //判斷如果有router屬性就執(zhí)行下方代碼
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    //創(chuàng)建全局組件router-link和router-view
    //創(chuàng)建router-link組件
    Vue.component('router-link', {
        props: {
            to: {
                type: String | Object,
                required: true
            }
        },
        render(h) {// h 有三個(gè)參數(shù),第一個(gè)參數(shù)創(chuàng)建的元素,第二個(gè)參數(shù)元素具有的屬性, 第三個(gè)參數(shù)元素的內(nèi)容
            const router = this.$router;
            if (router.options.mode === 'hash') {
                return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
            } else if (router.options.mode === 'history') {
                return h('a', {
                    attrs: { href: this.to },
                    on: {
                        'click': ev => {
                            // 1. 阻止a鏈接的默認(rèn)跳轉(zhuǎn)行為
                            ev.preventDefault()
                            // 2. 調(diào)用pushState方法來(lái)實(shí)現(xiàn)跳轉(zhuǎn): pushState(obj, title, url)
                            history.pushState({}, '', this.to)
                            // 3. 設(shè)置current的值
                            router.current = this.to;
                        }
                    }
                }, this.$slots.default)
            }
        }
    })
    //創(chuàng)建router-view組件
    Vue.component('router-view', {
        // 組件要重新渲染,必須要讓數(shù)據(jù)發(fā)生改變的時(shí)候,重新去執(zhí)行render函數(shù)
        render(h) {
            const router = this.$router
            console.log(router.routesMap, 'routesMap');
            let component = router.routesMap[router.current];//組件
            console.log(component, 'component');
            //獲取到外部傳遞的路由表
            return h(component)
        }
    })
}

這一期我們講解了,如何實(shí)現(xiàn)一個(gè)基本的hash路由模式以及history路由模式,但是我們通常使用情況下路由嵌套通過(guò)一級(jí)路由下定義children屬性來(lái)定義二級(jí)路由,這并沒(méi)有實(shí)現(xiàn),下一期來(lái)實(shí)現(xiàn)路由嵌套。

到此這篇關(guān)于vue中兩種路由模式的實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)vue路由模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論