学习笔记:Vue2高级篇

Vue2

  1. 学习笔记:Vue2基础篇_ljtxy.love的博客-CSDN博客
  2. 学习笔记:Vue2中级篇_ljtxy.love的博客-CSDN博客
  3. 学习笔记:Vue2高级篇_ljtxy.love的博客-CSDN博客

Vue3

  1. 学习笔记:Vue3_ljtxy.love的博客)-CSDN博客

    文章目录

7.Vuex(多组件共享状态)

笔记小结:

  1. 概述:Vuex 是 Vue.js 官方提供的状态管理库,用于在 Vue.js 应用中集中管理应用的状态(数据)。简单点说,多组件之间可以共享某些数据的状态

  2. 使用示例:

    • 步骤一:安装Vuex

      npm i vuex @3 //此处项目为vue2则可以直接执行,相应版本vue请自行百度
      

      注意:Vuex 版本与Vue版本不对应则不能使用在Vue中应用

    • 步骤二:创建Vuex目录和JS文件

      image-20231218170002476

    • 步骤三:编写index.js基本结构

      // 1.引入Vue
      import Vue from 'vue'
      // 2.引入Vuex
      import Vuex from "vuex"
      // 3.使用VueX插件
      Vue.use(Vuex)
      // 4.准备组件动作
      // 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
      const actions={}
      // 4.2准备mutations负责更新的对象——用于操作数据(state)
      const mutations={}
      // 4.3准备state状态对象——用于存储数据
      const state={}
      // 4.4准备getters获取状态对象——用于获取存储数据
      const getters={}
      // 5.创建并暴露store对象
      export default new Vuex.Store({
          //传入配置对象(此方法类似于,new Vue时编写的配置对象)
          actions,
          mutations,
          state,
          getters
      })
      
    • 步骤四:引入配置项

      // 修改main.js
      
      // 1.引入store
      import store from "./vuex/store"
      
      const vm = new Vue({
      ……
          //2.配置store
          store:store, // store简写
      ……
      })
      

7.1概述

7.1.1定义

​ Vuex 是 Vue.js 官方提供的状态管理库,用于在 Vue.js 应用中集中管理应用的状态(数据)。它解决了组件之间共享状态的问题,使得状态的变化更加可预测、可维护。Vuex也是组件间通信的一种方式,且适用于任意组件间的通信。

补充:状态管理什么意思

  1. 组件通信: 当一个组件的状态需要被另一个组件访问或修改时,通常需要通过 props 和事件来传递数据。但这在多层嵌套的情况下会变得繁琐,尤其是当数据需要在多个层级之间传递时。
  2. 跨组件状态同步: 如果多个组件共享相同的状态,确保状态在这些组件之间保持同步可能会变得复杂。当一个组件修改了状态,其他组件也需要得知并作出相应的响应。
  3. 全局状态: 有时候需要在整个应用中共享状态,而不仅仅是在某个组件树中。例如,用户登录状态、主题设置等。
  4. 异步操作管理: 处理异步操作,如数据获取或提交,可能导致嵌套的回调,使代码变得难以理解和维护。

例如:多组件共享数据

  • 方式一:全局事件总线实现

image-20231209165632874

说明:

​ 当一个组件A中的数据需要在组件B或组件C或组件D中修改获取时,就会写很多次$bus.$emit$bus.$on方法。若组件变得越来越多,则会写很多次API

  • 方式二:Vuex实现

image-20231209164525166

说明:

​ Vuex不属于任何一个组件。若其余组件向获得或者修改Vuex中的属性x的值则可以使用Vuex提供的API进行实现。也就是说如果A组件把x的值改为了20,那么其余组件看到的x的值就为20,组件之间的数据是共享的

补充:Vuex和Plugins和Mixin三者区别

  • Plugins是一种对 Vue.js 进行功能扩展的方式。Plugins允许你在全局或局部范围内添加 Vue 的功能或者添加全局方法/属性。通常,插件会在 Vue 实例化之前被应用
  • Mixin 是一种 Vue.js 提供的一种分发组件中可复用功能的方式。Mixin 允许你在多个组件之间共享组件选项。通过混入,你可以在多个组件中重复使用一些相同的逻辑、生命周期钩子等。
  • Vuex 是 Vue.js 官方提供的状态管理库,用于管理应用中的状态。与插件和混入不同,Vuex 主要关注于解决组件之间的状态共享和管理问题。它提供了一个集中式的状态存储,包括状态、mutations、actions 和 getters。

7.1.2作用

  1. 集中式状态管理: Vuex 提供了一个全局的状态管理器,称为「store」。在这个 store 中,包含了应用的所有组件共享的状态。这种集中式的状态管理使得在整个应用中能够轻松地追踪和管理状态的变化。
  2. 共享状态: Vuex 可以用来管理那些需要在多个组件之间共享的状态,例如用户登录信息、主题设置、购物车状态等。通过将这些状态集中管理,不同组件之间可以方便地共享和访问。
  3. 状态的可预测性: 在 Vuex 中,状态的变化是可追踪的。所有的状态变化都通过提交 mutation 来进行,每个 mutation 都有一个明确的类型。这种限制确保了状态变化的可控性,使得应用的状态变化变得可预测。
  4. 方便的状态获取和修改: 在组件中,通过使用 Vuex 提供的辅助函数,可以轻松地获取和修改全局状态。不再需要手动通过 props 和事件进行状态的传递和修改,从而简化了组件之间的通信。
  5. 支持异步操作: Vuex 提供了 actions 来处理异步操作,例如数据获取、API 请求等。通过 actions,可以更灵活地处理异步逻辑,并且在异步操作完成后再提交 mutation 来修改状态。
  6. 插件扩展: Vuex 支持插件,可以方便地扩展其功能。这使得开发者可以根据需要引入额外的功能,如日志记录、持久化存储等。

补充:VueX的应用时机

  1. 多个组件依赖于同一个状态(当A组件的内容需要被重复使用时,可以将A组件内容放入Vuex中,便于共享)
  2. 来自不同组件的行为需要变更同一状态(例如:A组件通过点击事件改变X的值+1,B组件通过鼠标滑过图片改变X的值乘上10倍。不同的行为)

7.2基本用例-Vuex导入

说明:

​ 在项目中导入Vuex,搭建Vuex使用的基础环境

步骤一:安装Vuex库

说明:

​ Vuex是一个插件,因此需要在项目中先安装插件才能使用

npm i vuex@3

注意:

  • Vuex 版本与Vue版本不则不能使用在Vue中应用

image-20231210113115125

  • 例如:vue2中,要用vuex的3版本,vue3中,要用vuex的4版本

说明:

  • 项目安装完Vuex后,可以在项目的package.json文件中进行版本查看

image-20231210113425781

步骤二:创建vuex目录和JS文件

说明:

​ 通常在项目的Src目录下新建Store.js文件

image-20231210114042304

步骤三:引入配置项

说明:

​ 修改项目的main.js文件

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// 1.引入Vuex插件中的store
import store from "./vuex/store"

const vm = new Vue({
    el: "#app",
    render: h => h(App),
    // 在组件实例(VC)上安装store,使得所有的Vm和VC对象上都可以看到store
    //2.配置store
    store:store, // store简写
    //安装全局事件总线
    beforeCreate() {
        Vue.prototype.$bus = this
    },
})

说明:

image-20231210131709781

  • 在所有的Vm和VC对象上都都会多一个$store属性

步骤四:准备Store基础结构

说明:

​ 修改Store.js文件。该文件由于创建VueX中最为核心的store对象。store对象会用来管理actions对象、mutations对象、state对象。详细介绍查看Vuex工作原理

// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={}
// 4.3准备state状态对象——用于存储数据
const state={}
// 4.4准备getters获取状态对象——用于获取存储数据
const getters={}
// 5.创建并暴露store对象
export default new Vuex.Store({
    //传入配置对象(此方法类似于,new Vue时编写的配置对象)
    actions,
    mutations,
    state,
    getters
})

注意:

  • 再创建Vuex.Store实例之前需要使用Vuex插件,确保Vuex插件能够正常的启用,才能进行Store对象的创建。因此需要引入Vue,并在创建Store之前使用Vuex插件

image-20221121203731260

  • 补充:Js对象Key和Value简写

Js语法当对象中key跟value的名字,值是一样的时候,可以触发简写形式。例如actions:actions可以简写为actions

  • 补充:Vue脚手架Import语法解析

    • 脚手架解析import语句时会将Import语句提前

      • 运行代码:

        image-20221121203946039

      • 输出结果:

    image-20221121203932216

    • 实际执行代码:

    image-20221121204007896

步骤五:演示

image-20231210132127265

说明:

​ 当搭建完基础环境后,就相当于把Vuex中的Store对象创建好了。但是呢,并没有和组件建立联系

7.3案例-Vuex简单求和案例(Vuex简单应用)

前提:

​ 已将Vuex在此项目中导入,详细可查看"基本用例-Vuex导入"小节

步骤一:创建Vuex作为存储容器

说明:

​ 在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件。在"store.js"文件的actions对象里创建“逻辑动作”的方法,在mutations对象里创建“状态变更”的方法

// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions = {
    plusOne(context, value) { // context参数是vuex的上下文,value参数是传过来的数据
        value = value + 1
        context.commit("PLUS_ONE", value)
    }
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations = {
    PLUS_ONE(state, value) { //state参数是状态对象,value参数是上一环节传过来的数据
        state.num += value
    }
}
// 4.3准备state状态对象——用于存储数据
const state = {
    num: 10
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters = {
    bigNum(state) { //state参数是状态对象
        return state.num
    }
}
// 5.创建并暴露store对象
export default new Vuex.Store({
    //传入配置对象(此方法类似于,new Vue时编写的配置对象)
    actions,
    mutations,
    state,
    getters
})

补充:了解即可,详细见Vuex工作原理

  • Actions(动作)

    • 作用actions 用于处理异步操作或包含多个 mutation 的复杂操作actions 包含一组方法,每个方法都是一个 action。在 action 中可以执行异步操作,然后通过提交 mutations 来修改状态。
    • 使用场景处理异步操作、封装复杂的业务逻辑,例如从后端获取数据后再提交 mutations 修改状态。
    actions: {
      asyncIncrement(context) {
        // 异步操作
        setTimeout(() => {
          // 提交 mutations 修改状态
          context.commit('increment') //补充:通过 commit 方法提交 mutations,actions 可以改变应用的状态。在组件中通过 dispatch 方法触发 actions 的执行。
        }, 1000)
      }
    
    
  • Mutations(变更)

    • 作用mutations 用于修改 Vuex 中的状态,它包含一组方法,每个方法都是一个 mutation。每个 mutation 都有一个字符串的事件类型(type)和一个回调函数,回调函数是实际执行状态变更的地方。
    • 使用场景通常用于处理同步的状态变更,例如修改某个变量的值。由于 mutations 是同步执行的,因此不适合处理异步操作。
    mutations: {
      increment(state) {
        state.count++
      },
      decrement(state) {
        state.count--
      }
    }
    
  • Getters(获取器)

    • 作用getters 用于对 Vuex 中的状态进行计算和返回,类似于组件中的计算属性。getters 是存取器的一种,允许你在获取状态时进行一些处理,然后返回一个新的值。
    • 使用场景当你希望获取 state 中的数据经过一些计算后再使用,或者希望在组件中获得派生状态而不直接修改原始状态时使用。
    getters: {
        // 示例:计算 state 中 count 的平方值
        squaredCount: (state) => {
            return state.count * state.count;
        },
    
        // 示例:获取符合某条件的用户列表
        activeUsers: (state) => {
            return state.users.filter(user => user.isActive);
        }
    }
    

步骤二:创建应用Vuex的组件

说明:

​ 创建并编写App.vue组件,实现简单的加法操作,体会Vuex的功能存储。使用Vuex提供的$store.dispatchAPI根据Vuex中的"store.js"文件的actions对象里的方法名来进行参数的传递

<template>
    <div>
        <!--通过使用Vuex提供存储,直接调用相应的对象方法即可获取"store.js"文件中的state状态对象的值-->
        当前num值:{{ $store.getters.bigNum }}<br>
        <button @click="addMethod">点我+1</button>
    </div>
</template>

<script>
export default {
    name: "TestCount",
    data() {
        return {
            num: 0
        }
    },
    methods: {
        addMethod() {
            // 通过使用Vuex提供的“dispatch”API来进行调用
            this.$store.dispatch("plusOne", this.num)
        }
    }
}
</script>
<style scoped>
</style>

步骤三:演示

image-20231214115736117

说明:

​ 当点击页面按钮时,数值成功累加

7.4Vuex工作原理(Vuex工作机制)✳

笔记小结:

​ 此小节重点,请详细查看

image-20231210112800766

说明:

​ Vuex由三个重要的核心对象组成,分别是Actions、Mutations、State

说明:核心对象解释

  1. State(状态):
    • 作用: 用于存储应用级别的状态,即数据
    • 特点: State 是响应式的,当 State 中的数据发生变化时,相关的组件将自动重新渲染。
  2. Mutations(变更):
    • 作用: 用于修改 State 中的数据
    • 特点: Mutations 中包含一系列的回调函数,每个函数都是一个 mutation。每个 mutation 都有一个字符串的事件类型(type)和一个回调函数(handler),它们共同完成状态的变更。Mutation 必须是同步函数。
  3. Actions(动作):
    • 作用: 用于提交 Mutations,而不是直接变更状态。
    • 特点: Actions 可以包含异步操作,比如网络请求、定时器等。它是组件与 Mutations 之间的桥梁,通过 Action 触发 Mutations 的变更。Actions 中的回调函数(handler)会接收一个 context 对象,包含了一些工具函数,其中最常用的是 context.commit 用于提交 Mutations。

image-20231215115747089

说明:组件使用Vuex的两种常用方式

  • 方式一:业务复杂触发
    • VC(Vue Components)组件通过 this.$store.dispatch("xxx",value)触发Action 操作实现函数异步调用
    • Action操作的回调函数callback(context,value)中通过 context.commit 触发Mutations操作实现State的数据修改
  • 方式二:业务简单触发
    • VC(Vue Components)组件通过this.$store.dispatch("xxx",value)触发Mutations操作 实现 State 的数据修改

7.5案例-Vuex实现求和案例(Vuex常规应用)

步骤一:创建Vuex作为存储容器

说明:

​ 在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件。在"store.js"文件的actions对象里创建“逻辑动作”的方法,在mutations对象里创建“状态变更”的方法

// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={
    jiaOdd(context,value){
        // console.log("action被调用了",context,value);
        // console.log(context,value);//$dispatch,$commit
        if(context.state.sum % 2){
            context.commit("JIA",value)
        }
    },
    jiaWait(context,value){
        setTimeout(() => {
            context.commit("JIA",value)
        }, 500);
    }
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={
    JIA(state,value){
        // console.log("mutations中的JIA被调用了",state,value);
        this.state.sum+=value
    },
    JIAN(state,value){
        this.state.sum-=value
    },
}
// 4.3准备state状态对象——用于存储数据
const state = {
    sum: 10,
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters={
    bigSum(state){
        return state.sum*10
    }
}
// 5.创建并暴露store对象
export default new Vuex.Store({
    //传入配置对象(此方法类似于,new Vue时编写的配置对象)
    actions,
    mutations,
    state,
    getters
})

注意:

​ 当state中的数据需要经过加工后再使用时,通常使用getters加工

步骤二:创建应用Vuex的组件

说明:

​ 创建App.vue组件,实现奇数求和已经延时相加的功能

<template>
<div>
    <h1>当前求和为:{{ $store.state.sum }}</h1> <!--可以通过$store.state获取state对象里面的num属性值-->
    <h1>当前求和10倍为:{{ $store.getters.bigSum }}</h1><!--也可以通过$store.getters获取getters对象里面bigSum函数的返回值-->
    <select v-model="number">
        <option :value="1">1</option>
        <option :value="2">2</option>
        <option :value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button>
    </div>
</template>

<script>
    export default {
        name: "App",
        data() {
            return {
                number: 1,
            };
        },
        methods: {
            increment() {
                // 业务逻辑简单,直接提交“mutations”里方法即可
                this.$store.commit("JIA", this.number);
            },
            decrement() {
                 // 业务逻辑简单,直接提交“mutations”里方法即可
                this.$store.commit("JIAN", this.number);
            },
            incrementOdd() {
                 // 业务逻辑复杂,可发送至“actions”里面方法
                this.$store.dispatch("jiaOdd", this.number);
            },
            incrementWait() {
                // 业务逻辑复杂,可发送至“actions”里面方法
                this.$store.dispatch("jiaWait", this.number);
            },
        },
        mounted() {
            // console.log(this);
        },
    };
</script>

步骤三:演示

image-20231215143234896

说明:

​ 当点击页面按钮后,存储在Vuex中的store.js文件中的值成功累加

7.6mapState与mapGetter(实现state和 getter 的使用优化)

笔记小结:

  1. 概述:在 Vuex 中,mapStatemapGetters 是用于简化在 Vue 组件中访问状态(state)和 getter 的辅助函数

  2. 使用方式:

    前提:项目中已经导入Vuex并能正常使用

    • 步骤一:导入

      // 在计算对象中书写一下方法
      ...mapState({ sum: "sum", school: "school", lesson: "lesson" }), // 对象写法
      ...mapGetters(["bigSum"]), //数组写法
      
    • 步骤二:直接使用

      <!--修改组件中的template标签中-->
      <h1>当前求和为:{{ sum }}</h1>
      <h1>当前求和10倍为:{{ bigSum }}</h1>
      <h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
      
  3. 总结:

    1. mapState方法:用于帮助我们映射state中的数据

      computed: {
          //借助mapState生成计算属性:sum、school、subject(对象写法)
           ...mapState({sum:'sum',school:'school',subject:'subject'}),
      
          //借助mapState生成计算属性:sum、school、subject(数组写法)
          ...mapState(['sum','school','subject']),
      },
      
    2. mapGetters方法:用于帮助我们映射getters中的数据

      computed: {
          //借助mapGetters生成计算属性:bigSum(对象写法)
          ...mapGetters({bigSum:'bigSum'}),
      
          //借助mapGetters生成计算属性:bigSum(数组写法)
          ...mapGetters(['bigSum'])
      },
      

7.6.1概述

​ 在 Vuex 中,mapStatemapGetters 是用于简化在 Vue 组件中访问状态(state)和 getter 的辅助函数。它们都属于 Vuex 的辅助函数库,通过这些函数,你可以更方便地将 Vuex 中的状态和 getter 映射到组件的计算属性中。

7.6.2基本用例-mapState和mapGetter使用

说明:

​ 此案例和"7.5案例-Vuex实现求和案例"小节的内容相差不大,只是从Vuex读取值时变为了mapStatemapGetters

步骤一:创建Vuex作为存储容器

说明:

​ 在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件

// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={
    jiaOdd(context,value){
        // console.log("action被调用了",context,value);
        // console.log(context,value);//$dispatch,$commit
        if(context.state.sum % 2){
            context.commit("JIA",value)
        }
    },
    jiaWait(context,value){
        setTimeout(() => {
            context.commit("JIA",value)
        }, 500);
    }
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={
    JIA(state,value){
        // console.log("mutations中的JIA被调用了",state,value);
        this.state.sum+=value
    },
    JIAN(state,value){
        this.state.sum-=value
    },
}
// 4.3准备state状态对象——用于存储数据
const state = {
    sum: 0,
    school:"尚硅谷",
    lesson:"HTML"
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters={
    bigSum(state){
        return state.sum*10
    }
}
// 5.创建并暴露store对象
export default new Vuex.Store({
    // 当对象中key跟value的名字,值是一样的时候,可以触发简写形式
    actions,
    mutations,
    state,
    getters
})

步骤二:创建应用Vuex的组件

说明:

​ 创建App.vue组件,将Vuex组件的store.js文件中的stategetters对象里的属性或方法通过Vuex提供的mapStatemapGetterAPI来进行相应的对象简写应用

<template>
  <div>
    <h1>当前求和为:{{ sum }}</h1>
    <h1>当前求和10倍为:{{ bigSum }}</h1>
    <h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
    <select v-model="number">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button>
  </div>
</template>

<script>
// 映射状态
import { mapState, mapGetters } from "vuex";
export default {
  name: "App",
  data() {
    return {
      number: 1,
    };
  },
  computed: {
    // 程序员亲自动手写代码,太麻烦
    // he() {
    //   return this.$store.state.sum;
    // },
    // xuexiao() {
    //   return this.$store.state.school;
    // },
    // xueke() {
    //   return this.$store.state.class;
    // },
    // Es6写法,当把一个对象放入另一个对象时,可用三个.表示剥离
    //借助mapState生成计算属性,读取state中的数据。(对象写法)
    // ...mapState({ sum: "sum", school: "school", lesson: "lesson" }),
    //借助mapState生成计算属性,读取state中的数据。(数组写法)
    //双引号内的东西既是计算属性中的函数名,又是state中的数据属性
    ...mapState(["sum", "school", "lesson"]),
    // 程序员亲自动手写代码,太麻烦
    // bigHe() {
    //   return this.$store.getters.bigSum;
    // },
    //借助mapGetters生成计算属性,读取state中的数据。(对象写法)
    // ...mapGetters({ bighe: "bigSum" }),
    //借助mmapGetters生成计算属性,读取state中的数据。(数组写法)
    ...mapGetters(["bigSum"]),
  },
  methods: {
    increment() {
      this.$store.commit("JIA", this.number);
    },
    decrement() {
      this.$store.commit("JIAN", this.number);
    },
    incrementOdd() {
      this.$store.dispatch("jiaOdd", this.number);
    },
    incrementWait() {
      this.$store.dispatch("jiaWait", this.number);
    },
  },
  mounted() {},
};
</script>

说明:

  • ...mapState(["sum", "school", "lesson"])含义:利用展开运算符 (…) 将 mapState 返回的数组中的元素作为独立的属性进行展开
……
computed:{
     ...mapState(["sum", "school", "lesson"]),
}
……
  • mapState(["sum", "school", "lesson"]) 返回一个包含要映射到组件中的状态属性名称的字符串数组
  • 利用展开运算符 ... 将该数组的元素展开。
  • 最终生成的对象将包含在组件的计算属性中。

补充:数组写法和对象写法区别

  • 数组写法
...mapState(["sum", "school", "lesson"]),
  • 对象写法
...mapState({ sum: "sum", school: "school", lesson: "lesson" }),
  • 数组写法和对象写法都适用,不过对象写法有一个映射功能

步骤三:演示

image-20231215150048965

说明:

​ 在步骤二中通过Vue提供的计算属性联合ES6的展开运算符写法以及Vuex提供的stategetter辅助函数实现了数据的累加

7.7mapActions与mapMutations(实现actions 和 mutations 的使用优化)

笔记小结:

  1. 概述:在 Vuex 中,mapActionsmapMutations 是用于简化在 Vue 组件中分发 actions 和提交 mutations 的辅助函数

  2. 使用方式:

    前提:项目中已经导入Vuex并能正常使用

    • 步骤一:导入

      // 在方法对象中书写一下方法
      ...mapActions({ // 对象写法
          incrementOdd: "jiaOdd",
          incrementWait: "jiaWait",
      }), 
      // ...mapMutations(["JIA", "JIAN"]), // 数组写法
      ...mapMutations({ // 对象写法
          increment: "JIA",
          decrement: "JIAN",
      }),
      
    • 步骤二:直接使用

      <!--修改组件中的template标签中-->
      <button @click="increment(number)">+</button>
      <button @click="decrement(number)">-</button>
      <button @click="incrementOdd(number)">当前求和为奇数再加</button>
      <button @click="incrementWait(number)">等一等再加</button>
      
  3. 总结:

    1. mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

      methods:{
          //靠mapActions生成:incrementOdd、incrementWait(对象形式)
          ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
      
          //靠mapActions生成:incrementOdd、incrementWait(数组形式)
          ...mapActions(['jiaOdd','jiaWait'])
      }
      
    2. mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

      methods:{
          //靠mapActions生成:increment、decrement(对象形式)
          ...mapMutations({increment:'JIA',decrement:'JIAN'}),
      
          //靠mapMutations生成:JIA、JIAN(对象形式)
          ...mapMutations(['JIA','JIAN']),
      }
      

7.7.1概述

​ 在 Vuex 中,mapActionsmapMutations 是用于简化在 Vue 组件中分发 actions 和提交 mutations 的辅助函数。它们都属于 Vuex 的辅助函数库,通过这些函数,你可以更方便地在组件中调用 actions 和 mutations。

7.7.2基本用例-mapActions和mapMutations使用

步骤一:创建Vuex作为存储容器

说明:

​ 在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件

// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={
    jiaOdd(context,value){
        // console.log("action被调用了",context,value);
        // console.log(context,value);//$dispatch,$commit
        if(context.state.sum % 2){
            context.commit("JIA",value)
        }
    },
    jiaWait(context,value){
        setTimeout(() => {
            context.commit("JIA",value)
        }, 500);
    }
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={
    JIA(state,value){
        // console.log("mutations中的JIA被调用了",state,value);
        this.state.sum+=value
    },
    JIAN(state,value){
        this.state.sum-=value
    },
}
// 4.3准备state状态对象——用于存储数据
const state = {
    sum: 0,
    school:"尚硅谷",
    lesson:"HTML"
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters={
    bigSum(state){
        return state.sum*10
    }
}
// 5.创建并暴露store对象
export default new Vuex.Store({
    // 当对象中key跟value的名字,值是一样的时候,可以触发简写形式
    actions,
    mutations,
    state,
    getters
})

步骤二:创建应用Vuex的组件

说明:

​ 创建App.vue组件,将Vuex组件的store.js文件中的actionsmutations对象里的方法通过Vuex提供的mapActionsmapMutations来进行相应的对象简写应用

<template>
    <div>
        <h1>当前求和为:{{ sum }}</h1>
        <h1>当前求和10倍为:{{ bigSum }}</h1>
        <h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
        <select v-model="number">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
        </select>
        <button @click="increment(number)">+</button>
        <button @click="decrement(number)">-</button>
        <button @click="incrementOdd(number)">当前求和为奇数再加</button>
        <button @click="incrementWait(number)">等一等再加</button>
    </div>
</template>

<script>
// 映射状态
import {mapActions, mapGetters, mapMutations, mapState} from "vuex";

export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Count",
    data() {
        return {
            number: 1,
        };
    },
    computed: {
        //借助mapState生成计算属性,读取state中的数据。(对象写法)
        // ...mapState({ sum: "sum", school: "school", lesson: "lesson" }),
        //借助mapState生成计算属性,读取state中的数据。(数组写法)
        //双引号内的东西既是计算属性中的函数名,又是state中的数据属性
        ...mapState(["sum", "school", "lesson"]),
        //借助mapGetters生成计算属性,读取state中的数据。(对象写法)
        // ...mapGetters({ bighe: "bigSum" }),
        //借助mmapGetters生成计算属性,读取state中的数据。(数组写法)
        ...mapGetters(["bigSum"]),
    },
    methods: {

        // increment() {
        //   this.$store.commit("JIA", this.number);
        // },
        // decrement() {
        //   this.$store.commit("JIAN", this.number);
        // },
        //注意mapMutations内不能写入Vuex中Mutations对象里回调函数的第二个属性值,而在使用此方法的时候加“()”进行传递参数即可
        // 对象写法
        ...mapMutations({
            increment: "JIA",
            decrement: "JIAN",
        }),
        // 数组写法
        // ...mapMutations(["JIA", "JIAN"]),
        // incrementOdd() {
        //   this.$store.dispatch("jiaOdd", this.number);
        // },
        // incrementWait() {
        //   this.$store.dispatch("jiaWait", this.number);
        // },
        // 对象写法
        ...mapActions({
            incrementOdd: "jiaOdd",
            incrementWait: "jiaWait",
        }),
        // 数组写法
        // ...mapActions(["jiaOdd", "jiaWait"]),
    },
};
</script>

步骤三:演示

image-20231215153940874

说明:

​ 在步骤二中通过Vue提供的方法属性联合ES6的展开运算符写法以及Vuex提供的actionsmutations辅助函数实现了数据的累加

7.8模块化命名空间(为Vuex状态使用NameSpace管理)✳

笔记小结:

  1. 概述:在 Vuex 中,模块化命名空间(Module Namespacing)是为了解决当应用变得复杂,存在**多个模块管理不同状态**。简单说,让代码更好维护,让多种数据分类更加明确

  2. 使用方式:

    • 步骤一:定义模块

      // 定义模块时开启命名空间
      const countAbout = {
          ……
          namespaced:true,//开启命名空间
          ……
      }
      
    • 步骤二:注册模块

    • 步骤三:使用模块

      • 组件中读取state数据

        //方式一:自己直接读取
        this.$store.state.personAbout.list
        //方式二:借助mapState读取:
        ...mapState('countAbout',['sum','school','subject']),
        
      • 组件中读取getters数据

        //方式一:自己直接读取
        this.$store.getters['personAbout/firstPersonName']
        //方式二:借助mapGetters读取:
        ...mapGetters('countAbout',['bigSum'])
        
      • 组件中调用dispatch

        //方式一:自己直接dispatch
        this.$store.dispatch('personAbout/addPersonWang',person)
        //方式二:借助mapActions:
        ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
        
      • 组件中调用commit

        //方式一:自己直接commit
        this.$store.commit('personAbout/ADD_PERSON',person)
        //方式二:借助mapMutations:
        ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
        

7.8.1概述

​ 在 Vuex 中,模块化命名空间(Module Namespacing)是为了解决当应用变得复杂,存在**多个模块管理不同状态**时,防止命名冲突而提供的一种机制。

说明:

​ 在 Vuex 中,如果应用变得复杂,可能会有多个模块负责管理不同的状态。为了避免命名冲突,Vuex 提供了模块化的命名空间

  • 优点:
  • 避免命名冲突: 每个模块都有自己的命名空间,防止了不同模块之间的命名冲突,提高了代码的可维护性。
  • 清晰的模块调用: 使用命名空间的方式在代码中清晰地表示出调用的是哪个模块的状态、mutations、actions 或 getters。

7.8.2基本用例-模块化命名空间应用

说明:

​ 完成模块化命名空间的基本应用

步骤一:创建Vuex容器并完成初始化Vuex操作

前提:

  • 在项目src目录钟创建了store文件夹

image-20231218145726844

1.在Store中注册模块

说明:

​ 在store目录下创建index.js文件,实现子模块的导入

// 导入 Vue 和 Vuex 插件
import Vue from 'vue'
import Vuex from "vuex"

// 使用 Vuex 插件, 确保Vuex插件能够正常的启用
Vue.use(Vuex)

// 导入模块化的 Vuex 模块
import moduleAbout from "./module"

// 创建 Vuex 的 Store 实例,同时注册模块
export default new Vuex.Store({
  // 当使用模块化编程时,加上 modules 前缀使得 Vuex 改为模块化编程
  modules: {
    moduleAbout, // 注册名为 "moduleAbout" 的模块,模块的实现在 "./module" 文件中
  }
})

说明:

​ 子模块的导入,需要先进行2.创建Store的定义模块步骤再来导入

补充:

​ 在 Vuex 中,可以将 store 分割成模块(module),每个模块拥有自己的 state、mutations、actions 等。这样可以更好地组织和维护大型应用的状态管理。

2.在Store中定义模块

说明:

​ 在store目录下创建module.js文件,并开启命名空间,并实现actionsmutationsgetters方法

export default {
  namespaced: true, // 开启命名空间
  state: { // state状态对象——用于存储数据
    count: 0,
  },
  mutations: { // mutations负责更新的对象——用于操作数据(state)
    increment(state) {
      state.count++;
    },
  },
  actions: { // action负责执行某个行为的对象——用于响应组件中的动作
    asyncIncrement(context) {
      setTimeout(() => {
        context.commit('increment');
      }, 1000);
    },
  },
  getters: { // getters获取状态对象——用于获取存储数据
    doubleCount(state) {
      return state.count * 2;
    },
  },
};

说明:

​ 由于子模块moudle.js文件开启了命名空间进行Vuex的管理,所以这里在VC(VueComponent)组件中使用Vuex插件时会有所变化

步骤二:在组件中使用模块

// 在组件中使用模块的 state
this.$store.state.moduleAbout.count; // 使用 'moduleAbout' 模块的 count 状态

// 在组件中使用模块的 mutation
this.$store.commit('moduleAbout/increment'); // 调用 'moduleAbout' 模块的 increment mutation

// 在组件中使用模块的 action
this.$store.dispatch('moduleAbout/asyncIncrement'); // 调用 'moduleAbout' 模块的 asyncIncrement action

// 在组件中使用模块的 getter
this.$store.getters['moduleAbout/doubleCount']; // 获取 'moduleAbout' 模块的 doubleCount getter

说明:

​ 使用的时候不再可直接访问了,而需要通过Vuex提供的模块的moduleAbout命名空间名称才能进行相关访问

7.8.3案例-多组件共享数据(开发中常用)✳

说明:

  • 项目总目录结构

image-20231218154201222

步骤一:完成项目初始化操作

前提:

​ 使用Vue提供的脚手架工具创建Vue2的项目

1.创建componentsstore目录

2.初始化各目录相关内容

补充:

项目目录结构请参考项目总目录图

2.1在components目录中创建Count.vuePerson.vue

2.2在store目录中创建index.jsperson.jscount.js

说明:

​ 创建index.js是为了注册模块,创建person.jscount.js是为了定义模块

3.初始化项目入口文件

说明:

​ 修改项目main.js文件,并安装Store以及全局事件总线

// 该文件是整个项目的入口文件

// 引入VUE
import Vue from 'vue'
// 引入APP组件,它是所有组件的父组件
import App from './App.vue'
// 引入store
import store from "@/store/index.js";

// 关闭Vue的生产提示
Vue.config.productionTip = false


// 创建Vue实例对象
new Vue({
    el: "#app",
    render: h => h(App),
    // 在VC上安装store,使得所有的组件都可以看到store
    store,
    //安装全局事件总线
    beforeCreate() {
        Vue.prototype.$bus = this
    },
})

步骤二:注册模块

说明:

​ 修改项目中src/store/index.js文件,并注册count.jsperson.js

import Vue from 'vue'
import Vuex from "vuex"
import countAbout from "./count"
import personAbout from "./person"

Vue.use(Vuex)


export default new Vuex.Store({
    //当使用模块化编程时,加上modules前缀使得VueX改为模块化编程
    modules: {
        countAbout,
        personAbout,
    }
})

步骤三:定义模块

1.count.js

说明:

​ 修改项目中src/store/count.js文件

export default {
    namespaced: true,//当将VueX进行模块化编程时,得开启命名空间,以便在传入值时区分
    actions: {
        //context 上下文
        jiaOdd(context, value) {
            if (context.state.sum % 2) {
                context.commit("JIA", value)
            }
        },
        jiaWait(context, value) {
            setTimeout(() => {
                context.commit("JIA", value)
            }, 500);
        }
    },
    mutations: {
        //state里面的状态
        JIA(state, value) {
            state.sum += value
        },
        JIAN(state, value) {
            state.sum -= value
        },
    },
    state: {
        sum: 0,
        school: "尚硅谷",
        lesson: "HTML",
    },
    getters: {
        bigSum(state) {
            return state.sum * 10
        }
    }
}

2.person.js

说明:

​ 修改项目中src/store/person.js文件

import axios from "axios"
import {nanoid} from "nanoid";

export default {
    namespaced: true,//当将VueX进行模块化编程时,得开启命名空间,以便在传入值时区分
    actions: {
        addPersonWang(context, value) {
            if (value.name.includes("玥")) {
                context.commit("ADD_PERSON", value)
            } else {
                alert("添加的人必须是玥!!!")
            }
        },
        addPersonServe(context) {
            axios.get("https://api.uixsj.cn/hitokoto/get?type=social").then(
                response => {
                    console.log(response.data);
                    context.commit("ADD_PERSON", {id: nanoid(), name: response.data})//此处要写入对象的形式
                },
                error => {
                    console.log(error.message);
                }
            )
        }
    },
    mutations: {
        ADD_PERSON(state, value) {
            state.personList.unshift(value)
        }
    },
    state: {
        personList: [{id: "001", name: "张三"}, {id: "002", name: "玥玥"}]
    },
    getters: {
        firstPersonName(state) {
            return state.personList[0].name
        }
    }
}

步骤四:注册组件

说明:

​ 修改项目App.vue文件,并注册Person.vueCount.vue组件

<template>
    <div>
        <Count></Count>
        <hr/>
        <Person></Person>
    </div>
</template>

<script>


import Count from "@/components/Count.vue";
import Person from "@/components/Person.vue";

export default {
    name: "App",

    methods: {},
    components: {
        Count,
        Person,
    },
};
</script>

步骤五:定义组件

1.定义Count.vue组件✳

说明:

​ 修改Count.vue组件方法,使用四个Map(mapStatemapGettermapActionsmapMutations

<template>
    <div>
        <h1>当前求和为:{{ sum }}</h1>
        <h1>当前求和10倍为:{{ bigSum }}</h1>
        <h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
        <h3 style="color: red">Person组件的总人数为:{{ personList.length }}</h3>
        <select v-model="number">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
        </select>
        <button @click="increment(number)">+</button>
        <button @click="decrement(number)">-</button>
        <button @click="incrementOdd(number)">当前求和为奇数再加</button>
        <button @click="incrementWait(number)">等一等再加</button>
    </div>
</template>

<script>
// 映射状态
import {mapActions, mapGetters, mapMutations, mapState} from "vuex";

export default {
    name: "Count",
    data() {
        return {
            number: 1,
        };
    },
    computed: { // mapState 和 mapGetters 是用于将 Vuex 的状态(state)和计算属性(getters)映射到 Vue 组件中的工具函数。这两者返回的是计算属性,因此应该放在 Vue 组件的 computed 选项中,因为 computed 属性允许你声明一个计算属性
        ...mapState("countAbout", ["sum", "school", "lesson"]),
        ...mapState("personAbout", ["personList"]),
        ...mapGetters("countAbout", ["bigSum"]),
    },
    methods: { // mapMutations 和 mapActions 则是用于将 Vuex 中的 mutations 和 actions 映射到 Vue 组件中的工具函数。这两者返回的是方法,因此应该放在 Vue 组件的 methods 选项中。
        ...mapMutations("countAbout", {
            increment: "JIA",
            decrement: "JIAN",
        }),
        ...mapActions("countAbout", {
            incrementOdd: "jiaOdd",
            incrementWait: "jiaWait",
        }),
    },
};
</script>

补充:简单来说

  • mapState 和 mapGetters 返回的是计算属性,应该放在 Vue 组件的 computed 选项中。这是因为计算属性用于派生出其他属性,而 mapState 和 mapGetters 实际上就是派生出的属 性。

image-20231218163459803

image-20231218163450298

  • mapMutationsmapActions 返回的是方法,应该放在 Vue 组件的 methods 选项中。这是因为方法用于处理一些操作,而 mapMutationsmapActions 实际上就是操作的方法。

image-20231218163513836

image-20231218163521995

2.定义Person.vue组件

说明:

  • 修改Person.vue组件方法,使用Vuex提供的常规API。
  • 通过this.$store.state.命名空间.属性来读取store模块中的state数据、通过 this.$store.dispatch("命名空间/方法名", 值)来操作store模块中的action方法、通过this.$store.commit("命名空间/方法名", 值)来操作store模块中的mutations方法、通过this.$store.getters["命名空间/方法名"]来读取store模块中的getters方法
<template>
    <div>
        <h1>人员列表</h1>
        <h2 style="color: red">Count组件的求和为:{{ sum }}</h2>
        <h3>列表中第一个人的名字是:{{ firstPersonName }}</h3>
        <input type="text" name="" id="" placeholder="请输入名字" v-model="name"/>
        <button @click="add">添加</button>
        <button @click="addYue">添加一个含玥的人</button>
        <button @click="addPersonServe">添加一个人,名字随机</button>
        <ul>
            <li v-for="person in personList" :key="person.id">
                {{ person.name }}
            </li>
        </ul>
    </div>
</template>

<script>
import {nanoid} from "nanoid";

export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Person",
    data() {
        return {
            name: "",
        };
    },
    computed: {
        sum() {
            return this.$store.state.countAbout.sum;
        },
        personList() {
            return this.$store.state.personAbout.personList;
        },
        firstPersonName() {
            // 模块化分类getters特殊写法
            return this.$store.getters["personAbout/firstPersonName"]; //如果在 . 语法中想要写 / 必须由[] 括起来
        },
    },
    methods: {
        add() {
            const temp = {id: nanoid(), name: this.name};
            // 模块化分类特殊写法
            this.$store.commit("personAbout/ADD_PERSON", temp);
            this.name = "";
        },
        addYue() {
            const temp = {id: nanoid(), name: this.name};
            // 模块化分类特殊写法
            this.$store.dispatch("personAbout/addPersonWang", temp); //通过dispatch与Actions联系
            this.name = "";
        },
        addPersonServe() {
            this.$store.dispatch("personAbout/addPersonServe");
        },
    },
    mounted() {
        // console.log(this.$store);
    },
};
</script>

<style>
</style>

步骤六:演示

image-20231218165011513

说明:

​ 当我们在任一一个组件中通过Vuex提供的Api进行操作时,数据发生改变,另一个组件中的数据也会发生相应变化

8.Router(页面切换)✳

8.1概述

8.1.1含义

​ 在 Vue.js 中,route 通常是指 Vue Router(路由器)中的路由对象。Vue Router 是 Vue.js 的官方**路由管理器,它允许你构建单页面应用(SPA)**,通过映射路由和组件的关系,实现页面之间的切换而无需刷新页面

8.1.2SPA应用(单页面应用)

​ SPA(Single Page Application,单页面应用)是一种现代化的网页应用程序架构。与传统的多页面应用(MPA)不同,SPA 在加载时只会加载单个 HTML 页面,并在用户与应用程序交互时动态更新页面内容,而无需重新加载整个页面。

image-20231218174902226

说明:

​ 简单来说,如果需要完成单个HTML页面的开发,通常需要使用Vue提供的路由来进行开发

8.1.3路由

路由器(Router)是一个用于管理和组织路由的工具。在Vue中,通常使用vue-router库来实现路由功能,它提供了一种在Vue应用中配置路由的方式。vue-router允许你定义路由规则,将不同的路径映射到不同的Vue组件,从而实现单页应用的页面切换。

路由(Route)是指确定应用程序如何响应特定的请求或路径的机制。在 Web 开发中,路由通常用于确定哪个组件或页面应该显示给用户,根据用户在浏览器中输入的路径或触发的操作,决定渲染哪个视图。

image-20231218175625353

说明:

​ 通常来说,一个应用中通常就只有一个路由器,并且一个路由器管理多个路由

  • 路由可以分为后端路由和前端路由
    1. 后端路由:
      • 理解: 后端路由的 value 通常是一个函数,用于处理客户端提交的请求。这样的路由工作在服务器端,根据请求的路径找到匹配的函数来处理请求,并返回相应的数据。
      • 工作过程: 当服务器接收到一个请求时,它会根据请求的路径(key)调用相应的函数(value)来处理请求,然后返回响应数据。
    2. 前端路由:
      • 理解: 前端路由的 value 通常是一个组件,用于展示页面内容。这样的路由工作在客户端,根据用户在浏览器中输入的路径或触发的操作,决定渲染哪个组件来显示相应的页面。
      • 工作过程: 当浏览器的路径改变时,前端路由会匹配相应的路径规则,并将对应的组件显示在页面上,而不需要向服务器发起新的请求。

8.1.4路由工作原理

image-20231218175625353

说明:

  1. 当用户点击了页面上的组件,导致路径发生了变化
  2. 路由器监听到路径发生的变化
  3. 路由器会根据路由的规则来找到相应的组件
  4. 并把组件返回给页面,页面上的内容就实现了切换

补充:

image-20231221175341417

8.2基本用例-Router导入示例

步骤一:安装vue-router库

说明:

​ 因为vue-router是一个插件,所以需要先在项目中安装后才能进行使用

npm i vue-router@3

注意:

  • Vue-Router 版本与Vue版本不则不能使用在Vue中应用

image-20231218180442864

  • 例如:vue2中,要用vue-router的3版本,vue3中,要用vue-router的4版本

说明:

  • 项目安装完Vuex后,可以在项目的package.json文件中进行版本查看

image-20231218181119929

步骤二:创建router目录和JS文件

说明:

​ 通常在项目的router目录下新建index.js文件

image-20231218181240632

步骤三:引入配置

说明:

​ 修改项目的main.js文件

// 该文件是整个项目的入口文件

// 引入VUE
import Vue from 'vue'
// 引入APP组件,它是所有组件的父组件
import App from './App.vue'
// 1.导入VueRouter插件,以便在本项目中能够使用路由器
import VueRouter from "vue-router"
// 2.使用VueRouter插件
Vue.use(VueRouter)
// 3.引入路由器实例,以便在本项目中能够注册使用路由器
import router from "./router/index.js"
// 关闭Vue的生产提示
Vue.config.productionTip = false

// 创建Vue实例对象
new Vue({
  el:"#app",
  render: h => h(App),
  router
})

说明:

image-20231222144751127

  • 当项目挂载完router之后,在VC(Vue Component)组件上就会出现$route$router属性

补充:

  • $router身上有很多实用的方法,以后会详细介绍

image-20231222145100013

步骤四:创建路由组件

说明:

​ 路由的组件,通常放置在src/pages目录下

1.创建About.vue路由组件

说明:

​ 创建src/pages/About.vue组件

<template>
    <div>
        <h1>我是About组件</h1>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "About",
};
</script>

<style>
</style>

2.创建Home.vue路由组件

说明:

​ 创建src/pages/Home.vue组件

<template>
  <h1>我是Home组件</h1>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Home",
};
</script>

<style>
</style>

步骤五:修改vue-router插件规则

说明:

​ 修改src/router/index.js文件

//该文件用于创建整个应用的路由器
import  VueRoute  from "vue-router";
//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";

//创建并暴露一个路由器
export default new VueRoute({//传入一个对象
  routes:[//此处为routes,注意别写为routers,否则页面路由配置没有一个可以成功,无展示效果
    {
        path:"/about",	//key—value写法
        component:About
    } ,
    {
        path:"/home",// 这个可以看作路由的key
        component:Home //这个可以看作路由的value
    }
  ]
})

说明:

​ 通常来说,一个应用中通常就只有一个路由器,并且一个路由器管理多个路由。所以这里需要引入Vue提供的vue-router作为路由器,并创建路由器实例,并在实例内编写路由规则

补充:

  • 当在项目中的路由,因为已挂载到项目中,所以在相应的组件上会出现对应的路由规则

image-20231222141259082

步骤六:实现路由切换

说明:

​ 修改App.vue组件并注册路由组件,使用

<template>
    <div>
        <h1>Vue Router Demo</h1>
        <hr/>
        <div>
            <!-- 组件中使用router-link实现路由切换 -->
            <router-link to="/about">About</router-link>
            <br/>
            <router-link to="/home">Home</router-link>
        </div>
        <hr/>
        <!-- 实现路由的组件展示 --><!--当点击了路由组件,导致了页面的路径发生了变化就会触发路由器,路由器根据相应的路由规则,将需要展示的组件放到此占位符处-->
        <router-view></router-view>
        <hr/>
    </div>
</template>

<script>
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";

export default {
    name: "App",

    methods: {},
    components: {
        Home,
        About,
    },
};
</script>

补充:

  • <router-link>标签将来会被vue解析为<a>标签在页面上进行展示

image-20231221191355108

  • <router-view>标签相当于一个占位符,便于路由组件的展示

步骤七:演示

image-20231221190941820

说明:

​ 当点击路由组建后,导致了页面的路径发生了变化就会触发路由器,路由器根据相应的路由规则,将需要展示的组件展示在页面上

补充:

image-20231222141018426

  • 路由的组件默认是被销毁的,也就是每点一次路由切换,组件就会不停的执行组件生命周期中的onMountedonDestory方法

8.3多级路由(路由嵌套)

笔记小结:

  1. 概述:多级路由是指应用中存在多层嵌套的路由结构

  2. 使用方式:

    • 步骤一:配置路由规则
    routes:[
    	{
    		path:'/about',
    		component:About,
    	},
    	{
    		path:'/home',
    		component:Home,
    		children:[ //通过children配置子级路由
    			{
    				path:'news', //此处一定不要写:/news
    				component:News
    			},
    			{
    				path:'message', //此处一定不要写:/message
    				component:Message
    			}
    		]
    	}
    ]
    
    • 步骤二:路由切换

      <!--跳转时需要在`<router-link>`标签中写完整路径-->
      <router-link to="/home/news">News</router-link
      

8.3.1概述

​ 在Vue中,多级路由是指应用中存在多层嵌套的路由结构。这种结构可以在一个页面中包含多个嵌套层级的组件,通过配置路由的嵌套关系来实现。多级路由的配置主要使用Vue Router实现。

说明:

image-20231222152705293

  • 当点击父路由组件时,会有相应的下一级子路由组件展开

8.3.2基本用例-多级路由示例

前提:

​ 项目已经安装Vue-Router插件,并且已成功引入到项目中。也就是说,已经完成8.2基本用例-Router导入示例的相应步骤

步骤一:创建路由组件

说明:

​ 在项目中的pages目录下创建组件

1.创建父路由组件

说明:

​ 创建项目中的pages/Home.vue

<template>
    <div>
        <h1>我是Home组件</h1>
        <router-link to="/home/news">News</router-link>&nbsp;&nbsp; <!--详细路由的名称需要写全-->
        <router-link to="/home/message">Message</router-link>
        <div>
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Home",
};
</script>

<style>
</style>

说明:

​ 这里写<router-link>标签的to属性之后需要将父路由的路径写上,而不是单单只写子路由的路径

2.创建子路由组件

2.1创建News组件

说明:

​ 创建项目中的pages/News.vue

<template>
    <div>
        <ol>
            <li>我是News组件</li>
            <li>我是News组件</li>
        </ol>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Message",
};
</script>

