21-22Vue-路由(入门)

150 阅读5分钟
前端路由

图片.png

ip地址--真实电脑的mac地址:他们两个会有一个映射关系

图片.png

后端路由

JSP、ASP、PHP

图片.png

前后端分离(主讲 前端路由)

图片.png

现在公司的开发模式:SAP(单一页面程序) S:single P:page A:application

整个应用程序里有多个页面,home、about、category; 每个页面可以是一个组件,当我路径是/home,就渲染home组件,路径是/about,就渲染/about组件。

我前端根据不同的路径,切换不同的页面,和后端没有关系。

我实现以上操作的时候,就会有:路径--组件 的映射关系 /home--Home.vue /about--About.vue

当我路径发生改变时,我就在某个位置渲染对应的组件,具体位置需要一个占位(router-view),等我路径为/home的时候,我就把Home.vue放在占位里;

如果在浏览器地址栏,输入主要网页名,但是用户把/home输入进来,浏览器会去静态服务器 请求静态资源,但是我们不想让用户请求到静态服务器。我们希望用户在前端上,通过点击切换,来到达对应的页面。因此我们可以将/home地址设置成一个hash值:#home,就不会再向服务器请求资源的。也可以设置为history模式,也不会再请求静态服务器的静态资源了。

1.URL的hash

图片.png

例子:

图片.png

vue的路由原理和这个例子差不多

2.history模式

history和哈希的最大区别:history更像真实路径,哈希会有一个 # 号

图片.png

go(-1):后退一步; go(1):前进一步

此方法的好处:修改了路径,但是不会再请求资源

图片.png

<body>
  <div id="app">
    <a href="/home">home</a>
    <a href="/about">about</a>

    <div class="content">Default</div>
  </div>

  <script>
    const contentEl = document.querySelector('.content');

    const changeContent = () => {
      console.log("-----");
      switch(location.pathname) {
        case "/home":
          contentEl.innerHTML = "Home";
          break;
        case "/about":
          contentEl.innerHTML = "About";
          break;
        default: 
          contentEl.innerHTML = "Default";
      }
    }

    const aEls = document.getElementsByTagName("a");
    for (let aEl of aEls) {
      aEl.addEventListener("click", e => {
        e.preventDefault();
        
        const href = aEl.getAttribute("href");
        // history.pushState({}, "", href);
        history.replaceState({}, "", href);
        
        changeContent();
      })
    }

    window.addEventListener("popstate", changeContent)

  </script>
</body>

认识vue-router

进入新的URL后,如果页面刷新,浏览器是会向服务器请求静态资源的。我们需要做到,进入新的URL,也不会向服务器请求静态资源。

图片.png

vue-router有:path -- 组件 之间的映射

     路径/home -- Home.vue组件
     
路由的使用

1.安装Vue Router

    npm install vue-router@4

2.创建路由组件的组件

2.1新建一个pages文件夹,里面存放组件:Home.vue
<template>
    <div>Home</div>
</template>

<script>
    import 
    export default{
        components:{
            
        }
    }
</script>
2.2在pages文件夹里再存放组件:About.vue
<template>
    <div>About</div>
</template>

<script>
    import 
    export default{
        components:{
            
        }
    }
</script>

3.配置路由映射:组件和路径映射关系的routes数组

src下新建router文件夹,存放路由配置
创建index.js文件
1.导入组件
import Home from '../pages/Home.vue'
import About from '../pages/Aout.vue'

4.使用路由对象和模式的前提:先导入
import {
createRouter, //有了这个函数,才能创建想要的路由对象
createWebHistory, //web端的history模式
createWebHashHistory  //web端的Hash模式
} from 'vue-router'

2.存储映射关系,由于映射关系会很多,所以用数组存储
里面存放的是对象,URL书写的路径名和组件名
const routes = [
    {
        path:'/home',
        component:Home
    },
    {
        path:'/about',
        component:About
    },
];

3.通过createRouter创建路由对象,并传入routes和history模式
//5.创建一个路由对象router
const router = createRouter({
    routes, //映射关系
    history:createWebHashHistory()  //指定模式
})

6.将 路由对象 导出出去,让别人使用路由
export default router

5.使用路由,通过<router-link><router-view>

