vue3中vuex与router的改变

这篇博客介绍了Vue3中Vuex、Vue Router的使用方式与Vue2的不同,以及Pinia作为新的状态管理库的特性。文章通过一个购物车的例子展示了如何在Pinia中定义和使用store,以及如何在组件中与Vue Router配合实现页面跳转。同时,文章还讨论了Vuex和Pinia在性能和适用场景上的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vuex

在store/index

import { createStore } from 'vuex'
const store = createStore({
  state() {
    return {
      count: 0
    }
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})
export default store

在用的时候

<script setup>
  import { useStore } from 'vuex'
  import { computed } from 'vue'
  const store = useStore()
  const count = computed(() => {
    return store.state.count
  })
  const increment = () => {
    store.commit('increment')
  }
</script>
<template>
  <h1>
    <span>{{count}}</span>
    <button @click="increment">+</button>
  </h1>
</template>

与vue2不同的而地方是创建store的时候vue2是const store = new Vuex.Store({}),在挂载的时候vue2在main.js里面


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

而在vue3中通过app.use(store)进行使用

在main.js

import store from './store'
const app = createApp(App)
app.use(store) //通过app.use(store)进行使用
app.use(router)
app.mount('#app')

router

在router/index下

知识点:用createRouter来创建路由对象, createWebHistory是history模式

import { createRouter, createWebHistory } from 'vue-router'

import Home from '@/views/Home.vue'

const routes = [
  {
    path: '/home',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/About.vue')
  },
  {
    path: '/list/:id',
    name: 'list',
    component: () => import('../views/List.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

当用的时候在about.vue组件

知识点通过useRouter, useRoute 来创建vue2中的$router与$route

<script setup>
  import { useRouter, useRoute } from 'vue-router'

  const router = useRouter()
  const route = useRoute()

  const pushWithQuery = () => {
    router.push({
      name: 'home',
      query: {
        ...route.query
      }
    })
  }
</script>

<template>
  <h1>about</h1>
  <button @click="pushWithQuery">跳转到首页</button>
</template>

home.vue

<script setup>
</script>

<template>
  <router-link to="/about?id=13">关于我们</router-link>
  <br />
  <router-link to="/list/100">列表</router-link>
</template>

<style>
  
</style>

List.vue

知识点:onBeforeRouteLeave当这个页面离开的时候触发的钩子,比起vue2多了个on

<script setup>
  import { useRoute, onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
  import { watch,ref } from 'vue'

  const route = useRoute()
  let id =ref(route.params.id) 

  watch(
    () => route.params.id,
    newId => {
      id.value=newId
    }
  )

  onBeforeRouteLeave((to, from) => {
    const answer = window.confirm('真的要离开吗?')
    if (!answer) return false
  })

  // onBeforeRouteUpdate((to, from) => {
  //   if (to.params.id !== from.params.id) {
  //     console.log(to.params.id);
  //   id.value=to.params.id
  //     console.log('changed.',id)
  //   }
  // })

Pinia

多了两个方法import { defineStore, storeToRefs } from 'pinia'

createPinia 在main.js挂载的时候用import { createPinia } from 'pinia';app.use(createPinia())

通过defineStore来创建store对象,通过storeToRefs来让引入其他模块的store数据具有响应式

npm install pinia@next

比起vuex来说更加方便,处理异步更加方便,并且vuex只允许有一个store文件,但是Pinia与mobx一样可以有多个store文件,相比来说Pinia的性能更快,因为Pinia体积约1KB。在vuex中从 Vue 3 开始,getter 的结果不会像计算属性那样缓存,并且在Pinia中store 的 action 被调度为常规的函数调用,而不是使用 dispatch 方法或 MapAction 辅助函数

由于Pinea是轻量级的,体积很小,它适合于中小型应用。它也适用于低复杂度的Vue.js项目,因为一些调试功能,如时间旅行和编辑仍然不被支持。

将 Vuex 用于中小型 Vue.js 项目是过度的,因为它重量级的,对性能降低有很大影响。因此,Vuex 适用于大规模、高复杂度的 Vue.js 项目。

例子实现一个购物车:

首先在store文件夹下

第一个是productStore.js的store对象,用来异步获取商品列表的数据

import { defineStore } from 'pinia'
import catchDataApi from '../data/api'

export const useProductStore = defineStore({
  id: 'productStore',

  state: () => ({
    products: []
  }),

  actions: {
    async loadData() {
      try {
        const data = await catchDataApi()
        this.products = data
      } catch (error) {

      }
    }
  }
})

第二个是cartStore.js是用来存购物车数据,与添加购物车数据方法的store

import { defineStore, storeToRefs } from 'pinia'
import { useProductStore } from './productStore' //把商品的store引进来里面的数据可以用
export const useCartStore = defineStore({
  id: 'cartStore',
  state: () => ({
    cartList: []
  }),
  // cartList = [
  //   {
  //     id: 1,
  //     name: 'iphone12',
  //     price: 10000,
  //     quantity: 1
  //   }
  // ]
  actions: {
    addToCart(product) {
      // 在购物车里查找是否有这个商品
      const p = this.cartList.find((item) => {
        return item.id === product.id
      })
      // 如果找到了,购物车里的这个商品的数量加 1
      // 如果没有没有找到,添加这个商品到购物车
      if (!!p) {
        p.quantity++
      } else {
        this.cartList.push({
          ...product,
          quantity: 1
        })
      }
      // 当点击放入购物车,这个商品的库存需要减少一个
      const productStore = useProductStore()
      const { products } = storeToRefs(productStore)
      const p2 = products.value.find((item) => {
        return item.id === product.id
      })
      p2.inventory--
    }
  },
  getters: {
    totalPrice() {
      return this.cartList.reduce((sum, item) => {
        return sum + item.price * item.quantity
      }, 0)
    }
  }
})

第三个是用来计算的counterStore.js

import { defineStore, storeToRefs } from 'pinia'
import { useProductStore } from './productStore'
export const useCartStore = defineStore({
  id: 'cartStore',
  state: () => ({
    cartList: []
  }),
  // cartList = [
  //   {
  //     id: 1,
  //     name: 'iphone12',
  //     price: 10000,
  //     quantity: 1
  //   }
  // ]
  actions: {
    addToCart(product) {
      // 在购物车里查找是否有这个商品
      const p = this.cartList.find((item) => {
        return item.id === product.id
      })
      // 如果找到了,购物车里的这个商品的数量加 1
      // 如果没有没有找到,添加这个商品到购物车
      if (!!p) {
        p.quantity++
      } else {
        this.cartList.push({
          ...product,
          quantity: 1
        })
      }
      // 当点击放入购物车,这个商品的库存需要减少一个
      const productStore = useProductStore()
      const { products } = storeToRefs(productStore)
      const p2 = products.value.find((item) => {
        return item.id === product.id
      })
      p2.inventory--
    }
  },
  getters: {
    totalPrice() {
      return this.cartList.reduce((sum, item) => {
        return sum + item.price * item.quantity
      }, 0)
    }
  }
})

当在main.js挂载Pinia的时候

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

在vue文件里用的时候

首先在Product.vue文件夹下

<script setup>
import { storeToRefs } from 'pinia'
import { useProductStore } from '@/stores/productStore'
import { useCartStore } from '@/stores/cartStore'
const productStore = useProductStore()
const cartStore = useCartStore()
const { products } = storeToRefs(productStore)
const { addToCart } = cartStore
productStore.loadData()
</script>
<template>
  <h1>产品列表</h1>
  <hr>
  <ul>
    <li
      v-for="product in products"
    >
      {{product.name}} - ¥{{product.price}}
      <button 
        @click="addToCart(product)"
        :disabled="product.inventory <= 0"
      >放入购物车</button>
    </li>
  </ul>
</template>
<style lang="css">
/* css 代码 */
</style>

在Cart.vue下

<script setup>
import { storeToRefs } from 'pinia'
import { useCartStore } from '@/stores/cartStore'
const cartStore = useCartStore()
const { cartList, totalPrice } = storeToRefs(cartStore)
</script>

<template>
  <h1>购物车</h1>
  <hr>
  <ul>
    <li v-for="product in cartList">
      {{product.name}} : {{product.quantity}} x ¥{{product.price}} = ¥{{product.quantity * product.price}}
    </li>
  </ul>
  <div>
    总价:¥{{totalPrice}}
  </div>
</template>

<style lang="css">
/* css 代码 */
</style>

在根组件挂载的时候

<script setup>
import Product from '@/views/Product.vue'
import Cart from '@/views/Cart.vue'
</script>
<template>
  <Product></Product>
  <Cart></Cart>
</template>
<style lang="css">
/* css 代码 */
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值