VueRouter路由与Vuex状态管理

前言

随着前端技术的快速发展和前后端分离架构的普及,单页面应用(SPA)已成为现代Web开发的主流。在SPA中,前端路由和状态管理扮演着至关重要的角色。Vue3作为当前流行的前端框架之一,提供了强大的路由(Vue Router)和状态管理(Vuex、Pinia等)解决方案。本章节将深入探讨Vue3中的路由与状态管理,涵盖路由的基本概念、实现原理、搭建与配置、动态与编程式路由、命名路由与视图、路由守卫等关键内容,以及Vuex和Pinia等状态管理库的基本使用、异步处理、计算属性和辅助函数的应用,还包括Vuex-persist数据持久化、模块分割和多状态管理等高级话题。此外,还将探讨在组合式API中如何使用Router和Vuex,并通过一个综合案例来加深理解。

一、路由的基本搭建与嵌套路由模

1、vue路由的搭建

路由在vue中属于第三方插件,需要下载安装后进行使用。

npm i -D vue-router

安装好后,需要对路由进行配置,并且与Vue进行结合,让路由插件生效。在/src/router/index.js创建配置文件。

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import { createRouter,createWebHistory } from "vue-router";

const routes=[
    {
        path: '/',
        component:Home
    },
    {
        path: '/test',
        component: Test
    }
]

// 创建路由实例
const router=createRouter({
    history:createWebHistory(),
    routes
})

export default router

src/main.js使用router。

import { createApp } from 'vue'
import App from './App.vue'
import router from "./router";

createApp(App).use(router).mount('#app')

src/views下创建Home页面,定义路由组件。

<template>
    <div class="wrapper">hello world</div>
</template>

<script>
export default {
    name: 'HomeView',
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>

src/views下创建Test页面,定义路由组件。

<template>
    <div class="wrapper">world hello</div>
</template>

<script>
export default {
    name: 'TestView',
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: aqua;
}
</style>

/src/App.vue

<template>
  <div>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
<style>
</style>

本地开发环境运行项目,通过url切换查看路由页面

npm run serve

image.png

切换url

image.png

2、路由跳转

修改App.vue

<template>
  <div>
    <router-link to="/">首页</router-link> |
    <router-link to="/test">测试</router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'App'
}
</script>
<style>
</style>

image.png

3、嵌套路由模式(二级路由)

src/views下创建TestChild页面,定义路由组件。

<template>
    <div class="wrapper">这里是test的嵌套路由</div>
</template>
<script>
export default {
    name: 'TestChild',
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: pink;
}
</style>

src/router下配置test嵌套路由。

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import TestChild from "@/views/TestChild.vue";
import { createRouter,createWebHistory } from "vue-router";
const routes=[
    {
        path: '/',
        component:Home
    },
    {
        path: '/test',
        component: Test,
        children:[
            {
                path:'testchild',
                component: TestChild
            }
        ]
    }
]
const router=createRouter({
    history:createWebHistory(),
    routes
})
export default router

test.vue中使用嵌套路由

<template>
    <div class="wrapper">world hello</div> 
    <router-link to="/test/testchild">嵌套路由</router-link>
    <div>
        <router-view></router-view>
    </div>
</template>
<script>
export default {
    name: 'TestView',
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: aqua;
}
</style>

image.png

二、动态路由模式与编程式路由模式

1、动态路由模式

所谓的动态路由其实就是不同的URL可以对应同一个页面,这种动态路由一般URL还是有规律可循的,所以非常适合做类似于详情页的功能。
通常采用path: 'xxx/:id'的方式来实现动态路由。

  • 动态路由TestChilddemo

/src/router配置TestChild动态路由

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import TestChild from "@/views/TestChild.vue";
import { createRouter,createWebHistory } from "vue-router";
const routes=[
    {
        path: '/',
        component:Home
    },
    {
        path: '/test',
        component: Test,
        children:[
            {
                path:'testchild/:id',
                component: TestChild
            }
        ]
    }
]
const router=createRouter({
    history:createWebHistory(),
    routes
})
export default router

