23Vue-路由(二)

156 阅读7分钟
序言

router对象提供的两个重要的内置组件<router-link><router-view>。他是全局注册的。

我们创建了router对象,然后使用app.use(router)
当我们 app.use(router) 实质上是做了如下操作:
如果是一个对象的话,就会执行install函数,如果本身是一个函数,就会直接执行,这里是对象
router.install = function(app){
内部帮我们 注册全局组件
    app.component("router-link",{});
    app.component("router-view",{});
}
路由插槽及属性

通过上面的知识,我们知道:router-link实际上是一个组件,组件意味着:就可以使用插槽

<router-link to = "/home">
    <button>首页</button>
</router-link>

<router-link to="/about">关于</router-link>
<router-link to="/user">用户</router-link>

<router-view/>

此时,曾经只是一个a标签的router-link变成了button,但是实质上,他还是被a标签包裹,a标签里面单独存在了一个button标签

和旁边两个router-link形成了对比:

图片.png

如果我放置的是一个组件可以吗? 当然可以

components/NavBar.vue组件

<template>
    <div>{{title}}</div>
</template>

<script>
    export default{
        props:{
            title:String
        }
    }
</script>

App.vue

<template>
    <router-link to = "/home">
        <nav-bar title="首页"></nav-bar>
    </router-link>

    <router-link to="/about">关于</router-link>
    <router-link to="/user">用户</router-link>

    <router-view/>
</template>

<script>
    import NavBar from './components/NavBar.vue'
    export default{
        components:{
            NavBar
        }
    }
</script>

正常显示

图片.png

作用域插槽 v-slot,组件想要给插槽这里传递数据,就会用到作用于插槽

//props里有: href 跳转的链接
// route route路由对象
// navigate导航函数 
<router-link to = "/home" v-slot = "props">
    <button>{{props.href}}</button> 显示/home
    <p>{{props.route}}</p>
</router-link>

route对象内容

图片.png

custom属性(自定义)

<router-link to = "/home" v-slot = "props" custom>
    <button>{{props.href}}</button> 显示/home
    <button>哈哈哈</button>
</router-link>

此时button标签,不再是a标签里的内容了,变成了自定义的,并且连跳转都跳转不了,因为自定义要求你自己书写跳转逻辑。router-link to="/home"跳转失效

图片.png

自定义跳转(props中的:navigate导航函数)

<router-link to = "/home" v-slot = "props" custom>
    <button>{{props.href}}</button> 显示/home
    <button @click="props.navigate">
        哈哈哈
    </button>
</router-link>

使用@click=".."然后写上push方法也是可以的,但是既然给我们提供了导航函数,那么我们最好就试用一下。

点击home是没有反应的,点击哈哈哈就有反应,因为我设置了navigate导航函数

demo08.gif

props中的:isActive 是否当前处于活跃状态

<router-link to = "/home" v-slot = "props" custom>
//可以用来动态添加class
    <span :class="{'active':props.isActive}">
        {{props.isActive}}默认在此页面是true,不在就是false
    </span>
</router-link>

默认在home页面就是true,当我切换到其他页面的时候,就为false

demo08.gif

props中的:isExactActive 是否当前处于精确的活跃状态

和上方的isActive效果一样,只不过如果我router-link to="/home"那么必须URL里的后缀是/home才能为true,如果是/home/message,那么也是错误的。更加精准的匹配

以上全是作用域插槽 v-slot 的props属性

router-view增强
//动画
以前的写法:用transition标签包裹动态组件实现
<transition>
    <component :is="组件"></component>
</transition>

现在使用router-view的写法
router-view其实是一个占位的,显示组件本质是把对应的组件拿到router-view的地方。
直接使用router-view是拿不到组件的

通过作用域插槽拿到。
<router-view v-slot="props">
通过component属性拿到当前组件,:is是谁,我就显示谁
    <component :is="props.Component">
    </component>
</router-view>

实现动画效果:

<router-view v-slot = "props'>
    <transition name="why">
        <component :is="props.Component">
        </component>
    </transition>
</router-view>


<style scoped>
    .why-enter-from,
    .why-leave-to{
        opacity:0; 纯透明
        从透明度0开始来的
    }
    
    .why-leave-active,
    .why-enter-active{
        transition:opacity 1s ease;
    }
</style>

demo08.gif

组件的缓存:keep-alive

图片.png

图片.png

动态添加路由

const routes = [],并不是一上来就写死的,而是通过一些判断,一些需求来动态的添加。根据不同的权限使用这个路由

components/Category.vue

index.js

//普通创建的路由
const routes = [{},{}...]

//创建的一个路由对象router
const router = createRouter({
    routes,
    history:createWebHistory()
})

//动态添加路由
const categoryRoute = {
    path:"/category",
    component:()=>import("../pages/Category.vue")
}

//路由对象添加
router.addRoute(categoryRoute)

//添加二级路由对象
//就是我home组件下的moment子组件
router.addRoute("被添加的路由名称(由name定一定)",)