<style>
</style>

2.2创建Message组件

说明:

​ 创建项目中的pages/Message.vue

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                    {{ m.title }}
        	</li>
        </ul>
    </div>
</template>

<script>
    export default {
        // eslint-disable-next-line vue/multi-word-component-names
        name: "Message",
        data() {
            return {
                messageList: [
                    {
                        id: "001",
                        title: "消息1",
                    },
                    {
                        id: "002",
                        title: "消息2",
                    },
                ],
            };
        },
    };
</script>

<style>
</style>

步骤二:修改vue-router插件规则

说明:

​ 修改src/router/index.js文件

//该文件用于创建整个应用的路由器
import VueRoute from "vue-router";
//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";

//创建并暴露一个路由器
export default new VueRoute({//传入一个对象
    routes: [//此处为routes,注意别写为routers,否则页面路由配置没有一个可以成功,无展示效果
        {
            path: "/home",
            component: Home,
            children: 
                [{//配置二级路由规则
                        path: "news",//注意,不要写 "/" 因为Vue在解析时,会自动解析children为 "/"
                        component: News,
                    }, {
                        path: "message",
                        component: Message,
                       /* children: [{
                            path: "xxxx",
                            component: XXXVueComponet, // 子路由们可以一直套娃
                        }]*/
                }]
        }
    ]
})

