VueRouter(自定义VueRourter、使用方法、router-view\link、传递参数、路由嵌套、重定向、路由拦截(全局和局部守卫)、命名路由、路由模式(原理)、路由懒加载)

  • Post author:
  • Post category:vue

目录

VueRouter(router)

VueRouter引入链接

使用方法

router-view标签

name属性(命名视图)

router-link标签

传递参数形式

嵌套路由

重定向

路由拦截

全局前置守卫

全局后置钩子

局部守卫

命名路由

路由模式(history)

路由原理

location.hash\history.pushState方法

路由懒加载

自定义简易VueRouter(history模式) 

自定义详细VueRouter(hash模式)  

VueRouter官网


VueRouter(router)

和v-if/v-show一样,是用来切换组件的显示,Vue Router是通过哈希来切换(#/xxx),且能够在切换的时候传递参数。注意要在Vue导入之后导入。

VueRouter引入链接

<script src=”https://unpkg.com/vue-router@2.0.0/dist/vue-router.js”></script>

使用方法

  1. 定义需要切换的组件对象,例如one={template:'<div>one</div>’},two={template:'<div>two</div>’}。
  2. 通过一个包含多个对象的数组来定义路由规则,每个对象就是一个规则,例如const v=[{path:’/one’,component:one},{path:’/two’,component:two}]。这里的one、two为component对象,不能传component的名称,path:’/’相当于当前路径。
  3. 创建VueRouter对象,const vr=new VueRouter({routes:v})
  4. 将创建好的路由对象绑定在Vue实例上new Vue({el:’#app’,data:{},router:vr})。
  5. 通过直接设置location.href=’#/one’或this.$router.push(‘/one’)或this.$router.replace(‘/one’)(注意和this.$route区分,route为当前匹配的路由对象信息,router为全部的路由信息)跳转或a标签改变当前网页链接,例如<a href=’#/one’>,点击便会改变当前url地址为….html#/one,此时router-view标签便会根据路由规则查找path=’/one’的组件显示,此例会显示one的组件。注意push相当于是压入栈顶,可以通过this.$router.back()方法或浏览器后退键回到上一次的路由,而replace相当于把栈顶的给替换了,是无法回到上一次的路由

router-view标签

根据不同的路由规则和当前的url对应显示不同的组件。

name属性(命名视图)

当有name属性后为命名视图,作用:在相同的url情况下想通过router-vie标签展示不同的组件。例如给router-view标签添加属性name=’rv1’,还需改变路由规则const v=[{path:’/one’,components:{rv1:one,rv2:two}},{path:’/two’,component:two}],这时url地址为….html#/one时,router-view标签显示组件one,想要显示组件two,把name改为’rv2’即可(改url也行)。

router-link标签

搭配router-view标签,用于切换组件。上面有to属性表示当前url后拼接的地址即使以https://开头依然会拼接在其后,注意不需要像a标签一样添加#了(直接to=’/one’即可),tag属性表示当前标签的显示形式(以HTML中的什么标签替换该标签,默认为a标签),显示点击后的标签的class会自动添加值’router-link-exact-active router-link-active’,在原router-link中设置属性active-class=’str’,则router-link-active会变成str

传递参数形式

方法一:通过URL参数在之后添加?key1=value1&key2=value2的形式,在组件对象的生命周期方法(例如one={template:'<div>one</div>’,created(){}})中通过this.$route.query拿到数据对象,对象的属性和值与其对应。

方法二:在指定路由规则时通过占位符传递数据属性名,通过URL传递数据属性值。例如const v=[{path:’/one/:name/:age‘,component:one,props:true},{path:’/two’,component:two}],<a href=’#/one/pyf/18‘>,在组件对象的生命周期方法(例   如one={template:'<div>one</div>’,created(){}})中通过this.$route.params拿到数据对象(不推荐,取值方式推荐使用下面代码),对象的属性和值与其对应(注意此时url/#/one/不能显示one组件了,只有url/#/one/str1/str2才能显示one组件,其中str1、str2可以随便写)。

通常通过在路由中开启props属性后,在组件中绑定传过来的对应属性名,后便可以在模板中直接使用。例如下面代码props开启后传递id属性。

const User = {
  // 请确保添加一个与路由参数完全相同的 prop 名
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
const routes = [{ path: '/user/:id', component: User, props: true }]

嵌套路由

在定义路由规则时,添加children属性,该属性为新的子路由规则例如const v=[{path:’/one’,component:one,children:[{path:’oneson’,component:oneson}]},{path:’/two’,component:two}],注意嵌套路由(子路由)可以省略一级路径的地址,且不用带/,例中切换到oneson组件时的url为….html#/one/oneson,注意router-link标签中的to写法还是不变(to=’/one/oneson’),切换组件oneson是在组件one下显示,而不会将整个one组件完全替换

重定向

当打开网页,想默认显示组件two而不在url后面加/two时,我们需要重定向,即在使用方法的第二步的数组中添加一个对象{path: ‘/’, redirect: ‘/two’ },此时当我们输入url(url/、url/#、url/#/都行)会自动给我们添加#/two,但是此时输入url/#/b则不会自动显示组件two(输入不对应的其它url也不会),如果想要显示,即可将path的路径/改为*即可(注意这些由于权重问题是不会影响跳转one组件的,正常输入one的url也会显示one组件)。如果是在嵌套路由中,即想默认显示子路由,我们需要将path:”。

路由拦截

当我们需要进行判断满足条件时在跳转(通常导航中的我的,当未登陆时跳转为登陆页面),这时我们可以在需要拦截到的组件的生命周期方法mounted中添加判断,当不满足时使用location.href=”或this.$router.push(”)进行跳转。Vue提供了更好的解决方法如下。

全局前置守卫

在创建VueRouter对象之后添加语句vr.beforeEach(funtion(to,from,next){}),当跳转到任何路由组件页面之前会运行function函数,其中to、from是一个对象,包含跳转路由的信息,to.fullPath指向跳转到的路由组件,from.fullPath指向由哪个路由组件跳转的,next为一个函数名,当next()执行时,才能跳转到to.fullPath的路径上去,也可以next(str)跳转到其它组件页面(str为路由路径例如’/one’)。

全局后置钩子

在创建VueRouter对象之后添加语句vr.afterEach(funtion(to,from){}),当跳转到路由组件页面后才会运行function函数,参数意义同上,无next。

局部守卫

都是组件的生命周期函数。

  1. beforeRouterEnter(to,from,next){}:在跳转到该页面之前被调用,如果只需要在单个路由组件中添加拦截,我们可以在需要拦截的组件对象中添加该方法,其中参数意义同上。
  2. beforeRouterUpdate(to,from,next){}:在路由改变,但组件被复用时调用,即嵌套路由中子组件之间的切换,参数同上。
  3. beforeRouterLeave(to,from,next){}:离开该组件的对应路由时调用,其中next(false)可以禁止离开。

命名路由

当定义路由规则的数组中的对象中添加属性name:’yf’,此时我们可以通过this.$router.push({name:’yf’,params:{name:’p’})访问设置name:’yf’路由的组件,也和点击下面router-link跳转。通过this.$route.params.name便可以拿到传入的参数’p’。

<router-link :to="{name:'yf',params:{name:'p'}}">
  User
</router-link>

路由模式(history)

通常我们在设置路由时未加#号,而在切换时自动加上了#号,这时由于路由的模式是hash模式,它还有一种history模式,即不带#号的模式,我们可以通过在定义路由规则的数组的对象中添加属性mode:’history’实现,此时切换该路由时将不带#号(由于没有网络请求改变,通过客户端改变的网络地址,且去除#号后相当于正常网页,刷新网页时,会像后端发送请求,如果后端没有正确配置会返回404,所以后端需要配置当URL匹配不到任何静态资源时,应该返回同一个页面)。

路由原理

  1. hash路由:location.hash切换,通过window.onhashchange监听路径的切换。
  2. history路由:history.pushState切换(IE10以上支持),window.onpopstate监听路径的切换,注意是没有网络请求的,通过客户端改变的网络地址

location.hash\history.pushState方法

js的BOM对象(window.location/history/navigator对象,弹出框,cookie,窗口和滚动条方法等)_YF-SOD的博客-CSDN博客

路由懒加载

项目(Vue-CLI)开发中,通常所有的路由都会在直接被打包(npm run build)到一个文件中,这时该文件过大,当客户端访问时网速不好,会导致加载过慢,此时我们可以采用路由懒加载(动态加载,当切换到该路由时,我们才去请求该路由的文件),会生成多个文件。使用方法:在定义路由规则时,将对象中的component属性指向一个函数function(){return import(/* webpackChunkName: “group-foo” */’path’)},其中path为该路由组件引入的相对路径,注释代表将该路由组件打包到带有group-foo的js文件命中(可以将多个组件合并到一个文件中),不写会单独打包。

自定义简易VueRouter(history模式) 

定义后通过Vue.use(VueRouter)注册路由插件,使用和上面使用方式相同。


let _Vue = null
export default class VueRouter {
    static install(Vue) {
        // 1.判断当前插件是否已经被安装
        if (VueRouter.install.installed) {
            return
        }
        VueRouter.install.installed = true
        // 2.把Vue构造函数记录到全局变量
        _Vue = Vue
        // 3.把创建Vue实例时候传入的router对象注入到Vue实例上
        // 混入
        _Vue.minxin({
            beforeCreate() {
                if (this.$options.router) {
                    _Vue.prototype.$router = this.$options.router
                }
                this.$options.router.init()
            }
        })
    }

    constructor(options) {
        this.options = options
        this.routeMap = {}
        this.data = _Vue.observable({
            current: '/'
        })
    }

    init() {
        // 遍历所有的路由规则,把路由规则解析成键值对的形式存储到routerMap中
        this.createRouteMap()
        // 注册router-link和router-view组件
        this.initComponents(_Vue)
        // 通过popstate监听url地址改变current值以及对应用到值的地方进行重新渲染。
        this.initEvent()
    }
    createRouteMap() {
        this.options.routes.forEach(route => {
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue) {
        const self = this
        Vue.component('router-link', {
            props: {
                to: string
            },
            render(h) {
                return h('a', {
                    attrs: {
                        href: this.to
                    },
                    on: {
                        click: this.clickHandler
                    }
                }, [this.$slot.default])
            },
            methods: {
                clickHandler(e) {
                    history.pushState({}, '', this.to)
                    this.$router.data.current = this.to
                    e.preventDefault()
                }
            }
            // template: '<a :href="to"><slot></slot></a>'
        })
        Vue.component('router-view', {
            render(h) {
                const component = self.routeMap[self.data.current]
                return h(component)
            }
        })
    }

    initEvent() {
        window.addEventListener('popstate', () => {
            this.data.current = window.location.pathname
        })
    }

}


自定义详细VueRouter(hash模式)  

GitHub – aiwmyself/VueRouter: VueRouter-hash

 

VueRouter官网

Vue Router


版权声明:本文为AIWWY原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。