router.addRoute("home",{
    path:"moment",
    component:()=>import("../pages/HomeMoment.vue")
    //也可以写children
    children:[...]
})
动态删除路由(用的较少)

1.添加一个name相同的路由(原来的被替换了)

图片.png

2.通过removeRoute方法,传入路由的名称

图片.png

3.通过addRoute方法的返回值回调

图片.png

其他方法的补充:

图片.png

路由导航守卫

如果我用户还没有登录,就想进入用户界面,我们不允许这样,这个时候要想实现这样类似的操作,就可以用导航守卫。

在跳转(导航)到指定界面的时候,我们可以拦截掉,并做出判断,看看是否符合要求,符合要求就可以继续跳转,否则就取消/返回回去。

专门放在guard文件夹里

index.js

//导航守卫,先拿到router对象
router.beforeEach((to,from) => {
    //在进行路由跳转的时候,就会来到这个函数
    return false;//不允许跳转
})

to:Route对象,即将跳转到的Route对象

from:Route对象,从哪一个的路由对象导航过来的

返回值:

   false:不进行导航
   undefined或者不写:默认导航,该去哪还是去哪
   字符串:路径,跳转到对应的路劲中
   对象:router.push({path:"/",query:..})

还有一个next,但是不推荐使用,这里不展开讲

route.beforeEach((to,from)=>{
    if(to.path === "/home"){
        如果我想到home页面,那我这里
        就得写判断你有没有登录,
        没登录我就return false跳转失败
    }
    
    字符串:如果点击跳转home,则直接跳到/login
    if(to.path.indexOf("/home") !== -1){
        return "/login"
    }    
})

要求所有的页面,要想访问就必须登录,除了login页面

router.beforeEach((to,from)=>{
    if(to.path !== /"login"){
        return "/login"
    }
})

不管点击哪里,仍然还是login页面

demo08.gif

当我点击登录后,就进入首页

为了避免我登录后进入首页,然后首页判断不是登录页面,又跳回去,所以我还需要设置一个缓存,告诉首页我已经登陆过了(一个很小的登录逻辑)

Login.vue

<button @click = "loginClick"></button>

import {useRouter} from 'vue-router'
export default{
    setup(){
        const router = useRouter();
        const loginClick = ()=>{
        
            //设置缓存
            window.localStorage.setItem("token","why")
        
            router.push({
                path:"/home"
            })
        }
        return{
            loginClick
        }
    }
}

index.js

router.beforeEach((to,from)=>{
//如果我不是去往login,那么我就判断你有没有token
//有的话就获取一下,否则你就老实去登录
    if(to.path !== /"login"){
    //获取token,判断是否已经登陆过了
        const token = window.localStorage.getItem("token");
        
        if(!token){
            return "/login"
        }
        
    }
})

demo08.gif

其他的导航守卫

router.vuejs.org/zh/guide/ad…

(只是beforeEach中不用next,其他的也是可以用的 尤其是beforeRouteEnter要使用next回调函数)

完整的导航解析流程

图片.png

historyApiFallback的补充

图片.png

本身不需要我们配置,因为vue已经帮我们配置好了。我们需要对原理进行理解。

前端路由回顾:localhost:8080:是域名和端口号,(端口号可以不写,这里任意一个域名都是一样的,举个例子而已)当我们向服务器请求资源的时候,我们是通过此域名去访问静态服务器,浏览器会将我们这个域名进行dns解析,将域名解析成ip地址,根据ip地址找到对应的服务器。然后就可以找到静态资源(html/css/js),浏览器再将它返回给我们的前端,前端将获取到的静态资源进行解析,通过js代码来解析前端路由,如果js代码中有重定向,js就会执行,然后再将重定向用到的组件进行解析成js文件,最终决定界面上渲染的内容并且路径发生了改变。

这些重定向的内容都是在前端完成的所以是前端路由。

当我进入到某个具体路由的时候localhost:8080/home/message,我点击刷新页面时,浏览器会根据localhost:8080/home/message地址通过dns解析成之前的ip地址并且携带 /home/message路径 ,去服务器中寻找静态资源。之前我们只是通过/ 也就是根路径去寻找静态资源。但是我们再服务器中并没有配置这样的资源,该路径就不会匹配到静态资源,然后没有资源就会出现404。所以我们要通过配置Njax,然后配置try_files,如果找不到资源就去查找配置后的路径index.html,去那里查找,如果都没找到,try_files//index.html/index.html在后面再写一个index.html,就算找不到也一定会返回index.html。

为啥我在vue中不用配置Njax?因为vue cli在webpack中将historyApiFallback:true,表示 如果我找不到对应的资源,我会默认帮你返回根路径下面的/index.html

vue下的 /cli-service/lib/commands/serve.js帮我们配置了很多webpack的配置

图片.png

vue想要修改webpack中的配置,还可以可以通过vue提供的一个出口:vue.config.js(自己创建的)

导出我们自己想做的配置
module.export = {
    configureWebpack:{
        devServer:{
            historyApiFallback:false
        }
    }
}
他会覆盖源码中的配置