准备一个案例
新建工程,创建components/Count.vue
<template>
<div class="count">
<h2> 当前求和为:{{sum}}</h2>
<!-- options 里面的value加:,可以让i从字符串变成number类型,也可以在v-model后面加number转number类型 -->
<select v-model.number="n">
<option :value="i" v-for="i in 10" :key="i">{{ i }}</option>
</select>
<button @click="add">加</button>
<button @click="min">减</button>
</div>
</template>
<script>
export default {
name: 'Counter'
}
</script>
<script setup>
import { ref } from 'vue'
const sum = ref(1)
const n = ref(1)
function add() {
sum.value += n.value
}
function min() {
sum.value -= n.value
}
</script>
<style lang="scss" scoped>
.count {
background-color: skyblue;
padding: 10px;
border-radius: 10px;
box-shadow: 0 0 10px;
}
select, button {
margin: 0 10px;
height: 25px;
}
</style>
创建components/Love.vue,npm install axios; npm install nanoid
<template>
<div class="love">
<button @click="getNewLove">获取一句土味情话</button>
<ul>
<li v-for="(item) in loveList" :key="item.id" v-html="item.text"></li>
</ul>
</div>
</template>
<script>
export default {
name: "Love"
}
</script>
<script setup>
import { reactive } from 'vue';
import axios from 'axios';
import { nanoid } from 'nanoid';
const loveList = reactive([
{id: 1, text: "心心念念全是你的脸。"},
{id: 2, text: "十五、说海枯石烂太远,说山盟海誓太大,我只愿能和你做一条线上的蚂蚁,一条爱情锁上的囚徒。"}
])
function getNewLove() {
// 这里不处理会有跨端问题,配置vite.config.js中的proxy,get里面的url不能包含http,否则就不会走proxy
axios.get('/words/api.php?return=json').then(res => {
loveList.unshift({
id: nanoid(),
text: res.data.word
})
}).catch(err => {
console.log(err);
})
}
</script>
<style lang="scss" scoped>
.love {
background-color: olive;
padding: 10px;
box-shadow: 0 0 10px;
border-radius: 10px;
}
</style>
配置vite.config.js,解决跨域问题
server: {
host: '0.0.0.0',
port: 80,
proxy: {
'/words/api.php': {
target: 'https://api.1314.cool',
changeOrigin: true,
secure: false, // 如果 HTTPS 证书有问题
}
},
},
pinia环境
npm i pinia
// main.js 中的内容
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
使用流程
创建src/store/Count.ts文件以及src/store/Love.ts文件, 名字和要使用pinia保存状态的vue文件名称保持一样。
Count.ts内容:
import { defineStore } from "pinia";
// 使用defineStore创建一个store,第一个入参是名称,第二个入参是对象,state方法里放要保存的数据
// 使用export导出后外面才能使用
export const useCountStore = defineStore("count", {
state: () => ({
sum: 6,
}),
});
使用者Count.vue调用
// 先引入
import { useCountStore } from '@/store/Count'
// 获取保存状态的countStore
const countStore = useCountStore()
// 模板中使用
<h2> 当前求和为:{{countStore.sum}}</h2>
完整读取数据示例
<template>
<div class="count">
<h2> 当前求和为:{{countStore.sum}}</h2>
<!-- options 里面的value加:,可以让i从字符串变成number类型,也可以在v-model后面加number转number类型 -->
<select v-model.number="n">
<option :value="i" v-for="i in 10" :key="i">{{ i }}</option>
</select>
<button @click="add">加</button>
<button @click="min">减</button>
</div>
</template>
<script>
export default {
name: 'Counter'
}
</script>
<script setup>
import { ref } from 'vue'
// 引入useCountStore
import { useCountStore } from '@/store/Count'
const n = ref(1)
// 使用useCountStore,得到一个专门保存count相关的store
const countStore = useCountStore()
function add() {
countStore.sum += n.value
}
function min() {
countStore.sum -= n.value
}
</script>
<style lang="scss" scoped>
.count {
background-color: skyblue;
padding: 10px;
border-radius: 10px;
box-shadow: 0 0 10px;
}
select, button {
margin: 0 10px;
height: 25px;
}
</style>
同样的方式,Love.ts
import { defineStore } from "pinia";
export const useLoveStore = defineStore("love", {
state: () => ({
loveList: [
{id: 1, text: "心心念念全是你的脸。"},
{id: 2, text: "十五、说海枯石烂太远,说山盟海誓太大,我只愿能和你做一条线上的蚂蚁,一条爱情锁上的囚徒。"}
],
}),
});
Love.vue使用完全代码
<template>
<div class="love">
<button @click="getNewLove">获取一句土味情话</button>
<ul>
<li v-for="(item) in loveStore.loveList" :key="item.id" v-html="item.text"></li>
</ul>
</div>
</template>
<script>
export default {
name: "Love"
}
</script>
<script setup>
import axios from 'axios';
import { nanoid } from 'nanoid';
// 引入useLoveStore
import { useLoveStore } from '@/store/Love';
// 使用useLoveStore,得到一个专门保存loveList相关的store
const loveStore = useLoveStore();
function getNewLove() {
axios.get('/words/api.php?return=json').then(res => {
loveStore.loveList.unshift({
id: nanoid(),
text: res.data.word
})
}).catch(err => {
console.log(err);
})
}
</script>
<style lang="scss" scoped>
.love {
background-color: olive;
padding: 10px;
box-shadow: 0 0 10px;
border-radius: 10px;
}
</style>
修改数据
上面示例中,我们直接修改数据,这种方式如果数据很多的时候不方便维护
function add() {
countStore.sum += n.value
}
比如我们修改Count.ts
export const useCountStore = defineStore("count", {
state: () => ({
sum: 6,
school: "河南师范大学",
location: "河南新乡"
}),
});
这时候如果要修改数据,则是这样
// 这种修改是没问题的,但是如果十几个字段这么写不美观,而且底层渲染的时候,mutation set会执行三次
countStore.sum += n.value
countStore.school = "school"
countStore.location = "location"
**第二种方式 ** $patch批量修改数据
// 这种方式$patch一次性批量修改数据内容,避免了mutation set执行三次的问题
countStore.$patch({
sum: 999,
school: '北京大学',
location: '北京'
})
第三种方式 actions方式
Count.ts修改为
import { defineStore } from "pinia";
export const useCountStore = defineStore("count", {
actions: {
add(n) {
this.sum+=n;
},
minus(n) {
this.sum-=n;
}
},
state: () => ({
sum: 6,
school: "河南师范大学",
location: "河南新乡"
}),
});
Count.vue中修改加减方法
function add() {
countStore.add(n.value)
}
function min() {
countStore.minus(n.value)
}
至此,Count已改造完成,同理,Love.ts Love.vue修改流程一样
// Love.ts 中的actions
actions: {
addLove() {
axios.get('/words/api.php?return=json').then(res => {
this.loveList.unshift({
id: nanoid(),
text: res.data.word
})
}).catch(err => {
console.log(err);
})
},
},
// Love.vue修改getNewLove
function getNewLove() {
loveStore.addLove();
}
模板读取优化
现在数据都是从countStore读取
<h2> 当前求和为:{{countStore.sum}}</h2>
可以使用解构进行优化,下面这种写法读取没问题,但是失去了响应式
const { sum } = countStore
<h2> 当前求和为:{{sum}}</h2>
使用toRefs优化,下面这种写法有了响应式,但是会把Count.ts中的方法和属性全都加上ref包裹,代价太大
const { sum } = toRefs(countStore)
可以直接打印看下
console.log(toRefs(countStore))
最优解是使用pinia中的storeToRefs,只会关注store中的数据,不会对方法进行ref包裹
const { sum } = storeToRefs(countStore)
console.log(storeToRefs(countStore))
getters
// Count.ts中:
export const useCountStore = defineStore("count", {
getters: {
// 对数据不满意,对数据进行加工,返回一个新的数据
doubleSum: (state) => state.sum * 2,
},
});
// 使用
const { sum, doubleSum } = storeToRefs(countStore)
<h2>@@@ {{doubleSum}}</h2>
$subscribe的使用,store中数据变化时调用
const loveStore = useLoveStore();
// 当数据更新时会执行subscribe
loveStore.$subscribe((mutation, state) => {
console.log("LoveStore 更新了!");
});
可以在这里进行数据持久化
loveStore.$subscribe((mutation, state) => {
localStorage.setItem('loveList', JSON.stringify(state.loveList));
});
在love.ts中,loveList数据先从本地读取,如果没读取到内容则返回空数组[]
state: () => ({
loveList: JSON.parse(localStorage.getItem("loveList")) || [],
}),