路由简单使用

安装

固定5个固定的步骤(不用死背,熟能生巧)

下载 VueRouter 模块到当前工程

yarn add vue-router@3.6.5

在main.js中

import VueRouter from 'vue-router'//引入VueRouter

Vue.use(VueRouter)//安装注册

const router = new VueRouter()//创建路由对象

new Vue({
  render: h => h(App),
  router:router//将路由对象注入到new Vue实例中
}).$mount('#app')

当我们配置完以上5步之后 就可以看到浏览器地址栏中的路由 变成了 /#/的形式。表示项目的路由已经被Vue-Router管理了

配置

创建好需要的组件 (views目录),配置路由规则

const router = new VueRouter({
  // routes 路由规则们
  // route  一条路由规则 { path: 路径, component: 组件 }
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend },
  ]
})

export default router

每条路由规则是一个对象,包含:

  • path:URL 路径(如 /find
  • component:路径匹配时渲染的组件(需提前导入组件如 Find

export default router将配置好的路由实例导出,供 Vue 主文件(如 main.js)注入到根实例中

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

new Vue({
  render: h => h(App),
  router
}).$mount('#app')

声明式导航

router-link标签

vue-router 提供了一个全局组件 router-link (取代 a 标签)

  • 能跳转,配置 to 属性指定路径(必须) 。本质还是 a 标签 ,to 无需 #
  • 能高亮,默认就会提供高亮类名,可以直接设置高亮样式

语法: <router-link to="path的值">发现音乐</router-link>

<div>
  <div class="footer_wrap">
    <router-link to="/find">发现音乐</router-link>
    <router-link to="/my">我的音乐</router-link>
    <router-link to="/friend">朋友</router-link>
  </div>
  <div class="top">
    <!-- 路由出口 → 匹配的组件所展示的位置 -->
    <router-view></router-view>
  </div>
</div>

router-link类名

使用router-link跳转后,我们发现。当前点击的链接默认加了两个class的值 router-link-exact-activerouter-link-active

在 Vue Router 中,router-link-activerouter-link-exact-active 是两个非常重要的 CSS 类名,它们由 Vue Router 自动添加到 <router-link> 组件上,用于指示当前导航链接的激活状态:

router-link-active

  • 触发条件:当路由路径部分匹配时添加
  • 匹配规则:只要当前路由的路径包含<router-link> 的目标路径,就会添加
  • 示例html <router-link to="/user">用户</router-link>
  • 当访问 /user → 激活 - 当访问 /user/profile → 激活(因为包含 /user
  • 当访问 /product → 不激活

router-link-exact-active

  • 触发条件:当路由路径完全匹配时添加
  • 匹配规则:只有当当前路由的路径完全等于<router-link> 的目标路径时才会添加
  • 示例html <router-link to="/user">用户</router-link>
  • 当访问 /user → 激活 - 当访问 /user/profile不激活(路径不完全相等)
  • 当访问 /users → 不激活(即使相似但不相等)

自定义类名

router-link的两个高亮类名太长了,我们可以在创建路由对象时,额外配置两个配置项

const router = new VueRouter({
  linkActiveClass: 'active', // 配置模糊匹配的类名
  linkExactActiveClass: 'exact-active' // 配置精确匹配的类名
})

查询参数传参

  • 通过 URL 的 ? 后拼接参数(如 /user?id=123
  • 参数可见,适合非敏感数据(如分页、筛选条件)
  • 不需要提前在路由配置中定义参数名

传参

<!-- 方式1:字符串拼接 -->
<router-link to="/user?id=123&name=Alice"></router-link>

<!-- 方式2:对象形式(推荐) -->
<router-link :to="{
  path: '/user',
  query: { id: 123, name: 'Alice' }
}">
</router-link>

接收

export default {
  mounted() {
    // 通过 $route.query 获取
    console.log(this.$route.query.id)    // 输出 123
    console.log(this.$route.query.name) // 输出 'Alice'
  }
}

动态路由传参

这种方式需要配置路由,必须使用 : 定义参数名

const router = new VueRouter({
  routes: [
    ...,
    { 
      path: '/search/:words', //定义参数名
      component: Search ,
      name: xxx//定义别名,可选
    }
  ]
})

传参


<!-- 方式1:路径拼接 -->
<router-link to="/user/123">用户123</router-link>

<!-- 方式2:对象形式(推荐) -->
<router-link :to="{
  name: 'user', 
  params: { id: 123 }
}">
</router-link>

其中,第二种写法需路由配置 name 属性

接收参数

export default {
  props: ['id'], // 需路由配置 props: true
  mounted() {
    // 方式1:通过 props(推荐)
    console.log(this.id) // 输出 123

    // 方式2:通过 $route.params
    console.log(this.$route.params.id) // 输出 123
  }
}

两种传参方式对比

对比项查询参数(Query)动态路由参数(Params)
URL 形式/path?key=value/path/:id(如 /user/123
路由配置无需特殊配置需定义 :param 占位符
参数可见性明文显示在 URL部分隐藏(仅路径中显示值)
传参方式query: { key: value }params: { key: value }
组件获取方式this.$route.querythis.$route.paramsprops
适用场景筛选、分页等可选参数必选参数(如用户ID、文章ID)
  • 用查询参数(Query)当:

    • 参数是可选的(如 ?page=1
    • 需要保留参数在 URL 中可见(如分享链接)
  • 用动态路由(Params)当:

    • 参数是必选的(如用户详情页 /user/123
    • 需要更简洁的 URL(符合 RESTful 风格)

重定向

网页打开时, url 默认是 / 路径,未匹配到组件时,会出现空白

const router = new VueRouter({
  routes: [
    { path: '/', redirect: '/home'},
      ...
  ]
})

404

404的路由,虽然配置在任何一个位置都可以,但一般配置在其他路由规则的后面

即前面不匹配就命中最后

const router = new VueRouter({
  routes: [
     ...
    { path: '*', component: NotFound }
  ]
})

编程式导航

跳转

编程式导航即用JS代码来进行跳转

//简单写法
this.$router.push('路由路径')

//完整写法
this.$router.push({
  path: '路由路径'
})

也可以通过name来进行跳转,配置name配置项

{ name: '路由名', path: '/path/xxx', component: XXX },
this.$router.push({
  name: '路由名'
})

查询参数传参

传参

// 方式1:path + query
this.$router.push({
  path: '/search',
  query: { keyword: 'vue', page: 1 } // 参数对象
})

// 方式2:命名路由 + query
this.$router.push({
  name: 'search',
  query: { keyword: 'vue' }
})

// 方式3:URL 字符串(不推荐)
this.$router.push('/search?keyword=vue&page=1')

接收

export default {
  mounted() {
    // 通过 $route.query 获取
    console.log(this.$route.query.keyword) // 'vue'
    console.log(this.$route.query.page)   // '1'
  }
}

动态路由传参

传参

// 方式1:命名路由 + params
this.$router.push({
  name: 'user',         // 必须用 name!
  params: { id: 123 }   // 参数对象
})

// 方式2:路径字符串(不推荐,维护性差)
this.$router.push('/user/123')

接收

export default {
  props: ['id'], // 需路由配置 props: true
  mounted() {
    // 方式1:通过 props(推荐)
    console.log(this.id)

    // 方式2:通过 $route.params
    console.log(this.$route.params.id)
  }
}

Vuex核心使用

安装

安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装

npm i vuex@3

新建 store/index.js 专门存放 vuex

为了维护项目目录的整洁,在src目录下新建一个store目录其下放置一个index.js文件。 (和 router/index.js 类似)

创建仓库 store/index.js

// 导入 vue
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
Vue.use(Vuex)

// 创建仓库 store
const store = new Vuex.Store()

// 导出仓库
export default store

在 main.js 中导入挂载到 Vue 实例上

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

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store
}).$mount('#app')

成功创建了一个 空仓库

State

State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储。

打开项目中的store.js文件,在state对象中可以添加我们要共享的数据。

// 创建仓库 store
const store = new Vuex.Store({
  state: {
    count: 101
  }
})

state 状态, 即数据, 类似于vue组件中的data

state 中的数据整个vue项目的组件都能访问到

组件中可以使用 $store 获取到vuex中的store对象实例,可通过state属性属性获取count

<h1>state的数据 - {{ $store.state.count }}</h1>

组件逻辑中使用,把state中数据,定义在组件内的计算属性中

<h1>state的数据 - {{ count }}</h1>

  computed: {
    count () {
      return this.$store.state.count
    }
  }

js文件中使用,需要先引入store

import store from "@/store"

console.log(store.state.count)

Mutations

Mutations 的核心职责是直接修改 Vuex store 的状态(state)

mutations: {
  addCount (state, count) {
    state.count = count
  }
}

其中state 参数是必须的

在组件中发送请求更新state,需要使用$store.commit,其中传参可以是对象

this.$store.commit('addCount', 10)

this.$store.commit('addCount', {
  count: 10
})

若要传递多个数据,只能通过传对象的方式

actions

state是存放数据的,mutations是同步更新数据 (便于监测数据的变化, 更新视图等, 方便于调试工具查看变化),

actions则负责进行异步操作

定义actions

mutations: {
  changeCount (state, newCount) {
    state.count = newCount
  }
}

actions: {
  setAsyncCount (context, num) {
    // 一秒后, 给一个数, 去修改 num
    setTimeout(() => {
      context.commit('changeCount', num)
    }, 1000)
  }
},

组件中通过dispatch调用

setAsyncCount () {
  this.$store.dispatch('setAsyncCount', 666)
}

getters

除了state之外,有时我们还需要从state中筛选出符合条件的一些数据,这些数据是依赖state的,此时会用到getters

例如,state中定义了list,为1-10的数组,

state: {
    list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}

组件中,需要显示所有大于5的数据,正常的方式,是需要list在组件中进行再一步的处理,但是getters可以帮助我们实现它

  getters: {
    // getters函数的第一个参数是 state
    // 必须要有返回值
     filterList:  state =>  state.list.filter(item => item > 5)
  }

调用语法也很简单

<div>{{ $store.getters.filterList }}</div>

Vuex辅助函数

mapState

mapState 是 Vuex(Vue.js 的状态管理库)中的一个辅助函数,用于将 Vuex store 中的 state 属性快速映射到组件的计算属性中。它可以简化组件中获取全局状态的代码,避免重复声明计算属性

import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState(['count', 'message'])
  }
}

将 store.state.count 映射为 this.count
将 store.state.message 映射为 this.message

可直接{{count}}调用

mapMutations

mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入

import  { mapMutations } from 'vuex'
methods: {
    ...mapMutations(['addCount'])
}

此时,就可以直接通过this.addCount调用了

<button @click="addCount">值+1</button>

mapActions

mapActions 是把位于 actions中的方法提取了出来,映射到组件methods中

import { mapActions } from 'vuex'
methods: {
   ...mapActions(['changeCountAction'])
}

直接通过 this.方法 就可以调用

<button @click="changeCountAction(200)">+异步</button>

Vuex模块化

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

这句话的意思是,如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护

由此,又有了Vuex的模块化

准备 state

定义模块 usersetting

user中管理用户的信息状态 userInfo modules/user.js

const state = {}

export default {
  state,
}

store/index.js文件中的modules配置项中,注册模块

import user from './modules/user'
import setting from './modules/setting'

const store = new Vuex.Store({
    modules:{
        user,
    }
})

使用模块中的数据, 可以直接通过模块名访问 $store.state.模块名.xxx => $store.state.setting.desc

也可以通过 mapState 映射

获取模块内的state数据

尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的 state 中,属性名就是模块名

访问方式有两种

  1. 直接通过模块名访问 $store.state.模块名.xxx
  2. 通过 mapState 映射:mapState('模块名', ['xxx']) - 要开启命名空间 namespaced:true
const state = {}

export default {
  namespaced: true,
  state,
}

$store直接访问

$store.state.user.userInfo.name

mapState辅助函数访问

...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),