修改Test.vue

<template>
    <div class="wrapper">world hello</div> 
    <router-link to="/test/testchild/1">嵌套路由</router-link>|
    <router-link to="/test/testchild/2">嵌套路由</router-link>
    <div>
        <router-view></router-view>
    </div>
</template>

image.png

image.png

  • 获取动态id值

TestChild.vuetemplate中获取动态路由id

{{$route.params.id}}

2、编程式路由(插槽方式)

前面介绍过如何在页面中对路由进行切换,可以采用声明式写法<router-link>来完成,但是往往这种方式不够灵活,首先不能更灵活的控制结构和样式,其次不能自动进行路由的跳转,必须点击操作才行。那么编程式路由就会在JavaScript中通过逻辑的方式进行路由跳转。

1)、作用域插槽

属性作用
href这是 <router-link> 组件解析后的目标 URL,可以用它来在 JavaScript 中进行编程式导航
route包含了当前路由信息的对象,可以通过它访问路由的路径、参数、查询等。
isActive表示<router-link>是否指向当前活跃的路由,to 属性所指定的路由与当前路由匹配(包括子路由)
isExactActive表示<router-link>是否精确匹配当前活跃的路由(路径),与to属性所指路由完全一致(不包括子路由)
navigate通常与路由跳转相关,this.$router.push()this.$router.replace() 这样的方法也能实现路由的跳转。

2)、 @click.preventthis.$router.push(href)this.$router.replace(),

@click监听 DOM 元素的点击事件,.prevent修饰符会调用事件对象的 preventDefault() 方法
preventDefault() 方法阻止元素的默认事件行为,从而确保确保不会有其他潜在的默认行为被意外触发
this.$router.push()会向浏览器的历史记录中添加一个新的记录,因此当用户点击后退按钮时,
他们会返回到使用 push() 方法跳转之前的页面。
this.$router.replace()用于跳转到指定的 URL,但它不会向浏览器的历史记录(history stack)中添加新的记录。

3)、demo案例,

修改App.vue,使用href, isExactActive ,isActive,href,通过this.$router.push(href)实现路由跳转

<template>
  <div>
    <router-link to="/">首页</router-link> |
    <router-link to="/test" v-slot="{ href, isActive }">
      <button :class="{ active: isActive }" @click.prevent="navigateTo(href)">
        测试
      </button>
    </router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'App',
  methods: {
    navigateTo(href) {
      this.$router.push(href);
    }
  }
}
</script>
<style scoped>
.active {
  color: #666;
  background: orange;
  border: none;
  /* 活跃的样式 */
  font-weight: bold;
}
</style>

image.png

image.png

修改Test.vue,使用navigatethis.$router.push(href)

<template>
  <div class="wrapper">
    <router-link to="/test/testchild/1" v-slot="{ href, isExactActive }">
      <button :class="{ 'exact-active1': isExactActive }" @click.prevent="navigateTo(href)">
        嵌套路由1
      </button>
    </router-link>
    <router-link to="/test/testchild/2" custom v-slot="{navigate, isExactActive }">
      <button  @click="navigate" :class="{ 'exact-active2': isExactActive }">
          嵌套路由2
      </button>
    </router-link>
  </div>
  <router-view></router-view>
</template>
<script>
export default {
  name: 'TestView',
  methods: {
    navigateTo(href) {
      this.$router.push(href);
    }
  }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: green;
}
.exact-active1 {
  color: orange;
}
.exact-active2 {
  color: purple;
}
</style>

image.png

image.png

三、命名路由与命名视图与路由元信息

1、普通命名路由

在路由跳转中,除了path 之外,你还可以为任何路由提供 name 的形式进行路由跳转。

  • 没有硬编码的 URL
  • params 的自动编码/解码
  • 防止你在 url 中出现打字错误
  • 绕过路径排序(如显示一个)

修改src/router,使用name:'test'

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import { createRouter,createWebHistory } from "vue-router";
const routes=[
    {
        path: '/',
        component:Home
    },
    {
        path: '/test',
        component: Test,
        name:'test'
    }
]
const router=createRouter({
    history:createWebHistory(),
    routes
})
export default router

