目次
1. 親コンポーネントから子コンポーネントへの通信をサポートする
4. v-modelコンポーネント通信(親子コンポーネントデータ同期)
ref はサブコンポーネントのインスタンス オブジェクトを取得します
$parent は親コンポーネントのインスタンス オブジェクトを取得します
Vue3 を使用してプロジェクトを開発する場合、よく直面する問題の 1 つはコンポーネント間の通信です。どのようにデータを対応するコンポーネントに送信するかは避けられない問題です。この記事では、Vue3 の 8 つの主要な通信方法について説明します。(他にも追加可能です)
1. 親コンポーネントから子コンポーネントへの通信をサポートする
親コンポーネント:
props は、データを子コンポーネントに渡すために親コンポーネントによって使用され、子コンポーネントは、definePropsを使用して、親コンポーネントによって渡されたパラメータを受け取ります。
親コンポーネントでは、使用時に子コンポーネントに props データを渡すことができます。
<Child info="父组件" v-bind:money="10000"></Child>
v-bindを使用しないデータは固定データ、v-bindを使用する場合は動的データとなります。
サブアセンブリ:
子コンポーネントでデータを受信する
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info', 'money'])
このメソッドは単純な記述方法であり、より多くの用途があり、データ型とデフォルト値を指定できるオブジェクトを記述する別の方法があります。
let props = defineProps({
info: {
type: String,
required: true, //是否规定必须得有
default: 'info默认值'
},
money: {
type: Number,
required: true, //是否规定必须得有
default: 9999 //默认数据,当父组件没有传递数据时,读取该数据
}
サブコンポーネントでの使用も非常に簡単です (両方の方法が利用可能です)。
<p>{
{props.info}}</p>
<p>{
{props.money}}</p>
<!--props可以省略前面的名字--->
<p>{
{info}}</p>
<p>{
{money}}</p>
注: 小道具のデータは読み取り専用であり、変更できません
2. カスタム イベントの子が親コンポーネントと通信する
親コンポーネント
親コンポーネントでカスタム イベントを受信する
<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
<Event2 @xxx="handler3"></Event2>
//事件回调---4
const handler3 = (val1, val2) => {
console.log(val1, val2)
}
サブアセンブリ
主に、サブコンポーネントは、 defineEmitsメソッドを使用して、カスタム イベントをトリガーする関数を返します。
//利用defineEmits方法返回函数触发自定义事件
//defineEmits方法不需要引入直接使用
let $emit = defineEmits(['xxx'])
イベント渡しパラメータのバインディング
<button @click="handler">点击我触发自定义事件xxx</button>
//按钮点击回调
const handler = () => {
//第一个参数:事件类型 第二个|三个|N参数即为注入数据
$emit('xxx', 'data1', 'data2')
}
ボタンをクリックすると、データが親コンポーネントに渡され、親コンポーネントは対応するパラメータを受け取ります。
3. グローバルイベントバス
Vue3 では vue コンストラクターが削除されているため、VM がなく $bus グローバル イベント バスを実現できません。グローバル イベント バスを実装するには、mitt プラグインを使用して実現できます。
ミットはプロジェクトにインストールできます
npm install --save mitt
データを渡す必要があるコンポーネントでは、$bus.emit メソッドがデータを渡します。
//引入$bus对象
import mitt from 'mitt'
const $bus = mitt()
//点击按钮回调
const handler = () => {
$bus.emit('car', { car: '法拉利' })
}
データを受信するコンポーネントでは、$bus.on がデータを受信するメソッドです
import mitt from 'mitt'
const $bus = mitt()
//组合式API函数
import { onMounted } from 'vue'
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
//第一个参数:即为事件类型 第二个参数:即为事件回调
$bus.on('car', (car) => {
console.log(car)
})
})
4. v-modelコンポーネント通信(親子コンポーネントデータ同期)
v-modelというとフォームデータの双方向バインディングを実現できるというイメージがあるかもしれませんが、実は親コンポーネントと子コンポーネントのデータ同期も実現できます。
単一のデータ同期をバインドする
v-model を使用しない場合、親コンポーネントと子コンポーネントのデータを同期したい場合は、次のように props とカスタム イベントを同時に使用できます。
親コンポーネント:
//props:父亲给儿子数据
<Child :modelValue="money" @update:modelValue="handler"></Child>
<script setup lang="ts">
import Child from './Child.vue'
import { ref } from 'vue'
let money = ref(10000)
//自定义事件的回调
const handler = (num) => {
//将来接受子组件传递过来的数据
money.value = num
}
</script>
サブアセンブリ:
<template>
<div class="child">
<h3>钱数:{
{ modelValue }}</h3>
<button @click="handler">父子组件数据同步</button>
</div>
</template>
<script setup lang="ts">
//接受props
let props = defineProps(["modelValue"]);
let $emit = defineEmits(['update:modelValue']);
//子组件内部按钮的点击回调
const handler = ()=>{
//触发自定义事件
$emit('update:modelValue',props.modelValue+1000);
}
</script>
親コンポーネントと子コンポーネント間のデータ同期を実現するには、プロパティとカスタム イベントを同時に使用する必要があることがわかります。
v-model を使用すると、次のことを実現できます。
サブコンポーネントのラベルを変更するだけです
<Child v-model="money"></Child>
v-model はコンポーネントで使用されます
1: props[modelValue] = 10000 を子コンポーネントに渡すことが非常に必要です
2: カスタム イベント update:modelValue をサブコンポーネントにバインドするのと同じです
複数のデータのバインド同期
親コンポーネント:
<Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
//父亲的数据
let pageNo = ref(1)
let pageSize = ref(3)
子コンポーネントは以下を受け取ります。
<template>
<div class="child2">
<h1>同时绑定多个v-model</h1>
<button @click="handler">pageNo{
{ pageNo }}</button>
<button @click="$emit('update:pageSize', pageSize + 4)">
pageSize{
{ pageSize }}
</button>
</div>
</template>
<script setup lang="ts">
let props = defineProps(["pageNo", "pageSize"]);
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
//第一个按钮的事件回调
const handler = () => {
$emit("update:pageNo", props.pageNo + 3);
};
</script>
主な実装原則は依然として props とカスタム イベントの組み合わせを使用しており、v-model はデータとメソッドの同期に役立つだけです
5. useAttrsコンポーネントの通信
親コンポーネント: message プロパティを子コンポーネントに渡します。
<template>
<div>
<input v-model="message">
<HidtButton :message="message" />
</div>
</template>
<script setup lang="ts">
import HidtButton from './HintButton.vue'
import { ref } from 'vue'
const message = ref('')
</script>
サブコンポーネント: useAttrs を使用してデータを受信して表示する
<template>
<div>
<p>{
{ $attrs.message }}</p>
</div>
</template>
<script setup lang="ts">
import { useAttrs } from 'vue'
let $attrs = useAttrs()
console.log($attrs)
</script>
useAttrs は親コンポーネントの属性を受け取ることができます
このようにして、子コンポーネントは親コンポーネントのデータを受け取ります。
useAttrs の機能は props の機能と非常によく似ています。両方の親コンポーネントがデータを子コンポーネントに渡します。props と useAttrs を同時にデータの受信に使用する場合、props の優先順位が useAttrs よりも高くなります。
6.refと$parent
ref はサブコンポーネントのインスタンス オブジェクトを取得します
参考: 実際の DOM ノードを取得し、サブコンポーネント インスタンス VC を取得し、親コンポーネントのサブコンポーネント インスタンスを取得すると、デフォルトでは取得できないサブコンポーネントのプロパティとメソッドを操作できます。外の世界にさらされる
親コンポーネント:
<template>
<div class="box">
<h1>我是父组件:{
{money}}</h1>
<button @click="handler">找我的儿子借10元</button>
<Son ref="son"></Son>
</div>
</template>
<script setup lang="ts">
//ref:可以获取真实的DOM节点,可以获取到子组件实例VC
//$parent:可以在子组件内部获取到父组件的实例
//引入子组件
import Son from './Son.vue'
import { ref } from 'vue'
//父组件钱数
let money = ref(100000000)
//获取子组件的实例
let son = ref()
//父组件内部按钮点击回调
const handler = () => {
console.log(son.value)//打印子组件的实例对象
money.value += 10
//儿子钱数减去10
son.value.money -= 10
son.value.fly()
}
})
サブアセンブリ:
<template>
<div class="son">
<h3>我是子组件:{
{money}}</h3>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
//儿子钱数
let money = ref(666)
const fly = () => {
console.log('我可以飞')
}
//组件内部数据对外关闭的,别人不能访问
//如果想让外部访问需要通过defineExpose方法对外暴露
defineExpose({
money,
fly
})
</script>
子コンポーネントのインスタンス オブジェクト:
$parent は親コンポーネントのインスタンス オブジェクトを取得します
$parent: 親コンポーネントのインスタンスは子コンポーネント内で取得できます。
親コンポーネントは子コンポーネントを配置するだけで済みます。
<Dau></Dau>
<script setup lang="ts">
//$parent:可以在子组件内部获取到父组件的实例
//引入子组件
import Dau from './Daughter.vue'
import { ref } from 'vue'
//父组件钱数
let money = ref(100000000)
//对外暴露
defineExpose({
money
)}
</script>
子コンポーネントで、$parent を使用して親コンポーネントのインスタンス オブジェクトを取得します。もちろん、子コンポーネントがインスタンス オブジェクトを取得できるように、親コンポーネントも外部に公開する必要があります
<template>
<div class="dau">
<h1>我是子组件{
{money}}</h1>
<button @click="handler($parent)">点击我父组件给我10000元</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
//子组件钱数
let money = ref(999999)
//子组件按钮点击回调
const handler = ($parent: any) => {
console.log($parent)
money.value += 10000
$parent.money -= 10000
}
</script>
クリック イベントを使用して $parent を挿入し、父親のインスタンス オブジェクトを取得します
7.provide-injectで世代間伝達が可能
親コンポーネント: Provide を使用して対応するデータを送信し、キーを提供します。後続のサブコンポーネントもこのキーを使用してデータを取得します
<template>
<div class="box">
<h1>Provide与Inject{
{car}}</h1>
<hr />
<Child></Child>
</div>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
//vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
import { ref, provide } from "vue";
let car = ref("法拉利");
//祖先组件给后代组件提供数据
//两个参数:第一个参数就是提供的数据key
//第二个参数:祖先组件提供数据
provide("TOKEN", car);
</script>
サブコンポーネント: inject と対応するキーを使用して、対応するデータを取得します。
<template>
<div class="child">
<h1>我是子组件1{
{ car }}</h1>
<Child></Child>
</div>
</template>
<script setup lang="ts">
import Child from './GrandChild.vue'
import { inject } from 'vue'
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('TOKEN')
</script>
孫コンポーネント: データは変更可能であり、すべてのコンポーネント データは同期されます。
<template>
<div class="child1">
<h1>孙子组件</h1>
<p>{
{car}}</p>
<button @click="updateCar">更新数据</button>
</div>
</template>
<script setup lang="ts">
import {inject} from 'vue';
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('TOKEN');
const updateCar = ()=>{
car.value = '自行车';
}
</script>
8. パイナップル
Vuex と比較して、Ponia はより簡潔で直接的な API を提供し、結合されたスタイル API を提供します。そして最も重要なことは、TypeScript を使用する際に、より完全な型推論を提供することです。
これが、vue が状態集中管理ツールを公式に推奨する理由でもあります。
pinia を使用する場合は依存関係をインストールする必要があります
npm i pinia
pinia は vue2 と vue3 をサポートしているので、組み合わせと選択の 2 つの書き方があります
1. 新しいウェアハウス ファイル ストアを作成して、大規模な Index.ts ウェアハウスを作成します
//创建大仓库
import { createPinia } from 'pinia';
//createPinia方法可以用于创建大仓库
let store = createPinia();
//对外暴露,安装仓库
export default store;
2. mian.jsでの参照
//引入仓库
import store from './store'
//使用
app.use(store)
選択的 API:
状態はデータを保存します
アクションの実装方法(途中でデータを変更可能)
ゲッターが計算したプロパティ
//定义info小仓库
import { defineStore } from "pinia";
//第一个仓库:小仓库名字 第二个参数:小仓库配置对象
//defineStore方法执行会返回一个函数,函数作用就是让组件可以获取到仓库数据
let useInfoStore = defineStore("info", {
//存储数据:state
state: () => {
return {
count: 99,
arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
},
actions: {
//注意:函数没有context上下文对象
//没有commit、没有mutations去修改数据
updateNum(a: number, b: number) {
this.count += a;
}
},
getters: {
}
});
//对外暴露方法
export default useInfoStore;
コンポーネントでのピニアデータの使用
<template>
<div class="child">
<h1>{
{ infoStore.count }}---{
{infoStore.total}}</h1>
<button @click="updateCount">点击我修改仓库数据</button>
</div>
</template>
<script setup lang="ts">
import useInfoStore from "../../store/modules/info";
//获取小仓库对象
let infoStore = useInfoStore();
console.log(infoStore);
//修改数据方法
const updateCount = () => {
//仓库调用自身的方法去修改仓库的数据
infoStore.updateNum(66,77);
};
</script>
構成 API:
//定义组合式API仓库
import { defineStore } from "pinia";
import { ref, computed } from 'vue';
//创建小仓库
let useTodoStore = defineStore('todo', () => {
let arr = ref([1,2,3,4,5]);
const total = computed(() => {
return arr.value.reduce((prev, next) => {
return prev + next;
}, 0)
})
function updateTodo() {
arr.value.push(0)
}
//务必要返回一个对象:属性与方法可以提供给组件使用
return {
arr,
total,
updateTodo
}
});
export default useTodoStore;
コンポーネントでは以下を使用します。
<template>
<div class="child1">
<p @click="updateTodo">{
{ todoStore.arr }}</p>
</div>
</template>
<script setup lang="ts">
//引入组合式API函数仓库
import useTodoStore from "../../store/modules/todo";
let todoStore = useTodoStore();
//点击p段落去修改仓库的数据
const updateTodo = () => {
todoStore.updateTodo();
};
</script>