编辑
2026-04-01
undefined
00

目录

pinia
搭建pinia环境
存储+读取+修改数据
storeToRefs
getters
$subscribe
store组合式写法
组件通信
props
自定义事件
mitt
v-model
$attrs
$refs 和 $parent
provide和inject

学习之前内容:Vue 3 快速上手学习笔记

pinia

搭建pinia环境

第一步:pnpm install pinia

第二步:修改src/main.ts

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

存储+读取+修改数据

Store是一个保存状态、业务逻辑的实体,每个组件都可以读取、写入它。它有三个概念:stategetteraction,相当于组件中的: datacomputedmethods

新建src/store/sum.ts

import { defineStore } from 'pinia' // 定义并暴露一个store export const useSumStore = defineStore('sum', { // 状态 state() { return { sum: 9, school: 'Hello', } }, // 计算 getters: {}, // 里面放方法,用于响应组件中的“动作” actions: { increment(value: number) { if (this.sum < 10) { this.sum += value // this就是当前的store } }, }, })

修改src\App.vue

新建src\components\Sum.vue

patch({ //   sum: 666, //   school: 'abc', // }) // 第三种修改方式 sumStore.increment(n.value) } function minus() { sumStore.sum -= n.value } .sum { background-color: skyblue; padding: 10px; border-radius: 10px; box-shadow: 0 0 10px; } select, button { margin: 0 5px; height: 25px; }

storeToRefs

借助storeToRefs将store中的数据转为ref对象,方便在模板中使用。注意pinia提供的storeToRefs只会将数据做转换,而Vue的toRefs会转换store中所有数据(包括方法)。

修改src\components\Sum.vue

getters

当state中的数据,需要经过处理后再使用时,可以使用getters配置。

修改getters配置src\store\sum.ts

getters: { bigSum: (state): number => state.sum * 10, upperSchool(): string { return this.school.toUpperCase() }, },

修改src\components\Sum.vue

$subscribe

通过store的$subscribe()方法侦听state及其变化。

修改src\components\Sum.vue

sumStore.$subscribe((mutate, state) => { console.log('sumStore', mutate, state) })

store组合式写法

新建src\store\talkList.ts import { defineStore } from 'pinia' import axios from 'axios' import { nanoid } from 'nanoid' import { reactive } from 'vue'

export const useTalkStore = defineStore('talkList', () => { const talkList = reactive(JSON.parse(localStorage.getItem('talkList') as string) || [])

// getATalk函数相当于action async function getATalk() { let { data: { content: title }, // 连续解构赋值 + 重命名 } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')

let obj = { id: nanoid(), title } // 把请求回来的字符串包装成对象 talkList.unshift(obj) // 放入数组中

}

return { talkList, getATalk } })

修改src\App.vue

新建src\components\TalkList.vue

.talk { background-color: orange; padding: 10px; border-radius: 10px; box-shadow: 0 0 10px; }

组件通信

props

props是使用频率最高的一种通信方式,常用于父子通信:

  • 父传子:属性值非函数
  • 子传父:属性值是函数

修改src\App.vue

新建src\components\Father.vue .father { background-color: rgb(165, 164, 164); padding: 20px; border-radius: 10px; }

新建src\components\Child.vue

.child { background-color: skyblue; padding: 10px; box-shadow: 0 0 10px black; border-radius: 10px; }

自定义事件

常用于子传父,注意区分原生事件、自定义事件:

  • 原生事件:

  • 事件名是特定的(click、mosueenter等)

  • 事件对象$event: 包含事件相关信息的对象(pageX、pageY、target、keyCode)

  • 自定义事件:

  • 事件名可以任意名称

  • 事件对象$event: 是调用emit时所提供的数据,可以是任意类型

修改src\components\Father.vue

修改src\components\Child.vue

$event到底是啥?啥时候能.target:

  • 原生事件,$event就是事件对象,能 .target
  • 自定义事件,$event就是触发事件时,所传递的数据,不能 .target

mitt

与消息订阅与发布(pubsub)功能类似,实现任意组件间通信。

安装mitt:pnpm i mitt

新建src\utils\emitter.ts

import mitt from 'mitt' const emitter = mitt() // emitter.on() 绑定事件 // emitter.off() 解绑事件 // emitter.emit() 触发事件 // emitter.all.clear() 清理事件 export default emitter

在main.ts引入emitter

import { createApp } from 'vue' import App from './App.vue' import emitter from './utils/emitter' createApp(App).mount('#app')

src\App.vue

src\components\Father.vue

.father { background-color: rgb(165, 164, 164); padding: 20px; border-radius: 10px; } .father button { margin-left: 5px; }

提供数据组件src\components\Child1.vue,在合适时候触发事件。

.child1 { margin-top: 50px; background-color: skyblue; padding: 10px; box-shadow: 0 0 10px black; border-radius: 10px; } .child1 button { margin-right: 10px; }

接收数据组件src\components\Child2.vue:绑定事件、同时在卸载前解绑事件。

.child2 { margin-top: 50px; background-color: orange; padding: 10px; box-shadow: 0 0 10px black; border-radius: 10px; }

v-model

v-model用在HTML标签上:<input type="text" v-model="userName" />,本质上是:<input type="text" :value="userName" @input="userName = (<HTMLInputElement>$event.target).value" />

v-model用在组件标签上,本质上是:

+ update
事件。

可以在组件标签上多次使用v-model:<AInput v-model:usr="userName" v-model:pwd="password" />

$attrs

用于实现当前组件的父组件,向当前组件的子组件通信,即祖传孙。

attrs是一个对象,包含所有父组件传入的标签属性。attrs是一个对象,包含所有父组件传入的标签属性。attrs会自动排除props中声明的属性(可认为声明过的props被子组件自己“消费”了)。

父组件src\components\Father.vue:

子组件src\components\Child.vue:

孙组件:

refsrefs 和 parent

refs用于:父子,refs用于:父 → 子,parent用于:子 → 父。

  • $refs值为对象,包含所有被ref属性标识的DOM元素或组件实例
  • $parent值为对象,当前组件的父组件实例对象

src\components\Father.vue

src\components\Child.vue

provide和inject

实现祖孙组件直接通信,具体使用:

  • 在祖先组件中通过provide配置向后代组件提供数据
  • 在后代组件中通过inject配置来声明接收数据

src\components\Father.vue

src\components\Child.vue

src\components\GrandChild.vue

本文作者:a

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!