修改App.vue,:to="{name:'test'}"

<template>
  <div>
    <router-link to="/">首页</router-link> |
    <router-link :to="{name:'test'}">测试
    </router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'App'
}
</script>
<style scoped>
</style>

2、命名路由(携带动态路由id)

修改src/router里的test路由path

{
        path: '/test/:id',
        component: Test,
        name:'test'
}

修改App.vue,通过params指定路由idparams:{id:123}

<template>
  <div>
    <router-link to="/">首页</router-link> |
    <router-link :to="{name:'test',params:{id:123} }">测试
    </router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'App'
}
</script>
<style scoped>
</style>

3、同级展示多个视图

修改src/router,使用components将HomeTest放在一起

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import { createRouter,createWebHistory } from "vue-router";
const routes=[
    {
        path: '/',
        components: {
            default: Home,
            test: Test,
        },
    }
]
const router=createRouter({
    history:createWebHistory(),
    routes
})
export default router

修改App.vue,使用router-view渲染视图

<template>
  <div>
    <router-view></router-view>
    <router-view name="test"></router-view>
  </div>
</template>
<script>
export default {
  name: 'App'
}
</script>
<style scoped>
</style>

修改Test.vue

<template>
  <div class="wrapper">Test</div>
</template>
<script>
export default {
  name: 'TestView',
}
</script>
<style scoped>
.wrapper {
  width: 100px;
  height: 100px;
  background: pink;
}
</style>

image.png

4、meta属性接受附加信息

修改src/router,给test路由加上meta属性

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import { createRouter,createWebHistory } from "vue-router";
const routes=[
    {
        path: '/',
        component:Home,
        name: 'home',
    },
    {
        path: '/test',
        component: Test,
        name:'test',
        meta:{auth:true}
    }
]
const router=createRouter({
    history:createWebHistory(),
    routes
})
export default router

test.vue中获取打印meta

mounted(){
    console.log(this.$route.meta.auth,'auth')
}

四、 路由传递参数的多种方式

  • query方式(显示) -> $route.query
  • params方式(显、隐式) -> $route.params

但是vue-router 从4.1.4版本开始 不再支持params 隐式传参,该传参方式之前一直是不推荐的,因为一旦刷新页面参数就获取不到了。
query:直接在 URL 中作为查询字符串(?id=value)显示
params 是通过路径中的动态段来传递的,而不是查询字符串

  • query、params传参

修改src/router

import Home  from "@/views/Home.vue";
import Test from "@/views/Test.vue";
import TestChild1 from "@/views/TestChild1.vue";
import TestChild2 from "@/views/TestChild2.vue";
import { createRouter,createWebHistory } from "vue-router";
const routes=[
    {
        path: '/',
        component:Home,
        name: 'home',
    },
    {
        path: '/test',
        component: Test,
        name:'test',
        children: [
            {
                path: 'testchild1',
                component: TestChild1,
                name: 'test1'
            },
            {
                path: 'testchild2/:id',
                component: TestChild2,
                name: 'test2'
            }
        ]
    }
]
const router=createRouter({
    history:createWebHistory(),
    routes
})
export default router

修改Test.vue

<template>
  <div class="wrapper">
    <router-link :to="{name:'test1', query: { id: 111 } }">Test1</router-link> |
    <router-link :to="{name:'test2', params: { id: 222 } }">Test2</router-link> 
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'TestView'
}
</script>
<style scoped>
.wrapper {
  width: 100px;
  height: 100px;
  background: pink;
}
</style>

新建src/views/TestChild1.vue

<template>
    <div class="wrapper">TestChild1</div>
