• Vue2:官方路由 Vue-Router 3.x


    前端路由

    前端路由:根据不同的url地址,页面上展示不同的内容(根据url地址的不同分发到不同的组件。)


    SPA 介绍

    spa 是 single page application 简写,意思是单页面应用程序。Vue 适合开发 spa 类型的项目。

    优点:

    • 业务场景的切换,性能很好。
    • 集中维护一个网站的功能。
    • 完全的前后端分离(前后端可以并行开发,提供系统开发效率)

    缺点:

    • 所有的功能集中的一个页面,依赖的资源是非常多的,加载第一次的时候很慢(首屏加载)
    • 业务复杂度很高(解决方案:vue组件、前端路由)

    前端路由原理

    基于 hash 的路由原理(通过地址栏 hash 字符串的改变,去更新页面的内容)

    • http://localhost:3000?username=lisi#abc
    • http://localhost:3000?username=lisi#hello
    • 锚点 (hash) 作用:跳转到网页的某一个位置
    • 锚点的变化不会导致浏览器重新向服务器发送一个请求。

    Vue 路由

    vue-router 是基于 vue 的 js 插件,实现了前端路由功能。

    下载地址:https://unpkg.com/vue-router/dist/vue-router.js

    Vue Router 3.x 是针对 Vue2 版本的官方路由。


    组件分类

    vue 文件分为两类,一个是页面组件,一个是复用组件。

    • 页面组件:页面展示 - 配合路由用
    • 复用组件:展示数据 / 常用于复用

    src/views(或pages) 文件夹下的页面组件,配合路由切换。

    src/components 文件夹下的一般引入到 src/views 下的 vue 中复用展示数据。

    基本使用

    基于 url 地址的变化实现组件的切换。一切都围绕着hash值变化为准。

    使用流程:下载路由,编写对应规则注入到vue实例上,使用router-view 挂载点显示切换的路由。

    main.js

    导入组件时,可以使用 @ 代替 ./,@的意思是在src文件夹下找文件。

    // 引入Router
    import VueRouter from 'vue-router'
    // 使用路由插件
    Vue.use(VueRouter)
    
    // 导入要切换的组件
    import Find from './views/Find.vue'
    import My from '@views/My.vue'
    import Part from '@views/part.vue'
    
    // 创建路由规则数组
    const routes = [
      {
        path: "/find",
        component: Find
      },
      {
        path: "/my",
        component: My
      },
      {
        path: "/part",
        component: Part
      }
    ]
    
    // 创建路由对象,传入规则
    const router = new VueRouter({
      routes
    })
    
    // 关联到Vue实例
    new Vue({
      router,
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    App.vue

    components 换成 router-view,用于组件内容渲染的地方。

    <template>
      <div>
        <div class="footer_wrap">
          <a href="#/find">发现音乐a>
          <a href="#/my">我的音乐a>
          <a href="#/part">朋友a>
        div>
        <div class="top">
          <router-view>router-view>
        div>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    声明式导航

    vue-router 提供了一个全局组件 router-link

    • router-link 实质上最终会渲染成 a 链接,to 属性等价于提供 href 属性,但是 to 属性不需要加 # ,直接写/组件名 就可以。

    • router-link 提供了声明式导航高亮的功能(自带类名)

    App.vue

    <template>
      <div>
        <div class="footer_wrap">
          <router-link to="/find">发现音乐router-link>
          <router-link to="/my">我的音乐router-link>
          <router-link to="/part">朋友router-link>
        div>
        <div class="top">
          <router-view>router-view>
        div>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    跳转传参

    在跳转路由时,给路由组件对应的组件内传值。

    router-link 的 to 属性传值:

    • /path?参数名=值
      
      • 1

      /pash/ 值:需要路由对象提前配置 path: “/pash/参数名”

    对应页面组件接收传递过来的值:

    • $route-query.参数名
      
      • 1
    • $route.params.参数名
      
      • 1
    语法格式

    : 的路径代表要接收具体的值

    App.vue

    <router-link to="/part?name=小传">朋友-小传router-link>
    <router-link to="/part/小智">朋友-小智router-link>
    
    • 1
    • 2

    main.js

    通过 params 传参,要使用路由定义。

    // 创建路由规则数组
    const routes = [
      {
        path: "/part",
        component: Part
      },
      {
        path: "/part/:username",
        component: Part
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    part.vue

    <template>
      <div>
          <p>人名: {{ $route.query.name }} -- {{ $route.params.username }}p>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    重定向和模式

    重定向

    匹配 path 后,强制切换到目标 path上。

    • 网页打开 url 默认 hash 值是 /路径。
    • redirect 是设置要重定向到哪个路由路径。

    应用场景:当网站需要一个默认页面时,可以将默认页强制重定向到首页。

    • 注意:强制重定向后,还会重新匹配一次数组中的规则。
    const routes = [
    	{
    		path: "/",
    		redirect: "/find"
    	},
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    404页面

    如果路径 hash 值,没有和数组里的规则匹配,则默认给一个 404 页面。

    语法:路由最后,path 匹配 * (任意路径) - 前面不匹配就命中最后这个,显示对应组件页面。

    const routes = [
      {
        path: "*",
        component: NotFound
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <router-link to="/404">404router-link>
    
    • 1
    模式设置

    hash 路由:http://localhost:8080/#/home

    history路由:http://localhost:8080/home(以后上线需要服务器端支持,否则找的是文件夹)

    区别:

    • hash (url中#后面的部分)虽然出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。

    • history 利用了 html5 history interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器记录栈

      hash 路由 和 history 路由一个加 #,一个不加 #

    main.js

    const router = new VueRouter({
      routes,
      mode: "history" // 打包上线后需要后台支持, 模式是 hash
    })
    
    • 1
    • 2
    • 3
    • 4

    编程式导航

    用 Js 代码跳转。

    <template>
      <div>
        <span @click="goFn('/find')">发现音乐span>
        <span @click="goFn('my')">我的音乐span>
        <span @click="goFn('part')">朋友span>
      div>
    template>
    
    <script>
    export default {
      methods: {
        goFn(targetPath) {
          this.$router.push({
            path: targetPath,
          })
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    多次点同一个按钮,会报错误:避免重复导航到当前位置:“/my”。

    7b09fd8ba95d4537863cd80524cf23d4

    解决这个错误,要在 router/index.js 中重写push方法,忽略报错

    // 原来的 push
    let originPush = VueRouter.prototype.push;
    // 重写push方法
    VueRouter.prototype.push = function (location) {
      return originPush.call(this, location).catch(err => err);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    跳转传参

    name 属性只有在js才会有用,决定跳转到哪里,其他时候选写。

    语法格式

    query需要 path 传值,使用path时,会忽略 params参数。

    params 需要 name 传值,name支持query 和 params传参。

    this.$router.push({
    	path: "路由路径",
        query: {
            "参数名":},
        
        name: "路由名",
        params: {
            "参数名":}
    })
    
    // 对应路由接收参数:$route.params.参数名
    // 对应路由接收参数:$route.query.参数名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    使用path时,会自动忽略params

    My.vue

    <template>
      <div>
        <h1>My Musich1>
        <span @click="goFn('find')">发现音乐-编程式导航span>
        <br />
        <span @click="goQuery">我的音乐-编程式导航queryspan>
        <br />
        <span @click="goParams">朋友-编程式导航paramsspan>
      div>
    template>
    
    <script>
    export default {
      methods: {
        goFn(targetPath) {
          this.$router.push({
            path: targetPath,
          })
        },
        goQuery () {
          this.$router.push({
            path: 'part',
            query: {
              name: '小传'
            }
          })
        },
        goParams () {
          this.$router.push({
            path: '/part',
            params: {
              username: '小智'
            }
          })
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    part.vue

    <template>
      <div>
          <h4>{{ $route.query.name }} -- {{ $route.params.username }}h4>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    嵌套和守卫

    路由嵌套

    在一级路由下,嵌套二级路由。

    思路:

    1. 在子组件中新建 router-link 标签,链接二级路由。

    2. 在 router/index.js 中的路由规则数组中,给一级路由添加 name 属性和 children 属性。

      children 属性中和一级路由一样,有路径 (path) 和 组件 (component)。

    语法格式:

    const routes = [
        // 一级路由1
        {
            path: '/find',
            component: Find,
            name: "Find",
            children: [
                // 二级路由1
                {
                    path: '/find/',
                    component: Recommend
                },
            ]
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Find.vue

    <template>
    	<div>
    		<div class="nav_main">
    			<router-link to="/find/recommend">推荐router-link>
    			<router-link to="/find/ranking">排行榜router-link>
    			<router-link to="/find/songlist">歌单router-link>
    		div>
    
    		<div style="1px solid red;">
    			<router-view>router-view>
    		div>
    	div>
    template>
    
    <style scoped>
    .nav_main {
    	background-color: red;
    	color: white;
    	padding: 10px 0;
    }
    .nav_main a {
    	text-align: center;
    	text-decoration: none;
    	color: white;
    	font-size: 12px;
    	margin: 7px 17px 0;
    	padding: 0px 15px 2px 15px;
    	height: 20px;
    	display: inline-block;
    	line-height: 20px;
    	border-radius: 20px;
    }
    .nav_main a:hover {
    	background-color: brown;
    }
    .nav_main .router-link-active {
    	background-color: brown;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    router/index.js

    路由规则数组在一级路由下写 children 属性,代表当前的二级路由。

    const routes = [
      {
        path: "/find",
        component: Find,
        // 二级路由
        name: "Find",
        children: [
          {
            path: "recommend",
            component: Recommend
          },
          {
            path: "ranking",
            component: Ranking
          },
          {
            path: "songlist",
            component: SongList
          }
        ]
      },
      // 404: 只需要在一级栏里给一个全局使用
      {
        path: "*",
        component: NotFound
      },
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    类名区分
    • router-link-exact-active(精确匹配)url 中 hash 值路径,与 href 属性值完全相同,设置此类名。
    • router-link-active(模糊匹配)url 中 hash 值,包含 href 属性值这个路径。
    全局前置守卫

    路由跳转之前,先执行前置守卫函数,判断是否可以正常跳转。

    语法格式:

    router.beforeEach((to, from, next) => {
        if (to.path == '目标页面' && 登录状态 == false) {
            // 未登录执行代码块。
            next(false);	// 阻止跳转
        } else {
            next();		// 已登录,放行
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    属性:

    • to:要跳转的路由。
    • from:从哪里跳转的路由。
    • next:函数体。

    应用场景:在跳转路由之前,判断用户是否登录,为登录弹窗提示,登录后跳转到 我的音乐 页面。

    const router = new VueRouter({
      routes,
    })
    
    // 模拟登录状态
    let isLogin = false;
    
    router.beforeEach((to, from, next) => {
        if (to.path == '/find' && isLogin == false) {
            alert('请登录');
            next(false);	// 阻止跳转
        } else {
            next();		// 放行
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    vant 组件库

    vant 是一个轻量、可靠的移动端Vue组件库,开箱即用。

    官网地址:https://vant-contrib.gitee.io/vant/#/zh-CN/

    特点:

    • 提供60多个高质量组件,覆盖移动端各类场景。
    • 性能极佳,组件平均体积不到 1kb。
    • 完善的中英文文档实例。
    • 支持 Vue2 & Vue3。
    • 支持按需引入和主题定制。
    全部引入
    1. 全部引入,快速开始:https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart
    2. 下载vant 组件库到当前项目中。
    3. 在 main.js 中全局导入所有组件。
    4. 使用按钮组件,作为示范的例子。
    方式一:导入所有组件

    Vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,不推荐。

    1. 下载 vant 组件

      yarn add vant -D
      
      • 1
    2. 导入所有组件,到 main.js 中

      import Vue from 'vue';
      import Vant from 'vant';
      import 'vant/lib/index.css';
      
      Vue.use(Vant);
      
      • 1
      • 2
      • 3
      • 4
      • 5
    3. 使用按钮组件

      https://vant-contrib.gitee.io/vant/#/zh-CN/button

      <van-button type="primary">主要按钮van-button>
      <van-button type="info">信息按钮van-button>
      <van-button type="default">默认按钮van-button>
      <van-button type="warning">警告按钮van-button>
      <van-button type="danger">危险按钮van-button>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    方式二:手动按需求引入

    只引入使用的组件。

    在不使用插件的情况下,可以手动引入需要的组件。

    1. 手动单独引入,快速开始:https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart

      import Button from 'vant/lib/button';	// button 组件
      import 'vant/lib/button/style';	// button 样式
      
      • 1
      • 2
    2. 注册

      components: {
      	VanButton: Button	// 手动注册组件名
      	[Button.name]: Button	// 等价的
      }
      
      • 1
      • 2
      • 3
      • 4
    3. 使用

      <van-button type="primary">主要按钮van-button>
      <van-button type="info">信息按钮van-button>
      <van-button type="default">默认按钮van-button>
      <van-button type="warning">警告按钮van-button>
      <van-button type="danger">危险按钮van-button>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    方式三:自动按需求引入

    按需求加载组件。

    babel-plugin-import 是一款 babel 插件,他会在编译过程中将import 的写法自动转换为按需求引入的方式。

    1. 安装插件

      yarn add babel-plugin-import -D
      
      • 1
    2. 在 babel 配置文件里 (babel.config.js)

      module.exports = {
        plugins: [
          ['import', {
            libraryName: 'Vant',
            libraryDirectory: 'es',
            style: true
          }, 'vant']
        ]
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    3. 全局注册 (main.js)

      import Vue from 'vue'
      
      import 'vant/lib/index.css'
      import { Button } from 'vant'
      Vue.use(Button);
      
      • 1
      • 2
      • 3
      • 4
      • 5
    弹出框使用

    弹出模态框,常用于消息提示、消息确认,或在当前页面内完成特定的交互操作。

    https://vant-contrib.gitee.io/vant/#/zh-CN/dialog

    <template>
    	<div>
        	<van-button type="primary" @click="btn">提示弹窗van-button>
        div>
    template>
    
    <script>
        // 导入提示弹窗
        import { Dialog } from "vant";
    
        export default {
            methods: {
                btn() {
                    // 属性
                    Dialog({
                        title: '标题',
                        message: "提示",
                        showCancelButton: true
                    });
                },
            }
        };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Dialog 是一个函数,调用后会直接在页面中弹出相应的模态框。

    Dialog 是一个方法,要在需要使用的组件中导入,不可以在 main.js 中导入。

    • title:提示框的标题
    • message:提示内容
    • showCanceButton:是否带取消按钮。
      • true:带取消按钮,相当于 Dialog.confirm()
      • false:不带取消按钮,相当于 Dialog.alert()

    表单使用

    用于数据录入、校验,支持输入框、单选框、复选框、文件上传等类型,需要与 Field 输入框 组件搭配使用。2.5 版本开始支持此组件。

    https://vant-contrib.gitee.io/vant/#/zh-CN/form

    导包
    import { Form, Field } from 'vant'
    Vue.use(Form);
    Vue.use(Field);
    
    • 1
    • 2
    • 3
    语法格式
    
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    校验规则

    通过 rules 定义表单校验规则。

    键名说明类型
    required是否为必选字段boolean
    message v2.5.3错误提示文案string | (value, rule) => string
    validator v2.5.3通过函数进行校验(value, rule) => boolean | Promise
    pattern v2.5.3通过正则表达式进行校验RegExp
    trigger v2.5.2本项规则的触发时机,可选值为 onChangeonBlurstring
    formatter v2.5.3格式化函数,将表单项的值转换后进行校验(value, rule) => any

    登录框

    <van-form @submit="onSubmit">
        <van-field
                   v-model="username"
                   name="username"
                   label="username"
                   placeholder="用户名"
                   :rules="[{ required: true, message: '请填写用户名' }]"
                   />
        <van-field
                   v-model="password"
                   type="password"
                   name="password"
                   label="password"
                   placeholder="密码"
                   :rules="[{ required: true, message: '请填写密码' }]"
                   />
        <div style="margin: 16px;">
            <van-button round block type="info" native-type="submit">
                提交
            van-button>
        div>
    van-form>
    
    <script>
        export default {
            data() {
                return {
                    username: '',
                    password: '',
                };
            },
            methods: {
                onSubmit(values) {
                    console.log('submit', values);
                },
            },
        };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    跨域

    端口不一样,

    反向代理解决跨域

    本地 node 服务器开启 cors,负责请求的转发和数据接收回传。

  • 相关阅读:
    typescript学习(二)
    2022年全国最新消防设施操作员(中级消防设施操作员)真题题库及答案
    软件测试用例设计练习
    设计模式---策略模式
    毕业季,终于毕业了!
    郑州灵活用工平台的市场价值大吗?
    Android修改开机动画
    2023湖南省赛-B Square game
    一次元数据空间内存溢出的排查记录
    Talk预告 | 微信AI高级研究员苏辉:微信AI大规模预训练语言模型WeLM
  • 原文地址:https://blog.csdn.net/qq_41952539/article/details/127877366