Vue3-pinia、组件通信、插槽
pinia
集中式状态(数据)管理
组件间的数据共享
- 搭建pinia环境
import { createPinia } from "pinia";
const pinia = createPinia();
//安装pinia
app.use(pinia);
- 存储、读取数据
在src/store 这个仓库下创建count.ts
pinia中state函数存储数据
若是在reactive包裹ref,则reactive自动解包了,不需要.value
import { defineStore } from "pinia";
export const useCountStore = defineStore("count", {
state() {
//state函数,真正存储数据的地方
return {
sum: 6,
};
},
});
然后调用
import axios from "axios";
import { nanoid } from "nanoid";
import { useLoveStore } from "@/store/love";
const LoveStore = useLoveStore();
// function add() {
// let id = talkList.length + 1;
// talkList.push({ id, content: `这是第${id}条留言` });
// }
async function fetchTalks() {
let result = await axios.get(
"https://api.uomg.com/api/rand.qinghua?format=json"
);
console.log(result.data.content);
let obj = { id: nanoid(), content: result.data.content };
// talkList.push({
// id: talkList.length + 1,
// content: result.data.content,
// });
LoveStore.talkList.unshift(obj);
}
- 修改数据
三种方法
import { ref } from "vue";
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
// console.log("@@@", countStore); //等于countStore.$state.sum
let sum = ref(0);
let n = ref(1);
function add() {
//方法一直接修改
// countStore.sum += n.value;
//方法二——适合多种属性同时修改
// countStore.$patch({
// sum: 888,
// school: "尚硅谷",
// });
//方法三 利于复用
countStore.increment(n.value);
}
function sub() {
countStore.sum -= n.value;
}
import { defineStore } from "pinia";
export const useCountStore = defineStore("count", {
//actions里存放一个个方法用于响应组件中的动作
actions: {
increment(value: any) {
console.log("incremnet被调用了", value);
if (this.sum < 10) {
} //这个修改方法利于 以后的复用
//this是当前的countStore
console.log("this", this.sum);
this.sum += value;
},
},
state() {
//state函数,真正存储数据的地方
return {
sum: 6,
school: "hh",
};
},
});
-
storeToRefs
const {sum,school} =storeToRefs(countStore)只包裹store中的,而不对其他方法进行ref包裹 -
getters
对数据不满意时可以进行getters函数改变 -
$subscribe
LoveStore.$subscribe((mutate, state) => {
//mutate本次修改的信息,state数据
// console.log("数据发生变化", mutate, state);
//将数据存储到localStorage中,做到刷新不丢失
//注意:localStorage只能存储字符串,所以需要将对象转换为字符串
localStorage.setItem("talkList", JSON.stringify(state.talkList));
});
state() {
return {
// talkList: [
// { id: "njn1j1", content: "你怪怪的" },
// { id: "njkjb2", content: "我去" },
// { id: "hnjnjj3", content: "鹅鹅鹅饿" },
// ],
// 使用localStorage来持久化数据
talkList: JSON.parse(localStorage.getItem("talkList") || "[]"),
};
- store 组合式使用
export const useLoveStore = defineStore("love", () => {
const talkList = reactive(
JSON.parse(localStorage.getItem("talkList") || "[]")
);
async function increment() {
let result = await axios.get(
"https://api.uomg.com/api/rand.qinghua?format=json"
);
console.log(result.data.content);
let obj = { id: nanoid(), content: result.data.content };
talkList.unshift(obj);
}
return { talkList, increment };
});
ref定义的数据在模板里面可以不用.value
组件通信
- props :父子组件间
- 父传子:
父:<Child :car='car'/>
子:defineProps(['car'])<h4>{{car}} - 子传父:
父:
- 父传子:
<Child :car='car' :sendToy='getToy' />
function getToy(value:string){
toy.value=value;
}
子:
<button @click='sendToy(toy)' >玩具给父亲</button>
defineProps(['car','sendToy'])
- 自定义事件实现子传父
- 父:```
<Son @send-toy="getToy" />
import Son from "./son-self.vue";
import { ref } from "vue";
let toy = ref("");
function getToy(value: string) {
toy.value = value || "默认玩具";
}
- 父:```
- 子:```
<button @click="emit('send-toy', toy)">触发</button>
import { ref, onMounted } from "vue";
const toy = ref("遥控车");
//声明事件
const emit = defineEmits(["send-toy"]);
onMounted(() => {
setTimeout(() => {
emit("send-toy");
}, 3000);
});
- mitt
import mitt, { type Emitter } from "mitt";
type Events = {
"send-toy": string;
// 可以添加更多事件类型
};
const emitter: Emitter<Events> = mitt<Events>();
export default emitter;
<button @click="emitter.emit('send-toy', toy)">触发</button>
import emitter from "../utils/emitter";
import emitter from "../utils/emitter";
emitter.on("send-toy", (value: string) => {
toy.value = value || "默认玩具";
});
onUnmounted(() => {
emitter.off("send-toy");
});
- v-model
可以实现组件间的数据传递
是一个动态的value值和一个@input事件
$event.target
对于原生事件,$event就是事件对象=>可以.target
对于自定义事件,$event就是触发事件时所传递的数据=>不能.target
父:
<Son v-model="username" />
子:(ui组件库)
<input type="text" :value="modelValue" @input="emit('update:modelValue',
(<HTMLInputElement>$event.target).value)"></input>
defineProps(['modelValue']);
const emit=defineEmits(['update:modelValue']);
- $sttrs
用于实现祖->孙的通信
父:
<Son :a="a" :b="b" v-bind="{ x: 10, y: 20 }" :updateA="changeA" />
import Son from "./zz.vue";
let a = ref(1);
let b = ref(2);
function changeA(value: number) {
a.value += value;
}
子:
<grandson v-bind="$attrs" />
则孙可以直接:
<h4>{{ x }}--{{ y }}--{{ a }}</h4>
<button @click="updateA(6)">点击改变A</button>
defineProps(["x", "y", "a", "b", "updateA"]);
- $refs、$parent
$refs:父->子
$parent:子->父
父传子:
let house = ref(4);
let c1 = ref();
let c2 = ref();
function changeToy() {
console.log(c1.value);
c1.value.toy = "芭比娃娃";
// 通过 mitt 发送事件,传递新的玩具名称
// emitter.emit("send-toy", "芭比娃娃");
}
function changecom() {
console.log(c2.value);
c2.value.computer = "Dell XPS";
}
function all(refs: { [key: string]: any }) {
// console.log(refs);
for (let key in refs) {
console.log(key, refs[key]);
refs[key].book += 3;
}
}
defineExpose({ toy, book });
子传父:
<button @click="subHouse($parent)">干掉房产</button>
function subHouse(parent: any) {
console.log(parent);
parent.house -= 1;
}
- provide inject
实现子孙间直接的通信
父组件provide
// provide("qian", money.value); //向后代提供数据
function updateMoney(num: number) {
money.value -= num;
}
provide("che", car);
//不可以写money:money.value ->这是将.value一个值传过去了,而不是money这个响应式对象
provide("moneyContext", { money, updateMoney });
孙组件inject
let car = inject("che", { brand: "未知", price: 0 }); //获取祖先组件提供的数据
let { money, updateMoney } = inject("moneyContext", {
money: 0,
updateMoney: (x: number) => {},
});
- 插槽
- 默认插槽
父:
- 默认插槽
<Category title="今日美食城市">
<img :src="imgURL" alt="美食图片" />
</Category>
子做插槽
<div class="category">
<h3>{{ title }}</h3>
<slot></slot>
<!--默认插槽-->
</div>
- 具名插槽
<slot name='s2'></slot>
此时需要在需插的内上标记:v-slot:s2 v-slot ->也可以写为#s2
默认插槽的name='default'
- 作用域插槽
在子组件中做插槽,但数据在子组件中。父组件想用子组件中的数据决定样式进行插入
父:
<Game>
<template v-slot:qwe="a">
<ul>
<li v-for="game in a.youxi" :key="game.id">
{{ game.name }}
</li>
</ul>
</template>
</Game>
子:
slot name='qwe' :youxi="games"></slot>
浙公网安备 33010602011771号