获取模块内的getters数据

使用模块中 getters 中的数据:

  1. 直接通过模块名访问 $store.getters['模块名/xxx ']
  2. 通过 mapGetters 映射:mapGetters('模块名', ['xxx']) - 需要开启命名空间
const getters = {
  // 分模块后,state指代子模块的state
  UpperCaseName (state) {
    return state.userInfo.name.toUpperCase()
  }
}

直接访问

<div>{{ $store.getters['user/UpperCaseName'] }}</div>

通过命名空间访问

computed:{
  ...mapGetters('user', ['UpperCaseName'])
}

获取模块内的mutations方法

  1. 直接通过 store 调用 $store.commit('模块名/xxx ', 额外参数)
  2. 通过 mapMutations 映射 :mapMutations('模块名', ['xxx']) - 需要开启命名空间
const mutations = {
  setUser (state, newUserInfo) {
    state.userInfo = newUserInfo
  }
}

直接访问

methods: {
  updateUser () {
    $store.commit('模块名/mutation名', 额外传参)
    },
}

通过命名空间访问

methods:{
...mapMutations('setting', ['setTheme']),
}

获取模块内的actions方法

  1. 直接通过 store 调用 $store.dispatch('模块名/xxx ', 额外参数)
  2. 通过 mapActions 映射:子模块的映射 mapActions('模块名', ['xxx']) - 需要开启命名空间
const actions = {
  setUserSecond (context, newUserInfo) {
    setTimeout(() => {
      context.commit('setUser', newUserInfo)
    }, 1000)
  }
}

直接通过store调用

methods:{
    update () {
      this.$store.dispatch('user/setUserSecond', {
        name: 'xiaohong',
        age: 28
      })
    },
}

mapActions映射

methods:{
  ...mapActions('user', ['setUserSecond'])
}
最后修改:2025 年 08 月 09 日
如果觉得我的文章对你有用,请随意赞赏