注意:

​ 这个path不要以/开始,因为Vue在解析时,会自动解析children为 “/”

步骤三:演示

image-20231222152332063

说明:

​ 当点击了Home里面的Message之后,地址栏发生相应的变化,嵌套的多级路由就会相应的展开

8.4Query参数(路由拼接传参)

笔记小结:

  1. 概述:使用路由的查询参数(Query Parameters)来传递参数

  2. 使用方式

    • 步骤一:传递参数

      <!-- 方式一:跳转并携带query参数,to的字符串写法 -->
      <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
      
      <!-- 方式二:跳转并携带query参数,to的对象写法 -->
      <router-link :to="{
      	path:'/home/message/detail',
      	query:{
      		id:666,
              title:'你好'
      	}
      }">跳转</router-link>
      
    • 步骤二:接收参数

      // 直接在<template>标签中使用即可
      $route.query.id
      $route.query.title
      

8.4.1概述

​ 在Vue Router中,可以使用路由的查询参数(Query Parameters)来传递参数。查询参数是以键值对的形式附加在URL的查询字符串中的,通常用于传递非必要但影响页面行为的参数。

8.4.2基本用例-路由传参示例

前提:

​ 本案例依据8.3多级路由传参8.3.2基本用例-多级路由示例基础上新增内容