前提:在main.js

import router from './router'

const app = createApp(App)

//把当前的路由对象看做是一个插件,use安装使用插件
app.use(router)
app.mount('#app')

使用:App.vue

<template>
    <div>
        <h2>哈哈</h2>
        //渲染出来组件的内容,全部在这里展示
        <router-view/>
        <div>呵呵</div>
    </div>
</template>
<script>
    export default{
        components:{
        }
    }
</script>

demo01.gif

当我后缀名是/home的时候,router-view就会显示home组件的内容,当我后缀名是/about的时候,router-view就会显示about组件的内容

点击按钮,切换路径

<template>
    <div>
    //router提供的一个组件,他包含 to 属性
    //我点击首页的时候跳转到首页,关于跳到关于
        <router-link to="/home">首页</router-link>
        <router-link to="/about">关于</router-link>
        
        <router-view/>
    </div>
</template>

<script>
    export default{
        components:{
        }
    }
</script>

<router-link to=".."/>本质是一个 a 元素。

demo02.gif

我点击首页,就会显示Home.vue组件的内容,并且URL的后缀是/home,关于 也同理

路由的默认路径

我们一打开页面的时候,URL是一个 / ,所以我们希望一进来就有相应的数据显示,我们就需要进行默认路径的配置

index.js

const routes = [
    多一条默认路径 / 的配置,默认显示Home组件
    {path:"/",component:Home}
]

更优质的默认路径:重定向(redirect)

当我们访问默认路径的时候,我们就重定向到/home,也就意味着匹配到一个组件:Home.vue。

const routes = [
    {path:"/",redirect:"/home"}
]

demo03.gif

我们默认访问的是8080,但是会重定向到/home

router-link补充

replace属性

<router-link to="/home" replace>

Home组件写上了replace,我从/home进入到/about后,想要从/about 后退到/home页面的时候,其实已经不给后退了。他和push 相反,push可以有后退的操作

active-class属性

图片.png App.vue

它是用来激活a元素后应用的class,默认是router-link-active

<template>
<router-link to="/home" active-class="why-active">
</template>

<style>
    .why-active{
        color:red;
    }
</style>

图片.png

路由懒加载

官方推荐:所有路由的组件全部设置成懒加载;

懒加载:用到的时候才会加载

index.js

import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'
//我以前在这里还需要导入Home和About组件,使用懒加载就不用这样import导入了

const routes = [
{
//我传入的不再是组件对象,而是一个函数
    path:"/home",
    component:()=>{
        return import("../pages/Home.vue")
    }
},
{
//魔法注释,对这个东西打包的时候,告诉webpack名字
    path:"/about",
    component:()=>{
    //在前面写(/*webpackChunkName:"自己取"*/)
        return import(
        /*webpackChunkName:"自己取"*/
        "../pages/About.vue")
    }
},
]

当我npm run build打包时,路由懒加载出来的组件就不会再次 存在于 默认包里了,这样再第一次页面渲染的时候会加速渲染效果。

图片.png

关于懒加载,还有一种写法,一个意思

//写在了上方
const home = () => import("../pages/Home.vue")

const routes = [
    {
        path:"/home",
        component:home
    }
]

图片.png

路由的其他属性

name:设置名字,独一无二的名称,根据名字进行跳转(用的很少)

meta:在别的地方可以拿到route对象,然后根据route.meta,可以拿到meta中存储的属性

const routes = [
    {
        path:"/home",
        name:"home", //取名字,也可以根据名字进行跳转
        component:home,
        meta:{
            name:"lyx",
            age:18,
        }
    }
]
动态路由的基本匹配

我们希望,如果用户 why 登录,跳转到User.vue,那么URL标签可以显示/why。如果是lyx,那么就显示/lyx。我们曾经都是写死的/user的,通过动态路由实现此效果。

$route的具体信息

图片.png

在pages中新建User.vue的用户组件

<template>
在template中获取数据不用this
    <div>
    User:{{$route.params.username}}
    </div>
</template>