</template>
<script>
export default {
    name: 'TestChild1',
    mounted(){
        console.log(this.$route.query,'query')
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: green;
}
</style>

新建src/views/TestChild2.vue

<template>
    <div class="wrapper">TestChild2</div>
</template>
<script>
export default {
    name: 'TestChild2',
    mounted() {
        console.log(this.$route.params, 'params')
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: blue;
}
</style>

image.png

image.png

五、route对象与router对象

1、route对象是获取路由信息 -> $route.params

route对象对应属性功能作用
fullPath完整路径包含了查询参数和 hash 的完整解析后的 URL
hashURL hash 值当前的 URL hash 值 (带 #)
href解析后的目标 URL解析完成后的 URL,等同于 window.location.href
matched匹配的路由记录数组包含了当前匹配的路由的所有嵌套路径片段的路由记录(数组)
meta路由元信息包含在路由定义中可以自定义的任意字段,常用于路由元数据的存储
name当前路由的名字当前路由的名称(如果有的话)
params动态段值一个 key/value 对象,包含了动态片段和全匹配片段的键值对
path路径字符串,对应当前路由的路径,总是解析为绝对路径,如 “/test”
query查询参数一个 key/value 对象,包含了 URL 查询参数(没有 ?)

2、router对象是调用路由方法 -> $router.push()

router对象对应属性功能作用
addRoute动态添加路由允许你在运行时向路由映射添加新的路由规则
afterEach全局后置守卫在所有路由跳转完成以后调用,不接受任何参数
back后退模拟点击浏览器后退按钮,相当于 window.history.back()
beforeEach全局前置守卫在路由跳转前调用,常用于登录验证、页面加载前的数据处理等
beforeResolve全局解析守卫在路由被解析之后调用,但在组件被渲染之前
currentRoute当前路由对象一个可以观察的对象,表示当前激活的路由的状态信息
forward前进模拟点击浏览器前进按钮,相当于 window.history.forward()
getRoutes获取路由配置获取路由映射中定义的路由记录数组
go前进或后退控制历史记录中前进或后退的步数,相当于 window.history.go(n)
hasRoute检查路由是否存在
push编程式导航导航到不同的URL,此方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL
removeRoute动态删除路由允许你在运行时从路由映射中删除特定的路由规则

3、路由守卫详解及应用场景

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航,守卫主要的作用就是在进入到指定路由前做一个拦截,看一下我们是否具备权限,如果有权限就直接进入,如果没权限就跳转到其他页面。

路由守卫分类一般可以分为三种路由守卫使用的方式:

  • 全局环境的守卫
  • 路由独享的守卫
  • 组件内的守卫

全局环境的守卫,其中to表示需要进入到哪个路由,from表示从哪个路由离开的,那么next表示跳转到指定的页面。

router.beforeEach((to, from, next)=>{
  if(to.meta.auth){
    next('/');
  }
  else{
    next();
  }
})

路由独享的守卫,只给某一个指定的路由添加守卫

const routes = [
    {
        name: 'bar',
        component: Bar,
        beforeEnter(to, from, next){
            if(to.meta.auth){
                next('/');
            }
            else{
                next();
            }
        }
    }
];

组件内的守卫,可以通过在.vue文件中进行路由守卫的设置,代码如下:

<script>
  export default {
    name: 'FooView',
    beforeRouteEnter(to, from, next){
      if(to.meta.auth){
        next('/');
      }
      else{
        next();
      }
    }
  }
</script>

六、Vuex共享状态

image.png

1、Vuex五大核心模块

模块名称描述功能与特性
state状态管理用来存放应用的状态(数据,类似于Vue组件中的data属性,是响应式的,当状态改变时,视图会自动更新
getters计算属性可以获取state中的状态并进行计算后返回,类似于Vue组件中的computed属性, 可以用于对状态进行复杂处理,返回处理后的结果
mutations同步状态更新唯一可以修改state的方法,必须是同步函数,用于处理同步事务, 提交时,可以使用commit方法
actions异步操作可以包含任意异步操作,通过提交mutations来改变state,可以包含任意异步操作,如API请求, 提交时,可以使用dispatch方法
modules模块化开发将单一状态树分割成多个模块,每个模块拥有自己的state、mutations、actions、getters, 使得代码更加清晰,便于维护, 可以使用modules属性将多个模块合并成一个单一的Vuex store
  • 安装vuex
npm i -D vuex

2、使用state模块,状态管理

用来存放应用的状态(数据,类似于Vue组件中的data属性,是响应式的,当状态改变时,视图会自动更新

常见的state属性状态管理对象

属性名类型初始值描述
countnumber0计数器的当前值,用于示例
userInfoObject{ name: ‘’, email: ‘’ }用户信息对象,包含姓名和电子邮件
isLoggedInboolean0表示用户是否已登录的标志
cartItemsArray[]购物车中的商品列表
selectedCategorystringall当前选中的商品分类(例如:‘all’, ‘electronics’, 'books’等)
  • 新建src/store/index.js
import { createStore } from "vuex";
const store=createStore({
    state:{
        count:0
    }
});
export default store
  • src/main.js中引入store
import { createApp } from 'vue'
import App from './App.vue'
import router from "./router"
import store from "./store"
createApp(App).use(router).use(store).mount('#app')
  • .vue文件中使用store,如Home.vue
<template>
    <div>{{ $store.state.count }}</div>
</template>
<script>
export default {
    name: 'HomeView'
}
</script>
<style scoped>
</style>

3、使用getters模块,计算属性

可以获取state中的状态并进行计算后返回,类似于Vue组件中的computed属性, 可以用于对状态进行复杂处理,返回处理后的结果

  • 修改src/store/index.js
import { createStore } from "vuex";
const store=createStore({
    state: {
        users: [
            { id: 1, name: 'A', isActive: true },
            { id: 2, name: 'B', isActive: false },
            { id: 3, name: 'C', isActive: true },
        ]
    },
    getters: {
        activeUsersCount: state => {
            return state.users.filter(user => user.isActive).length;
        }
    }
});
export default store
  • 修改Home.vue
<template>
    <div class="wrapper">
         <p>活跃用户数量: {{ activeUsersCount }}</p>
         <!-- <p>活跃用户数量: {{ $store.getters.activeUsersCount }}</p> -->
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    computed: {
        activeUsersCount() {
            return this.$store.getters.activeUsersCount;
        }
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>
  • 修改Test.vue,注释count使用
//{{ $store.state.countModule.count }}

4、使用mutations模块,同步状态更新

唯一可以修改state的方法,必须是同步函数,用于处理同步事务, 提交时,可以使用commit方法

  • 修改src/store/index.js
import { createStore } from "vuex";
const store=createStore({
    state:{
        count:0
    },
    mutations: {
        plus(state){
            state.count++
        }
    }
});
export default store
  • 修改Home.vue
<template>
    <div class="wrapper">
         {{ $store.state.count }}
        <button @click="handleClick">点击</button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    methods:{
        handleClick(){
            // this.$store.state.count++
            this.$store.commit('plus')
        }
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>
  • 修改Test.vue
<template>
  <div class="wrapper">
    {{ $store.state.count }}
  </div>
</template>
<script>
export default {
  name: 'TestView'
}
</script>
<style scoped>
.wrapper {
  width: 100px;
  height: 100px;
  background: pink;
}
</style>

5、使用actions模块,异步操作

异步操作|可以包含任意异步操作,通过提交mutations来改变state,可以包含任意异步操作,如API请求, 提交时,可以使用dispatch方法

  • 修改src/store/index.js
import { createStore } from "vuex";
const store=createStore({
    state:{
        count:0
    },
    mutations: {
        plus(state, payload){
            state.count++
            console.log(payload,'mutations-payload')
        }
    },
    actions: {
        update(context,payload){
            setTimeout(()=>{
                console.log(payload,'actions-payload')
                context.commit('plus', payload)
            })
        }
    }
});
export default store
  • 修改Home.vue
<template>
    <div class="wrapper">
         {{ $store.state.count }}
        <button @click="handleClick">点击</button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    methods:{
        handleClick(){
            const num=999
            this.$store.dispatch('update',num)
        }
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>

6、使用modules模块,模块化开发

将单一状态树分割成多个模块,每个模块拥有自己的state、mutations、actions、getters, 使得代码更加清晰,便于维护, 可以使用modules属性将多个模块合并成一个单一的Vuex store

  • 新建src/store/modules/index.js
const state = {
    count: 0
}
const getters={}
const actions={}
const mutations={
    plus(state) {
        state.count++
    }
}
export default {
    namespaced:true,
    state,
    getters,
    actions,
    mutations
}
  • 修改src/store/index.js,使用modules:{countModule }加载单个countModule模块
import { createStore } from "vuex"
import countModule from "./modules/index"
const store = new createStore({
    state: {},
    getters :{},
    mutations: {},
    actions: { },
    modules:{
        countModule
    }
})
export default store
  • 修改Home.vue,还是通过this.$store.commit('plus')或者this.$store.commit('countMoudlues/plus')调用mutations模块里的plus方法
<template>
    <div class="wrapper">
        {{ $store.state.countModule.count }}
        <button @click="handleClick">点击</button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    methods: {
        handleClick() {
            this.$store.commit('countMoudlues/plus')
        }
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>
  • 修改Test.vue,通过{{ $store.state.countModule.count }}获取count
<template>
  <div class="wrapper">
    {{ $store.state.countModule.count }}
  </div>
</template>
<script>
export default {
  name: 'TestView'
}
</script>
<style scoped>
.wrapper {
  width: 100px;
  height: 100px;
  background: pink;
}
</style>

7、vuex的辅助函数

Vuex 提供了一些辅助函数(helper functions)来帮助我们更方便地在 Vue 组件中使用 Vuex 的状态(state)、getters、mutations 和 actions。这些辅助函数通常在结合 Vue 的 mapState、mapGetters、mapMutations 和 mapActions 一起使用时非常有用。

  • 修改home.vue,@click="plus()"中plus可以传递参数
<template>
    <div class="wrapper">
        {{ count }}
        <button @click="plus()">点击</button>
    </div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
    name: 'HomeView',
    methods: {
        ...mapMutations('countModule', ['plus'])
    }, computed: {
        // 使用对象展开运算符将 `mapState` 的结果混入 computed 对象中
        // ...mapState(['count'])
        //如果是使用的countModule模块,则使用
        ...mapState('countModule', ['count'])
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>

8、Vuex-presist对数据进行持久化处理

Vuex-presist文档

将Vuex的状态持久化到本地存储(如localStorage或sessionStorage),以便在页面刷新或重新加载时能够恢复状态。这对于需要长期存储的数据(如用户信息、令牌等)特别有用。

  • 安装插件,使用上一节的mutations的模块案例扩展使用Vuex-presist
npm i -D vuex-persist
  • 修改src/store/index.js
import { createStore } from "vuex"
import VuexPersistence from 'vuex-persist'
const vuexLocal = new VuexPersistence({
    //默认存储window下的localStorage
    storage: window.localStorage,
    // 单一存储对象,一般会存储,state中的user和token属性
    // reducer: (state)=>({count:state.count})
})
const store = new createStore({
    state: {
        count: 0
    },
    mutations: {
        plus(state) {
            state.count++
        }
    },
    actions: { },
    plugins: [vuexLocal.plugin]
})
export default store
  • 修改Home.vue
<template>
    <div class="wrapper">
        {{ $store.state.count }}
        <button @click="handleClick">点击</button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    methods: {
        handleClick() {
            // this.$store.state.count++
            this.$store.commit('plus')
        }
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>

七、使用组合式api获取router。router,vuex对象

在 Vue 3 中,随着 Composition API 的引入,我们使用新的逻辑组合和重用来编写我们的 Vue 组件。

import { useRoute,useRouter,useStore } from 'vue-router';
export default {
  setup() {
    const route = useRoute();
    const router = useRouter();
    const store = useStore();
    console.log(route,'route)
    console.log(router,'router)
    console.log(store,'store)
  }
};
的localStorage
    storage: window.localStorage,
    // 单一存储对象,一般会存储,state中的user和token属性
    // reducer: (state)=>({count:state.count})
})
const store = new createStore({
    state: {
        count: 0
    },
    mutations: {
        plus(state) {
            state.count++
        }
    },
    actions: { },
    plugins: [vuexLocal.plugin]
})
export default store
  • 修改Home.vue
<template>
    <div class="wrapper">
        {{ $store.state.count }}
        <button @click="handleClick">点击</button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    methods: {
        handleClick() {
            // this.$store.state.count++
            this.$store.commit('plus')
        }
    }
}
</script>
<style scoped>
.wrapper {
    width: 100px;
    height: 100px;
    background: orange;
}
</style>

七、使用组合式api获取router。router,vuex对象

在 Vue 3 中,随着 Composition API 的引入,我们使用新的逻辑组合和重用来编写我们的 Vue 组件。

import { useRoute,useRouter,useStore } from 'vue-router';
export default {
  setup() {
    const route = useRoute();
    const router = useRouter();
    const store = useStore();
    console.log(route,'route)
    console.log(router,'router)
    console.log(store,'store)
  }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/693217.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【React】json-server的使用

参考文章 【文章一】 【文章二】 json-server详解 1、简介 Json-server 是一个零代码快速搭建本地 RESTful API 的工具。它使用 JSON 文件作为数据源&#xff0c;并提供了一组简单的路由和端点&#xff0c;可以模拟后端服务器的行为。github地址&#xff1a;https://github.…

理解数仓建模

​​​在数仓建设的过程中&#xff0c;由于未能完全按照规范操作&#xff0c; 从而导致数据仓库建设比较混乱&#xff0c;常见有以下问题&#xff1a; 数仓常见问题 ● 数仓分层不清晰&#xff1a;数仓的分层没有明确的逻辑&#xff0c;难以管理和维护。 ● 数据域划分不明确…

启动游戏出现concrt140.dll错误的解决方法

concrt140.dll是一个动态链接库文件&#xff0c;属于Microsoft Visual C 2015 Redistributable组件集的一部分。这个文件是并发运行时库&#xff08;Concurrency Runtime&#xff09;的一部分&#xff0c;对于支持和增强应用程序的多线程与并发执行能力至关重要。它包含了实现并…

QT c++ 堆栈一些理解--限制对象建立在栈上--栈堆区别

图示形象化理解&#xff1a; 堆栈都是数据结构存取数据的方式 堆&#xff1a;理解为一个堆积物体&#xff0c;独立的分散的&#xff0c;当需要空间时&#xff0c;再找一个地方。需要的就是new关键字&#xff0c;动态申请一个空间。程序员自己动态分配空间&#xff0c;使用指针…

线性回归例子, 学习笔记[机械学习]

参考书籍, [pythonによる機械学習入門] y ax b # 直线的线性回归 import numpy as np import matplotlib.pyplot as plt # 求最小二乘法的回归直线,用到的库 from sklearn import linear_model# x 和 y的单点图 x np.random.rand(100, 1) x x*4-2 y 3*x-2 # 增加一部分乱…

LLVM Cpu0 新后端10

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1V_tZkt9uvxo5bnUufhMQ_Q?…

[图解]企业应用架构模式2024新译本讲解12-领域模型5

1 00:00:00,560 --> 00:00:04,690 刚才是往那个表里面添加数据了 2 00:00:04,700 --> 00:00:07,960 相当于&#xff0c;或者往这个合同里面添加数据了 3 00:00:08,430 --> 00:00:09,530 现在要查询怎么办 4 00:00:09,900 --> 00:00:10,930 跟前面一样 5 00:00:…

JDK下载安装Java SDK

Android中国开发者官网 Android官网 (VPN翻墙) 通过brew命令 下载OracleJDK(推荐) 手动下载OracleJDK(不推荐) oracle OracleJDK下载页 查找硬件设备是否已存在JDK环境 oracle官网 备注&#xff1a; JetPack JavaDevelopmentKit Java开发的系统SDK OpenJDK 开源免费SDK …

6路以太网,8路串行接口,继电器、DI、IRIG-B等多路通讯及控制接口,并支持蓝牙、GPS、北斗、Wifi、2G/3G/4G等功能

●是基于ARM Cortex™-A9的嵌入式产品&#xff0c;主频高达四核1.2GHz&#xff0c;实现了HD级别的视频加速器并通过全新的集成电源管理解决方案实现最佳的节能效果。 硬件集成了6路以太网&#xff0c;8路串行接口&#xff0c;继电器、DI、IRIG-B等多路通讯及控制接口&#xff0…

最值,反转数组——跟之前的差不多

文章目录 数组最值感悟改进 反转数组问题 代码改进 数组最值 package com.zhang; /*求数组最大最小值*/ public class test_arr1 {public static void main(String[] args) {int[] arr {10,66,42,8,999,1};max(arr);min(arr);}public static int max(int[] arr){int max arr…

新增FTP功能、支持添加Redis远程数据库,专业版新增网站监控和黑金主题,1Panel开源面板v1.10.10版本发布

2024年6月7日&#xff0c;现代化、开源的Linux服务器运维管理面板1Panel发布v1.10.10版本。 在这一版本中&#xff0c;1Panel新增了多项实用功能。社区版方面&#xff0c;新增了FTP功能、支持添加Redis远程数据库、支持设置压缩密码&#xff0c;并新增了清理镜像构建缓存的功能…

倩女幽魂搬砖攻略:云手机自动托管搬砖刷本选哪家云手机?

欢迎来到《倩女幽魂手游》的世界&#xff0c;一个充满江湖恩怨的世界。在这个游戏中&#xff0c;你将扮演各个门派中的不同职业&#xff0c;踏上一段属于你自己的江湖之路。本攻略将为你详细介绍如何利用多开挂机搬砖&#xff0c;快速提升自己的实力&#xff0c;成为江湖中的一…

002-链路聚合

链路聚合 链路聚合是一个重要的计算机网络术语&#xff0c;它涉及将多个物理端口汇聚在一起&#xff0c;形成一个逻辑端口&#xff0c;从而增加网络带宽、实现链路传输的弹性和工程冗余。 定义与基本原理 定义&#xff1a;链路聚合&#xff08;英语&#xff1a;Link Aggrega…

python数据分析-连云港石化基地2023年用电量分析

接下来对连云港石化基地2023年用电量进行分析&#xff0c;首先导入数据分析基本的包&#xff1a; import pandas as pd import matplotlib.pyplot as plt# Load the data from the provided Excel files file_path1 data1.xlsx file_path2 data2.xlsxdata1 pd.read_excel(f…

轻松构建聊天机器人,大模型 RAG 有了更强大的AI检索器

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

【机器学习300问】109、什么是岭回归模型?

在进行回归任务时间&#xff0c;可以能会遇到特征数量多于观测数量或某些特征变量之间相关性较高&#xff08;几乎线性相关&#xff09;时&#xff0c;标准的线性回归模型的系数估计可能非常不精确&#xff0c;可以理解成独立方程个数小于未知数个数此时方程有无穷多解。 例如&…

基于SVPWM矢量控制的无速度传感器电机控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于SVPWM矢量控制的无速度传感器电机控制系统simulink建模与仿真&#xff0c;包括电机&#xff0c;SVPWM模块&#xff0c;矢量控制器模块等。 2.系统仿真结果 3.核心程序与模…

ChatGPT为啥不用Websocket而是EventSource?

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

《精通ChatGPT:从入门到大师的Prompt指南》第9章:实战练习

第9章&#xff1a;实战练习 9.1 Prompt练习题 在本节中&#xff0c;我们将提供一系列练习题&#xff0c;旨在帮助读者通过实际操作提升使用ChatGPT的能力。这些练习题涵盖了从基础到高级的不同难度级别&#xff0c;并针对各种应用场景设计&#xff0c;确保读者能够在实际使用…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(三十一)- 微服务(11)

12.7 DSL查询语法 查询的基本语法 GET /indexName/_search{"query": {"查询类型": {"查询条件": "条件值"}}} 查询所有 GET /hotel/_search{"query": {"match_all": {}}} 12.7.1 全文检索查询 全文检索查询,会…