步骤一:创建路由组件

说明:

​ 在项目中的pages目录下创建组件

1.创建传递参数父组件

说明:

修改项目中的pages/Message.vue

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                <!-- 路由传递query参数,写法一:to的字符串写法 -->
                <!-- 将消息列表里的id和消息列表里的title通过传递参数的方式传入路径detail内。 -->
                <!-- 将to变为绑定,并添加模板语法,通过${m.id}实现动态查询 -->
                <!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`"> -->
                <!-- 路由传递query参数,写法二:to的对象写法 。-->
                <!-- 将传入的参数写在query内-->
                <router-link
                        :to="{
                            path: '/home/message/detail',  // 注意:当使用 query传递参数时,此处需要指定路由的path
                            query: {
                              id: m.id,
                              title: m.title,
                            },
                          }"
                >
                    {{ m.title }}
                </router-link>
            </li>
        </ul>
        <div>
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Message",
    data() {
        return {
            messageList: [
                {
                    id: "001",
                    title: "消息1",
                },
                {
                    id: "002",
                    title: "消息2",
                },
            ],
        };
    },
    mounted() {
        // console.log(this.$route);
    },
};
</script>

<style>
</style>

说明:

​ 传递参数时通常有两种方式进行参数传递,在规则比较复杂的时候可以使用绑定对象的方式进行传递,在规则比较简单的时候就可以使用绑定字符串的方式进行传递

补充:

<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
  • 当使用了绑定:的方式进行传递后,双引号内的东西会解析成模板语法

2.创建接收参数子组件

说明:

​ 创建项目中的pages/Detail.vue

<template>
  <div>
    <ul>
      <li>消息编号:{{ $route.query.id }}</li>
      <li>消息标题:{{ $route.query.title }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Detail",
  // mounted() {//各自组件的route上有可以查询相应的消息
  //   console.log(this.$route);
  // },
};
</script>

<style>
</style>

说明:

  • 因为由父组件将参数通过Query也就是路径的方式将参数数据传输到此子组件中,因此可在此子组件的$route路由中看到传递的参数对象,所以使用时,直接.query即可使用

image-20231222160427606

步骤二:修改vue-router插件规则

说明:

​ 修改src/router/index.js文件

//该文件用于创建整个应用的路由器
import VueRoute from "vue-router";
//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";

//创建并暴露一个路由器
export default new VueRoute({//传入一个对象
    routes: [//此处为routes,注意别写为routers,否则页面路由配置没有一个可以成功,无展示效果
        {
            path: "/home",
            component: Home,
            children: [
                {//配置二级路由规则
                    path: "news",//注意,不要写 "/" 因为Vue在解析时,会自动解析children为 "/"
                    component: News,
                },{
                    path: "message",
                    component: Message,
                    children: [{
                        path: "detail",
                        component: Detail,
                    }]
                }
            ]
        }
    ]
})

说明:

​ 只需要将Detail组件配置为Message组件的子组件即可,这样就可以通过Query进行传参

步骤三:演示

image-20231222162938033

说明:

​ 当点击了Home里面的Message之后,地址栏发生相应的变化,嵌套的多级路由就会相应的展开,并将父组件中的数据通过对象传递给子组件

8.5命名路由(路由Name)

笔记小结:

  1. 概述:在Vue Router中,命名路由是为路由起一个特定的名称

  2. 使用方式:

    • 步骤一:给路由命名

      // 修改src/router/index.js文件
      {
      	path:'/demo',
      	component:Demo,
      	children:[
      		{
      			path:'test',
      			component:Test,
      			children:[
      				{
                            name:'hello' //给路由命名
      					path:'welcome',
      					component:Hello,
      				}
      			]
      		}
      	]
      }
      
    • 步骤二:简化跳转

      <!-- 修改src/pages/相应.vue文件配置命名路由的使用-->
      <!--简化前,需要写完整的路径 -->
      <router-link to="/demo/test/welcome">跳转</router-link>
      
      <!--简化后,直接通过名字跳转 -->
      <router-link :to="{name:'hello'}">跳转</router-link>
      
      <!--简化写法配合传递参数 -->
      <router-link 
      	:to="{
      		name:'hello',
      		query:{
      		    id:666,
                  title:'你好'
      		}
      	}"
      >跳转</router-link>
      

8.5.1概述

​ 在Vue Router中,命名路由是为路由起一个特定的名称,以方便在代码中引用和跳转。通过给路由配置项设置name属性,可以为该路由指定一个名称。

8.5.2基本用例-命名路由示例

前提:

本案例依据8.4多级路由传参8.4.2基本用例-路由传参示例基础上新增内容

步骤一:为路由配置添加name配置项

说明:

修改项目src/router/index.js文件内容,并添加组件name配置项

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[
                {
                    path:'news',
                    component:News
                },
                {
                    path:'message',
                    component:Message,
                    children:[
                        {
                            //name配置项为路由命名
                            name:'xiangqing',
                            path:'detail',
                            component:Detail
                        }
                    ]
                }
            ]
        }
    ]
})

步骤二:模板中的路由链接

说明:

​ 修改项目中的pages/Message.vue的路由跳转使用方式

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                <!-- 跳转路由并携带query参数,to的字符串写法 -->
                <!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
                    {{m.title}}
                </router-link>&nbsp;&nbsp; -->

                <!-- 跳转路由并携带query参数,to的对象写法 -->
                <router-link :to="{
                    // 使用name进行跳转
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                }">
                    {{m.title}}
                </router-link>&nbsp;&nbsp;
            </li>
        </ul>
        <hr/>
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name:'News',
        data(){
            return{
                messageList:[
                    {id:'001',title:'消息001'},
                    {id:'002',title:'消息002'},
                    {id:'003',title:'消息003'}
                ]
            }
        }
    }
</script>

8.6Params参数(路由路径传参)

笔记小结:

  1. 在Vue Router中,路由参数(params)是一种路由路径中传递数据的方式。类似于软件开发中的ResultFul风格

  2. 使用方式:

    • 步骤一: 配置路由path,声明接收params参数

      {
      	path:'/home',
      	component:Home,
      	children:[
      		{
      			path:'news',
      			component:News
      		},
      		{
      			component:Message,
      			children:[
      				{
      					name:'xiangqing',
      					path:'detail/:id/:title', //使用占位符声明接收params参数
      					component:Detail
      				}
      			]
      		}
      	]
      }
      
    • 步骤二:传递参数

      <!-- 跳转并携带params参数,to的字符串写法 -->
      <router-link :to="/home/message/detail/666/你好">跳转</router-link>
      
      <!-- 跳转并携带params参数,to的对象写法 -->
      <router-link 
      	:to="{
      		name:'xiangqing',
      		params:{
      		   id:666,
                  title:'你好'
      		}
      	}"
      >跳转</router-link>
      
    • 步骤三:接收参数

      $route.params.id
      $route.params.title
      

8.6.1概述

​ 在Vue Router中,路由参数(params)是一种在路由路径中传递数据的方式。当定义路由规则时,可以通过:符号来指定某个路径片段为参数,并在路由组件中通过$route.params来访问这些参数。

image-20231224101447847

说明:

​ 以前发送ajax请求的时候,有两种方式可以将数据传递给后端。第一种就是通过query在请求路径里发送,第二种就是通过param在请求体中携带并发送

  • params传递参数和query传递参数区别
  1. 传递方式:
    • params参数是直接嵌入在URL路径中的,可以通过$route.params访问。
    • query参数是通过URL查询字符串追加的,可以通过$route.query访问。
  2. URL形式:
    • params参数在URL中会显得比较整洁,直接体现在路径中。
    • query参数以?key=value形式追加在URL后,形式上略显繁琐。
  3. 用途:
    • params通常用于标识资源,如用户ID、文章ID等。
    • query通常用于过滤、排序或其他不涉及资源标识的场景

补充:

​ param参数进行参数传递类是于Web开发中的RestFul风格

8.6.2基本用例-路由传参示例

前提:

​ 本案例依据8.5命名路由(路由name)8.5.2基本用例-命名路由示例基础上修改内容

步骤一:配置路由path接收params参数

说明:

​ 修改src/router/index.js文件

import VueRoute from "vue-router";

import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";


export default new VueRoute({
    routes: [
        {
            name: "i",
            path: "/about",
            component: About
        },
        {
            name: "love",
            path: "/home",
            component: Home,
            children: [{
                path: "news",
                component: News,
            },
                {
                    name: "you",
                    path: "message",
                    component: Message,
                    children: [{
                        name: "yueyue",
                        path: "detail/:id/:title",//使用占位符声明接收params参数
                        component: Detail,
                    }]
                }]
        }
    ]
})

说明:

​ 需要声明接收params参数,才便于vue-router进行路径解析时将最后两个斜杠中的内容解析为params参数,而不是路由路径

步骤二:修改传递参数父组件

说明:

修改项目中的pages/Message.vue

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                <!-- 路由传递params参数,to的字符串写法 -->
                <!-- 将消息列表里的id和消息列表里的title通过传递参数的方式传入detail内。 -->
                <!-- 将to变为绑定,并添加模板语法,通过${m.id}实现动态查询 -->
                <router-link :to="`/home/message/detail/${m.id}/${m.title}`">
                    <!-- 路由传递params参数,to的对象写法 。将传入的参数写在params内-->
                    <!-- <router-link
                    :to="{
                      // path: '/home/message/detail',
                      name: 'yueyue', // 注意:当使用 params 传递参数时,此处需要指定路由的name,而不是query参数传递时所指定的path
                      params: {
                        id: m.id,
                        title: m.title,
                      },
                    }"
                  > -->
                    {{ m.title }}
                </router-link>
            </li>
        </ul>
        <hr/>
        <div>
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Message",
    data() {
        return {
            messageList: [
                {
                    id: "001",
                    title: "消息1",
                },
                {
                    id: "002",
                    title: "消息2",
                },
            ],
        };
    },
    mounted() {
        console.log(this.$route);
    },
};
</script>

<style>
</style>

说明:

​ 传递参数时通常有两种方式进行参数传递,在规则比较复杂的时候可以使用绑定对象的方式进行传递,在规则比较简单的时候就可以使用绑定字符串的方式进行传递

补充:

<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
  • 当使用了绑定:的方式进行传递后,双引号内的东西会解析成模板语法

补充:

image-20231224102200796

  • 当使用params进行参数传递时,参数存放在route的params

步骤三:接收参数

说明:

​ 修改项目中的pages/Detail.vue

<template>
  <div>
    <ul>
      <!-- <li>消息编号:{{ $route.query.id }}</li>
      <li>消息标题:{{ $route.query.title }}</li> -->
      <!-- 改为params接收 -->
      <li>消息编号:{{ $route.params.id }}</li>
      <li>消息标题:{{ $route.params.title }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: "Detail",
  // mounted() {//各自组件的route上有可以查询相应的消息
  //   console.log(this.$route);
  // },
};
</script>

<style>
</style>

说明:

因为此时是通过Params进行参数传递,所以需要在routeparams中进行接收,而并不是query中进行接收

8.7Props路由传递(简化Query和Params参数的使用方式)

笔记小结:

  1. 概述:在Vue Router中,props选项用于将路由参数传递给组件。换句话说,让路由组件更方便的收到参数

  2. 使用方式:

    • 步骤一:配置路由props传递

      {
      	name:'xiangqing',
      	path:'detail/:id',
      	component:Detail,
      
      	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
      	// props:{a:900}
      
      	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
      	// props:true
      
      	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
      	props(route){
      		return {
      			id:route.query.id,
      			title:route.query.title
      		}
      	}
      }
      
    • 步骤二:传递参数

      // 详细传方式参考Query参数和Params参数,这里只做示例
      <router-link
                   :to="{
                            name: 'yueyue',
                            params: {
                            id: m.id,
                            title: m.title,
                            },
                        }"
                   >
          {{ m.title }}
      </router-link>
      
    • 步骤三:接收参数

      <!-- 使用路由props配置简化query和params接收 -->
      <li>消息编号:{{ id }}</li>
      <li>消息标题:{{ title }}</li>
      
      props: ["id", "title"],
      

8.7.1概述

​ 在Vue Router中,props选项用于将路由参数传递给组件。通过props配置,你可以指定如何将路由参数映射到组件的props中,从而在组件中访问这些参数。

8.7.2基本用例-Props传参示例

前提:

​ 本案例依据8.7Props路由传递(简化Query和Params参数的使用方式)8.6.2基本用例-路由传参示例基础上修改内容

步骤一:配置路由props传递

说明:

​ 修改src/router/index.js文件

import VueRoute from "vue-router";

import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";


export default new VueRoute({
    routes: [
        {
            name: "i",
            path: "/about",
            component: About
        },
        {
            name: "love",
            path: "/home",
            component: Home,
            children: [{
                path: "news",
                component: News,
            },
                {
                    name: "you",
                    path: "message",
                    component: Message,
                    children: [{
                        name: "yueyue",
                        path: "detail/:id/:title",//使用占位符声明接收params参数
                        component: Detail,
                        // props的第一种写法,值为对象,该对象中的所有key-Value都会以props形式传给Detail组件
                        // props:{a:"玥玥",b:"杰哥"} //缺点,程序写死,所以不常用,了解即可

                        // props的第二种写法,值为布尔值,若布尔值为真,则会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
                        // 也就说,此时的path路径为“detail/:id/:title”,那么可以直接在组件中通过props接收,并直接使用
                        // props:true

                        // props的第三种写法,值为函数,该对象中的所有key-Value都会以params形式传给Detail组件
                        props($route) {
                            // console.log($route);
                            return {
                                id: $route.params.id,
                                title: $route.params.title
                            }
                        }
                    }]
                }]
        }
    ]
})

注意:props传参数的第二种写法

props:true
  • 值为布尔值,若布尔值为真,则会把该路由组件收到的所有params参数,也就说如果传递的不是params参数而是query参数,则组件将接收不了,控制台也不会报错

补充:props的第三种写法

props($route) {
 // console.log($route);
 return {
     id: $route.query.id, // 此处返回的是$route中的query参数
     title: $route.query.title
 }
}
  • 当使用Props参数进行参数传递时,返回内部为对象,并且参数可以灵活调整

步骤二:传递参数

说明:

修改项目中的pages/Message.vue

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                <!-- 路由传递params参数,to的字符串写法 -->
                <!-- 将消息列表里的id和消息列表里的title通过传递参数的方式传入detail内。 -->
                <!-- 将to变为绑定,并添加模板语法,通过${m.id}实现动态查询 -->
                <!--<router-link :to="`/home/message/detail/${m.id}/${m.title}`">-->
                <!-- 路由传递params参数,to的对象写法 。将传入的参数写在query内-->
                <router-link
                        :to="{
                            name: 'yueyue',
                            params: {
                              id: m.id,
                              title: m.title,
                          },
                        }"
                >
                    {{ m.title }}
                </router-link>
            </li>
        </ul>
        <hr/>
        <div>
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Message",
    data() {
        return {
            messageList: [
                {
                    id: "001",
                    title: "消息1",
                },
                {
                    id: "002",
                    title: "消息2",
                },
            ],
        };
    },
    // mounted() {
    //     console.log(this.$route);
    // },
};
</script>

<style>
</style>

步骤三:接收参数

说明:

​ 修改项目中的pages/Detail.vue

<template>
    <div>
        <ul>
            <!-- query接收 -->
            <!--
              <li>消息编号:{{ $route.query.id }}</li>
              <li>消息标题:{{ $route.query.title }}</li>
             -->
            <!-- params接收 -->
            <!--
              <li>消息编号:{{ $route.params.id }}</li>
              <li>消息标题:{{ $route.params.title }}</li>
             -->
            <!-- 使用路由props配置简化query和params接收 -->
            <li>消息编号:{{ id }}</li>
            <li>消息标题:{{ title }}</li>
        </ul>
    </div>
</template>

<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
    name: "Detail",
    props: ["id", "title"],
};
</script>

<style>
</style>

说明:

​ 使用路由props配置简化query和params接收。直接在VC实例中配置props配置即可

8.8路由跳转Replace(控制浏览器历史记录)

笔记小结:

  1. 概述:replace 是路由导航的其中一种模式,它用于控制路由跳转时操作浏览器历史记录的模式

  2. 浏览器的历史记录有两种写入方式:push和replace,其中push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push方式

  3. 使用方式:

    • 步骤一:开启replace模式

      <router-link replace ...>News</router-link>
      

8.8.1概述

​ 在Vue Router中,pushreplace 是路由导航的两种模式,它们用于控制浏览器的历史记录以及切换路由时的行为。

image-20231224134858707

说明:

​ 这个放框看作一个数据结构中的栈。push模式是一直往栈里面放数据,replace模式就是进去一个数据,就将下一条数据做替换

8.8.2基本用例-开启Replace属性

前提:

​ 本案例依据8.6Params参数(路由路径传参)8.7.2基本用例-Props传参示例基础上修改内容

步骤一:开启声明式路由导航的Replace属性

说明:

​ 修改src/pages/home.vue

<template>
    <div>
        <h2>Home组件内容</h2>
        <div>
            <router-link replace class="list-group-item" active-class="active" to="/home/news">News
            </router-link> <!--使用<router-link>标签进行路由跳转的方式叫声明式路由导航-->
            &nbsp;&nbsp;&nbsp;
            <router-link replace class="list-group-item" active-class="active" to="/home/message">Message
            </router-link>
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: 'Home'
}
</script>

说明:

​ 当实现路由切换的时候,只需要为<router-link>标签添加replace属性即可

步骤二:演示

image-20231224141843539

说明:

​ 当点击浏览器的回退按钮后,路径不再是一级一级的往回走,而是直接跳转到#路径处。因为#/home级别的路由被#/home/message给替换了

8.9编程式路由导航(路由跳转方式)

笔记小结:

  1. 概述:编程式路由导航是通过在代码中显式调用路由的方式进行页面导航。换句话说,不借助<router-link>实现路由跳转,让路由跳转更加灵活

  2. 使用方式:

    • 步骤一:定义编程式路由导航

      this.$router.push({
      	name:'xiangqing',
          params:{
              id:xxx,
              title:xxx
          }
      })
      
      this.$router.replace({
      	name:'xiangqing',
          params:{
              id:xxx,
              title:xxx
          }
      })
      
    • 步骤二:使用编程式路由导航

      this.$router.forward() //前进
      this.$router.back() //后退
      this.$router.go() //可前进也可后退
      

8.9.1概述

​ 编程式路由导航是通过在代码中显式调用路由的方式进行页面导航,而不是通过用户的交互行为(比如点击链接或浏览器的前进后退按钮)触发路由。

说明:

​ 简单的说,就是不借助<router-link>标签来实现路由导航,而是通过其余的方式来实现路由的切换。例如通过编程的方式来完成路由组件的切换

补充:

使用<router-link>标签来完成路由导航的,叫声明式导航,只适合超链接

8.9.2基本用例-编程式路由导航示例

前提:

本案例依据8.8路由跳转Replace(控制浏览器历史记录)8.8.2基本用例-开启Replace属性基础上修改内容

步骤一:定义编程式路由导航

说明:

​ 修改项目中的pages/Message.vue,在方法中实现路由导航功能

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
                <router-link :to="{
                    name:'xiangqing',
                    params:{
                        id:m.id,
                        title:m.title
                    }
                }">
                    {{ m.title }}
                </router-link>
                <button @click="showPush(m)">push查看</button>
                <button @click="showReplace(m)">replace查看</button>
            </li>
        </ul>
        <hr/>
        <router-view></router-view>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: 'News',
    data() {
        return {
            messageList: [
                {id: '001', title: '消息001'},
                {id: '002', title: '消息002'},
                {id: '003', title: '消息003'}
            ]
        }
    },
    methods: {
        showPush(m) {
            this.$router.push({ // 注意:这里获取的是项目的路由器对象,而不是路由对象
                name: 'xiangqing',
                params: {
                    id: m.id,
                    title: m.title
                }
                /* 注意:使用编程式的路由导航时,push以及replace方法会返回一个Promise对象。Promise对象期望你能通过参数的方式给它两个回调函数,一个是成功的回调,一个是失败的回调。如果你没有给这两个回调函数,则会出现错误。怎么解决:在参数位置上给两个回调函数。*/
            }, () => {
            }, () => {
            })
        },
        showReplace(m) {
            this.$router.replace({
                name: 'xiangqing',
                params: {
                    id: m.id,
                    title: m.title
                }
            }, () => {
            }, () => {
            })
        }
    }
}
</script>

补充:

this.$route //获取的是路由对象。
this.$router  //获取到整个项目的路由器对象。(路由器对象一般一个项目只需要一个。)

步骤二:模拟跳转

说明:

修改项目中的pages/Banner.vue,在方法中通过项目的路由器对象实现页面路由的切换

<template>
    <div class="col-xs-offset-2 col-xs-8">
        <div class="page-header">
            <h2>Vue Router Demo</h2>
            <button @click="back">后退</button>
            <button @click="forward">前进</button>
            <button @click="test">测试一下go</button>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: 'Banner',
    methods: {
        back() {
            this.$router.back()
        },
        forward() {
            this.$router.forward()
        },
        test() {
            this.$router.go(3)
        }
    },
}
</script>

步骤三:配置路由规则

说明:

​ 修改src/router/index.js文件

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
    routes: [
        {
            path: '/about',
            component: About
        },
        {
            path: '/home',
            component: Home,
            children: [
                {
                    path: 'news',
                    component: News
                },
                {
                    path: 'message',
                    component: Message,
                    children: [
                        {
                            name: 'xiangqing',
                            path: 'detail/:id/:title',
                            component: Detail,
                            props($route) {
                                return {
                                    id: $route.params.id,
                                    title: $route.params.title,
                                }
                            }
                        }
                    ]
                }
            ]
        }
    ]
})

步骤四:演示

image-20231226164923213

说明:

​ 当使用按钮后退、前进、前进三步时页面成功跳转。此时我们已经可以不通过<router-link>标签来实现页面路由的跳转,现在页面路由的跳转方式可以通过自定义的方式进行了。从而,页面路由的跳转变得更加的灵活多样

8.10路由缓存(缓存路由组件)

笔记小结:

  1. 概述:在Vue中,可以通过keep-alive组件来缓存路由组件。换句话说,让不展示的路由组件保持挂载,不被销毁‘

  2. 使用方式:

    • 步骤一:创建子组件

      ……
      <script>
      export default {
          name: 'News' // 此处的组件名称需要同缓存的路由组件名称相同
      }
      </script>
      
    • 步骤二:父组件缓存路由组件

      //缓存一个路由组件
      <keep-alive include="News"> //include中写想要缓存的组件名,不写表示全部缓存
          <router-view></router-view>
      </keep-alive>
      
      //缓存多个路由组件
      <keep-alive :include="['News','Message']"> 
          <router-view></router-view>
      </keep-alive>
      
  3. 路由组件生命周期

    1. 概述:activateddeactivated是路由组件所独有的两个钩子,用于捕获路由缓存组件激活状态。也就是说,路由的组件需要再被缓存的前提下才会有这两个路由组件的生命周期

    2. 使用方式:

      • 步骤一:添加缓存组件

        <keep-alive include="News">
            <router-view></router-view>
        </keep-alive>
        
      • 步骤二:添加生命周期函数

        ……
        activated() { // 路由缓存组件被激活时调用
        },
        deactivated() { //路由缓存组件失去激活或销毁时调用
        }
        

8.10.1概述

​ 在Vue中,可以通过keep-alive组件来缓存路由组件,以提高性能和优化用户体验。keep-alive是Vue内置的一个抽象组件,用于缓存动态组件或者路由的组件。

image-20231226181756504

说明:

​ 当组件的路由来回切换时,组件会不停的销毁并重新创建

8.10.2基本用例-路由缓存示例

步骤一:创建需要被缓存的子组件

说明:

​ 修改项目的src/pages/news.vue组件

<template>
    <ul>
        <li>news001 <input type="text"></li>
        <li>news002 <input type="text"></li>
        <li>news003 <input type="text"></li>
    </ul>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: 'News'
}
</script>

步骤二:在被缓存的父组件上实现保持缓存

说明:

​ 修改项目中的pages/Message.vue,在方法中实现保持缓存功能

<template>
    <div>
        <h1>我是Home组件</h1>
        <router-link to="/home/news">News</router-link>&nbsp;&nbsp;&nbsp;
        <router-link to="/home/message">Message</router-link>
        <div>
            <keep-alive include="News"> <!--此处避免所有子组件全部缓存,这里通过include属性指定需要缓存的子组件即可-->
                <router-view></router-view>
            </keep-alive>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Home",
};
</script>

<style>
</style>

注意:

​ 缓存的是组件名

步骤三:演示

image-20231226182448132

说明:

​ 当完成路由切换时,News组件上的输入框的值依旧还在。Message组件被销毁,但News组件不会被销毁

8.10.3路由组件生命周期(activated 和 deactivated)

8.10.3.1概述

​ 在Vue中,路由组件在进入和离开路由时有两个特殊的生命周期钩子:activateddeactivatedactivated 钩子在组件被缓存时调用。它对于处理一些进入路由时的逻辑非常有用,因为在组件被缓存后,再次进入路由时会触发该钩子。deactivated 钩子在组件被缓存时调用。它对于处理一些离开路由时的逻辑非常有用,因为在组件被缓存后,再离开路由时会触发该钩子。

image-20231226185012704

说明:

​ 其中有三个个生命周期钩子并没有在图中体现。路由组件中常用的两个是activateddeactivated

补充:

​ 三个未在路由组件官网中出现的路由组件生命钩子,$nextTickactivateddeactivated

8.10.3.2基本用例-路由组件生命周期示例

步骤一:添加缓存组件

说明:

​ 修改项目中的pages/Home.vue,在方法中实现保持缓存功能

<template>
    <div>
        <h1>我是Home组件</h1>
        <router-link to="/home/news">News</router-link>&nbsp;&nbsp;&nbsp;
        <router-link to="/home/message">Message</router-link>
        <div>
            <keep-alive include="News">
                <router-view></router-view>
            </keep-alive>
        </div>
    </div>
</template>

<script>
export default {
    // eslint-disable-next-line vue/multi-word-component-names
    name: "Home",
};
</script>

<style>
</style>

步骤二:添加生命周期函数

说明:

​ 修改项目的src/pages/news.vue组件

<template>
    <ul>
        <li :style="{opacity}">欢迎学习vue</li>
        <li>news001 <input type="text"></li>
        <li>news002 <input type="text"></li>
        <li>news003 <input type="text"></li>
    </ul>
</template>

<script>
export default {
    name: 'News',
    data() {
        return {
            opacity: 1
        }
    },
    activated() {
        console.log('News组件被激活了')
        this.timer = setInterval(() => {
            this.opacity -= 0.01
            if (this.opacity <= 0) this.opacity = 1
        }, 16)
    },
    deactivated() {
        console.log('News组件失活了')
        clearInterval(this.timer)
    }
}
</script>

步骤二:演示

image-20231226185139209

说明:

​ 当切换路由时,路由组件成功执行,并执行定时器实现了页面上元素的渐变效果。当切出News组件后,News组件取消激活

8.11路由守卫(路由切换时添加业务逻辑)✳

笔记小结:

  1. 概述:路由守卫,可以对路由进行权限控制

  2. 分类:全局守卫、独享守卫、组件内守卫

  3. 全局守卫:

    //全局前置守卫:初始化时执行、每次路由切换前执行
    router.beforeEach((to,from,next)=>{
    	console.log('beforeEach',to,from)
    	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
    		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
    			next() //放行
    		}else{
    			alert('暂无权限查看')
    		}
    	}else{
    		next() //放行
    	}
    })
    
    //全局后置守卫:初始化时执行、每次路由切换后执行
    router.afterEach((to,from) => {
    	console.log('afterEach',to,from)
    	if(to.meta.title){ 
    		document.title = to.meta.title //修改网页的title
    	}else{
    		document.title = 'vue_test'
    	}
    })
    
  4. 独享守卫:

    beforeEnter(to,from,next){
    	console.log('beforeEnter',to,from)
        if(localStorage.getItem('school') === 'atguigu'){
            next()
        }else{
            alert('暂无权限查看')
        }
    }
    
  5. 组件内守卫:

    //进入守卫:通过路由规则,进入该组件时被调用
    beforeRouteEnter (to, from, next) {...},
    //离开守卫:通过路由规则,离开该组件时被调用
    beforeRouteLeave (to, from, next) {...},
    

8.11.1概述

​ 在Vue Router中,路由守卫是一种机制,允许你在路由导航过程中添加一些业务逻辑或限制条件。Vue Router 提供了全局守卫、路由独享的守卫、组件内的守卫等多种守卫方式。

说明:

​ 路由守卫就是保证路由安全的一种机制

image-20231226191407494

说明:

​ 在切换到这个路由组件之前写一段代码。执行一段代码,在开发中,通常用来进行权限校验之类的操作。这种路由切换的操作类似与Java开发当中的拦截器和过滤器,会在进入controller之前进行一段逻辑的请求

8.11.2基本用例-全局守卫示例

步骤一:路由配置全局守卫

说明:

​ 修改src/router/index.js文件

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'

// 创建一个路由器
const router = new VueRouter({
    routes:[
        {
            name:'guanyv',
            path:'/about',
            component:About,
            meta:{title:'关于'} 
        },
        {
            name:'zhuye',
            path:'/home',
            component:Home,
            meta:{title:'主页'},
            children:[
                {
                    name:'xinwen',
                    path:'news',
                    component:News,
                    meta:{isAuth:true,title:'新闻'} // meta 是一种用于存储额外信息的对象,这里用来存一点常用的数据例如isAuth,便于程序判断此路由是否需要进行权限校验
                },
                {
                    name:'xiaoxi',
                    path:'message',
                    component:Message,
                    meta:{isAuth:true,title:'消息'},
                    children:[
                        {
                            name:'xiangqing',
                            path:'detail',
                            component:Detail,
                            meta:{isAuth:true,title:'详情'},
							props($route){
								return {
									id:$route.query.id,
									title:$route.query.title,
								}
							}
                        }
                    ]
                }
            ]
        }
    ]
})

//全局前置路由守卫————初始化的时候、每次路由切换之前被调用
router.beforeEach((to,from,next) => {
    console.log('前置路由守卫',to,from) // from,从哪个路由来,to去哪个路由
    if(to.meta.isAuth){
        if(localStorage.getItem('school')==='atguigu'){
            next() // 放行
        }else{
            alert('学校名不对,无权限查看!')
        }
    }else{
        next()
    }
})

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || '硅谷系统' //常用于动态切换单页面的标签信息
})

//导出路由器
export default router

说明:meta属性解释

​ 在 Vue Router 中,meta 是一种用于存储额外信息的对象。每个路由配置对象中都可以包含 meta 属性,用于定义一些元信息,这些信息可能不直接影响路由的匹配和组件的显示,但在某些场景下非常有用。

步骤二:演示

image-20231226194106145

说明:

​ 当从页面点击News组件时,可以看到路由被拦截

8.11.3独享路由守卫

​ 在 Vue Router 中,独享路由守卫是指在某个路由配置项中单独定义的路由守卫。这些守卫会在进入或离开该路由时被调用。

  • 代码示例

步骤一:路由配置独享守卫

说明:

​ 修改src/router/index.js文件

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建一个路由器
const router = new VueRouter({
    routes:[
        {
            name:'guanyv',
            path:'/about',
            component:About,
            meta:{title:'关于'}
        },
        {
            name:'zhuye',
            path:'/home',
            component:Home,
            meta:{title:'主页'},
            children:[
                {
                    name:'xinwen',
                    path:'news',
                    component:News,
                    meta:{title:'新闻'},
                    //独享守卫,特定路由切换之后被调用。
                    beforeEnter(to,from,next){ // 注意独享路由守卫跟全局路由守卫不同,独享路由守卫只有前置,没有后置
                        console.log('独享路由守卫',to,from)
                        if(localStorage.getItem('school') === 'atguigu'){
                            next()
                        }else{
                            alert('暂无权限查看')
                        }
                    }
                },
                {
                    name:'xiaoxi',
                    path:'message',
                    component:Message,
                    meta:{title:'消息'},
                    children:[
                        {
                            name:'xiangqing',
                            path:'detail',
                            component:Detail,
                            meta:{title:'详情'},
							props($route){
								return {
									id:$route.query.id,
									title:$route.query.title,
								}
							}
                        }
                    ]
                }
            ]
        }
    ]
})

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || '硅谷系统'
})

//导出路由器
export default router

步骤二:演示

image-20231226194919602

说明:

​ 当点击新闻组件时,独享路由成功执行,无法查看页面。Message组件跳转不影响

8.11.4组件内路由守卫

​ 在 Vue Router 中,组件内路由守卫是指在组件内部通过定义一些特定的生命周期钩子函数来执行与路由相关的逻辑。这些守卫可以在组件实例中进行定义,以响应组件内路由的变化。

  • 代码示例

步骤一:组件配置路由守卫

说明:

​ 修改src/pages/About.vue文件

<template>
    <h2>我是About组件的内容</h2>
</template>

<script>
    export default {
        name:'About',
        //通过路由规则,离开该组件时被调用
        beforeRouteEnter (to, from, next) {
            console.log('About--beforeRouteEnter',to,from)
            if(localStorage.getItem('school')==='atguigu'){
                next()
            }else{
                alert('学校名不对,无权限查看!')
            }
        },
        //通过路由规则,离开该组件时被调用
        beforeRouteLeave (to, from, next) { //注意,此处是当路由离开时调用,并不是像全局路由守卫一样是在路由切换时前置路由守卫和后置路由守卫都调用
            console.log('About--beforeRouteLeave',to,from)
            next()
        }
    }
</script>

步骤二:演示

image-20231226201049807

说明:

​ 当点击News组件后,独享路由守卫成功执行

8.12路由工作模式(路由向后端传递方式)

笔记小结:

  1. 概述:

    • 含义:在Vue中,路由的工作模式主要有两种:Hash 模式和 History 模式。简单的说,Hash模式向后端发生请求时#后面的值不会向后端进行传递
    • 补充:对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值
  2. 总结:hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器

  3. hash模式:

    • 地址中永远带着#号,不美观
    • 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
    • 兼容性较好
  4. history模式:

    • 地址干净,美观
    • 兼容性和hash模式相比略差
    • 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
  5. 配置方式

      mode: "history",
    

8.12.1概述

​ 在Vue中,路由的工作模式主要有两种:Hash 模式和 History 模式。Vue Router 提供了配置选项来选择使用哪种模式。

image-20231227150631692

说明:

  URL 中的 `#` 号及其后面的内容被称为 hash 值。那么前端向后端发送请求时`#`后面的内容不会向后端进行传递