<script>
//通过引用useRoute函数,在setup中拿到$route
    import {useRoute} from 'vue-router'
    export default{
        created(){
            console.log(this.$route.params.username)
        //$route里有一个params属性,里面有username属性
        },
        
        //我想在setup中拿到username
        setup(){
            //这里面没有this,怎么拿呢?
            const route = useRoute();
          //他会返回用户点击的用户对象
          //点击首页,返回首页的route对象
          console.log(route.params.username)
        }
    }
</script>

index.js

const routes = [
    {
    //1.路径不写死,后面写 /:username
        path:"/user/:username",
        
        component:()=>{
        return import(
        "../pages/User.vue"),
        
    }
]

App.vue

<template>
    <div>
    //2.跳转的时候,就不能写死了
        <router-link to = "/user/why">
        用户
        </router-link>
    //3.升级版写法,动态绑定实现
    <router-link :to = '/user/'+name>
    </div>
</template>

<script>
    export default{
        setup(){
            name:"why",
            return{
                name
            }
        }
    }
</script>

图片.png

图片.png

NotFound

如果我随便输入一个路径,对应的路径是没有组件的,显示的是空白的,对于用户来说是不友好的,我们需要 给用户显示一个组件。

实质上也是一个映射关系

path:去匹配一个不存在的路径

const routes = [
//vue会先找满足条件的映射,没有的话最后才走这里
// .* 表示0-多个任意字符
    path:"/:pathMatch(.*)", //完整字符串
    path:"/:pathMatch(.*)*",
//多了一个*,会以数组形式存储,以/为分隔符,将输入的url字符串,存放在数组中

    component:()=>import("../NotFound.vue")
]
路由的嵌套

图片.png 点击首页会显示一个组件,但是我希望再点击Home的时候,再能显示一个组件,这就是路由嵌套

msg.vue

<template>
    <h2>Msg组件</h2>
    <ul>
        <li>msg1</li>
        <li>msg2</li>
        <li>msg3</li>
    </ul>
</template>

<script>
    export default{
        components:{
        }
    }
</script>

shops.vue

<template>
    <h2>shop组件</h2>
    <ul>
        <li>shop1</li>
        <li>shop2</li>
        <li>shop3</li>
    </ul>
</template>

<script>
    export default{
        components:{
        }
    }
</script>

Home.vue

<template>
    <div>
        <h2>Home</h2>
        <ul>
            <li>Home1</li>
            <li>Home2</li>
            <li>Home3</li>
        </ul>
        
        占位,匹配上后显示路由组件
        <router-view/>
        
        <router-link to="/msg">消息</router-link>
        <router-link to="/shops">商品</router-link>
        
        
    </div>
</template>

index.js

我们发现:msg和shops都是home的

const routes = [
    {
        path:"/home",
        name:"home",
        component:()=>import("/Home.vue"),
        meta:{
            name:"why",
            age:18,
        },
        //此时多了一个children属性
        children:[
            {
            //这里不用再精确写 /home/msg
            //vue会从home查找,就表示一定是以/home开头的,直接写msg名称
                path:"msg",
                component:"Mes.vue"
            },
            {
                path:"shops",
                component:shops.vue
            }
        ]
    }
]

补充

我只给我的/home写了router-link-active,那么我的/home/shops会被匹配吗?

答案是会的,那么怎么样可以避免呢? router-link-exact-active用来精准匹配

如果想要重定向到home组件下的子组件,那么就得写全 图片.png

编程式导航(代码的页面跳转)

About.vue

取传来的query
<template>
<h2>{{$route.query.name}}</h2>
</template>

App.vue

<template>
    <button @click = "jumpToAbout">
        首页
    </button>
</template>

<script>
//导入hook
import {useRouter} from 'vue-router'
    //1.使用methods
    methods:{
        jumpToAbout(){
        //这里router是index.js中创建的路由对象
            this.$router.push("/about")
        }
    },
    //2.使用setup,就得使用hook
    setup(){
        const router = useRouter();
    
        const jumpToAbout = ()=>{
            //router.push('/about')
            
            也可以传对象
            router.push({
                path:"/about",
            //跳转后,顺便把参数也传过去了    
                query:{
                    name:"123",
                    age:18
                }
             //URL会显示name=123&age=18
            })
          //router.replace("/about")  
            
        },
        return{
            jumpToAbout
        }
    }
</script>

此时点击button也是可以跳转页面的 demo04.gif