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>