8.12.2基本用例-路由history模式切换

说明:

​ 修改src/router/index.js文件

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建一个路由器
export default new VueRouter({
    mode: "history",  // 此处配置model模式即可
    routes: [
        {
            name: 'guanyv',
            path: '/about',
            component: About,
            meta: {title: '关于'}
        },
        {
            name: 'zhuye',
            path: '/home',
            component: Home,
            meta: {title: '主页'},
            children: [
                {
                    name: 'xinwen',
                    path: 'news',
                    component: News,
                    meta: {title: '新闻'},
                },
                {
                    name: 'xiaoxi',
                    path: 'message',
                    component: Message,
                    meta: {title: '消息'},
                    children: [
                        {
                            name: 'xiangqing',
                            path: 'detail',
                            component: Detail,
                            meta: {title: '详情'},
                            props($route) {
                                return {
                                    id: $route.query.id,
                                    title: $route.query.title,
                                }
                            }
                        }
                    ]
                }
            ]
        }
    ]
})

补充:

image-20231227145911086

  • 前端搭建服务器的方法

相关推荐

  1. 前端学习笔记 2Vue

    2024-04-23 20:36:06       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-23 20:36:06       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-23 20:36:06       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-23 20:36:06       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-23 20:36:06       18 阅读

热门阅读

  1. 前端宝藏图:寻找技术之旅的星辰大海

    2024-04-23 20:36:06       12 阅读
  2. Python爬取网易云平台

    2024-04-23 20:36:06       13 阅读
  3. 【Linux开发 第十一篇】rpm和yum

    2024-04-23 20:36:06       10 阅读
  4. 傅立叶变换与拉普拉斯变换的区别与联系?

    2024-04-23 20:36:06       12 阅读
  5. Rust :快速了解 VecDeque 双向队列

    2024-04-23 20:36:06       12 阅读
  6. Codeforces Round 816 (Div. 2)(D拆位图论构造 E斜率优化)

    2024-04-23 20:36:06       10 阅读
  7. freebase一站式搭建流程

    2024-04-23 20:36:06       14 阅读
  8. 重生之我来写低代码后端01-如何高效组织代码

    2024-04-23 20:36:06       9 阅读