シリコンバレー選抜運営プラットフォーム
このプロジェクトの技術スタックには、vue3+TypeScript+vue-router+pinia+element-plus+axios+echarts などが含まれます。
アイテムの注文 | 住所 |
---|---|
Vue3コンポーネントの通信方法 | https://blog.csdn.net/m0_55644132/article/details/130711542 |
1. Vue3コンポーネントの通信方法
Vue2コンポーネントの通信方法:
props : 親子コンポーネント、子と親コンポーネント、さらには兄弟コンポーネント間でも通信可能
カスタム イベント: 子コンポーネントと親コンポーネント間の通信を実現できます。
グローバルイベントバス $bus : 任意のコンポーネント通信を実現可能
pubsub : 任意のコンポーネント通信用のパブリッシュ/サブスクライブ モード
vuex : 任意のコンポーネント通信を可能にする集中状態管理コンテナ
ref : 親コンポーネントは子コンポーネントのインスタンス VC を取得し、子コンポーネントの応答データとメソッドを取得します。
スロット: スロット (デフォルト スロット、名前付きスロット、スコープ付きスロット) は、親子コンポーネント通信を実現します...
1.1 小道具
props は親子コンポーネントの通信を実現するもので、vue3 ではdefineProps を通じて親コンポーネントから渡されたデータを取得することができます。また、コンポーネント内にdefinePropsメソッドを導入する必要はなく、直接使用できます。
親コンポーネントから子コンポーネントにデータを渡す
// 父组件中给子组件 Child 传数据--静态/动态数据
<Child info="我爱祖国" :money="money"></Child>
子コンポーネントは親コンポーネントから渡されたデータを取得します: 方法 1: オブジェクトの書き込み
let props = defineProps({
info:{
type:String,//接受的数据类型
default:'默认参数',//接受默认数据
},
money:{
type:Number,
default:0
}})
子コンポーネントは親コンポーネントから渡されたデータを取得します: 方法 2: 配列の書き込み
let props = defineProps(["info",'money']);
プロパティ データを取得した後、サブコンポーネントをテンプレートで使用できますが、プロパティは読み取り専用であることに注意してください(読み取りのみ可能で、変更はできません)。
1.2 カスタムイベント
Vue フレームワークには 2 種類のイベントがあります。1 つはネイティブ DOM イベントで、もう 1 つはカスタム イベントです。(vue2に.nativeを追加する必要があります)
ネイティブ DOM イベントにより、ユーザーはクリック、dbclick、change、mouseenter、mouseleave などの Web ページと対話できるようになります。
カスタム イベントは子コンポーネントを実装して親コンポーネントにデータを渡すことができます
1.2.1 ネイティブ DOM イベント
コードは以下のように表示されます。
<pre @click="handler">
我是祖国的老花骨朵
</pre>
現在のコード レベルでは、ネイティブ DOM イベントのクリック イベントは pre タグにバインドされ、デフォルトでイベント イベント オブジェクトがイベント コールバックに挿入されます。もちろん、クリックイベントに複数のパラメータを注入したい場合は、下図のように操作できます。ただし、挿入されたイベント オブジェクトは $event という名前にする必要があることに注意してください。
<div @click="handler1(1,2,3,$event)">我要传递多个参数</div>
vue3 フレームワークでは、クリック、dbclick、および変更 (ネイティブ DOM イベントなど) は、タグまたはカスタム タグ (コンポーネント タグ) のいずれであっても、ネイティブ DOM イベントです。
vue2 では、コンポーネント タグがネイティブ DOM イベントになるようにネイティブ修飾子を渡す必要があります。
1.2.2 カスタムイベント
カスタム イベントを使用すると、子コンポーネントが親コンポーネントにデータを渡すことができます。これはプロジェクトでより一般的に使用されます。
たとえば、カスタム イベントを親コンポーネント内の子コンポーネント (Event2) にバインドします。
<Event2 @xxx="handler3"></Event2>
Event2 サブコンポーネント内でこのカスタム イベントをトリガーします。
<template>
<div>
<h1>我是子组件2</h1>
<button @click="handler">点击我触发xxx自定义事件</button>
</div>
</template>
<script setup lang="ts">
let $emit = defineEmits(["xxx"]);
const handler = () => {
$emit("xxx", "法拉利", "茅台");
};
</script>
<style scoped>
</style>
script タグ内で、 defineEmitsメソッドが使用されていることがわかります。このメソッドは vue3 によって提供されており、直接導入して使用する必要はありません。defineEmits メソッドが実行され、配列が渡されます。配列要素は、コンポーネントが今後トリガーする必要があるカスタム イベントのタイプです。このメソッドは、カスタム イベントをトリガーするための $emit メソッドを返します。
ボタンがクリックされると、イベント コールバックは内部的に $emit メソッドを呼び出してカスタム イベントをトリガーします。最初のパラメーターはトリガー イベント タイプで、2 番目、3 番目、および N パラメーターは親コンポーネントに渡されるデータです。
注: コードは次のとおりです
<Event2 @xxx="handler3" @click="handler"></Event2>
注: @click を記述するコンポーネント ラベルはネイティブ DOM イベントであるべきであると言うのが通常ですが、サブコンポーネントがdefineEmits を通じて内部で定義されている場合、それはカスタム イベントになります。
let $emit = defineEmits(["xxx",'click']);
1.3 グローバルイベントバス
グローバルイベントバスは任意のコンポーネント通信を実現できますが、vue2ではVMとVCの関係に応じてグローバルイベントバスを起動することができます。ただし、vue3 には Vue コンストラクターがないため、Vue.prototype が存在せず、結合された API にもこれがないため、Vue3 でグローバル イベントのバス関数を実装するのは少し非現実的です。 Vue3 のイベント バス機能 これは、プラグイン mittを使用して実現できます。
ミット:公式サイトアドレス:https://www.npmjs.com/package/mitt
src/バス/index.ts
//引入mitt插件:mitt一个方法,方法执行会返回bus对象
import mitt from 'mitt';
const $bus = mitt();
export default $bus;
サブコンポーネント 1 で — データを受信します
import $bus from "../../bus";
//组合式API函数
import {
onMounted } from "vue";
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
//第一个参数:即为事件类型 第二个参数:即为事件回调
$bus.on("car", (car) => {
console.log(car);
});
サブコンポーネント 2 - データの送信 (ブラザー コンポーネント通信)
<button @click="handler">点击我给兄弟送一台法拉利</button>
//引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
$bus.emit('car',{
car:"法拉利"});
}
1.4 v モデル
v-modelコマンドはフォームデータの収集(データ双方向バインディング)が可能であり、親子コンポーネントのデータ同期も実現できます。
そして、v-model は実際には、props[modelValue] とカスタム イベント [update:modelValue] を使用した実現を指します。
以下のコードは、props (modelValue) をコンポーネント Child に渡し、カスタム イベント update:modelValue をバインドすることと同等です。
親子コンポーネントのデータ同期を実現
// 父组件中
<Child v-model="msg"></Child>
vue3 では、コンポーネントは複数の v-model を使用して、親コンポーネントと子コンポーネントの間で複数のデータを同期できます。以下のコードは、2 つのプロパティ、つまり pageNo と pageSize をコンポーネント Child に渡し、2 つのカスタム イベントをバインドすることと同等です。 -子データと更新:pageSize
<Child v-model:pageNo="msg" v-model:pageSize="msg1"></Child>
注: 子コンポーネントのパラメータが親コンポーネントで使用されていない場合、コールバック関数を準備する必要はなく (子コンポーネントは親コンポーネントにデータを渡す必要はありません)、子コンポーネントを直接トリガーできます。
そして、v-modelを使うと、親コンポーネントがコールバック関数を用意するのと同等になります(実際には書かれていません、受け取る際の子コンポーネントの名前はupdate:pageNoなど自分たちで決めます)、次に子コンポーネントに渡すと、子コンポーネントをトリガーできます (同等であることに注意してください)。
1.5 useAttrs
Vue3 では、useAttrs メソッドを使用してコンポーネントの属性とイベント (ネイティブ DOM イベントまたはカスタム イベントを含む) を取得できます。二次関数の機能はVue2 フレームワークの属性とメソッドに似ています$attrs
。$listeners
例: 親コンポーネント内で子コンポーネント my-button を使用します。
<my-button type="success" size="small" title='标题' @click="handler"></my-button>
コンポーネントの属性とイベントは、サブコンポーネント内の useAttrs メソッドを通じて取得できます。したがって、これは props に似ており、親コンポーネントによって渡されるプロパティとプロパティ値を受け入れることができることもわかりました。**defineProps が特定の属性を受け入れる場合、useAttrs メソッドによって返されるオブジェクトには対応する属性と属性値が含まれないことに注意してください。
// 子组件使用useAttrs接收父组件传的东西
<script setup lang="ts">
import {
useAttrs} from 'vue';
let $attrs = useAttrs();
</script>
useAttrs はボトムアップ操作です。props が受信されると、useAttrs はなくなります。小道具の方が優先度が高い
1.6 ref と $parent
ref というと、要素の DOM やサブコンポーネント インスタンスの VC を取得できると思われるかもしれません。子コンポーネントのインスタンス VC は親コンポーネント内の ref を通じて取得できるため、子コンポーネント内のメソッドと応答データは親コンポーネントで使用できます。
例: 親コンポーネントがマウントされた後にコンポーネント インスタンスを取得します。
親コンポーネントの内部コード:
<template>
<div>
<h1>ref与$parent</h1>
<Son ref="son"></Son>
</div>
</template>
<script setup lang="ts">
import Son from "./Son.vue";
import {
onMounted, ref } from "vue";
const son = ref();
onMounted(() => {
console.log(son.value);
});
</script>
ただし、親コンポーネントに子コンポーネントのデータまたはメソッドを取得させたい場合は、 defineExposeを通じてそれを外部に公開する必要があることに注意してください。これは、 vue3 のコンポーネント内のデータは外部に対して「閉じられている」ためです。外界にあるため、外部からアクセスすることはできません。(コンポーネント インスタンスは取得しますが、コンポーネント データは取得しません)
<script setup lang="ts">
import {
ref } from "vue";
//数据
let money = ref(1000);
//方法
const handler = ()=>{
}
defineExpose({
money,
handler
})
</script>
$parent は、特定のコンポーネントの親コンポーネント インスタンス VC を取得できるため、親コンポーネント内のデータとメソッドを使用できます。クリックされたときに親コンポーネントのインスタンスを取得するには、子コンポーネント内にボタンが必要です。もちろん、親コンポーネントのデータとメソッドは、defineExpose メソッドを通じて外部に公開する必要があります。
// 子组件中---注入$parent,必须叫这个;同时父组件的数据也要对外暴露
<button @click="handler($parent)">点击我获取父组件实例</button>
1.7 提供と注入
提供する[提供する]
注射する[注射]
Vue3 には、コンポーネント間のパラメータの受け渡しを実現できる、provide と inject の 2 つのメソッドが用意されています。祖先コンポーネントはデータを子孫コンポーネントに渡します。
祖先コンポーネントは以下のデータを提供します。
Provideメソッドはデータを提供するために使用されます。このメソッドは、それぞれデータ キーとデータ値を提供する 2 つのパラメーターを渡す必要があります。
<script setup lang="ts">
import {
provide} from 'vue'
provide('token','admin_token');// 后代都可以通过inject方法去使用这个数据
</script>
子孫コンポーネントは、injectメソッドを通じてデータを取得し、キーを通じて格納された値を取得できます。
<script setup lang="ts">
import {
inject} from 'vue'
let token = inject('token');
</script>
注: 子孫コンポーネントはデータを変更することができ、それに応じて祖先コンポーネントも変更されます。これがプロップとの違いの一つです
1.8ピニア
ピニア公式サイト:https://pinia.web3doc.top/
pinia も、vuex と同様に、集中管理状態コンテナーです。ただしコアコンセプトにはミューテーションやモジュールはなく、使用方法は公式サイトを参照
欠点: vuex と同様、保存されたデータは永続的ではありません。
piniaオプションAPIの記述方法
src/store/index.ts
//创建大仓库
import {
createPinia } from 'pinia';
//createPinia方法可以用于创建大仓库
let store = createPinia();
//对外暴露,安装仓库
export default store;
エントリファイル main.ts
//引入仓库
import store from './store'
app.use(store)
小さな倉庫を作る
src/store/modules/info.ts
//定义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: {
total() {
let result:any = this.arr.reduce((prev: number, next: number) => {
return prev + next;
}, 0);
return result;
}
}
});
//对外暴露方法
export default useInfoStore;
データを使用したいコンポーネント、子コンポーネント(他のコンポーネントも使用可能)
import useInfoStore from "../../store/modules/info";
//获取小仓库对象
let infoStore = useInfoStore();
// 使用
<h1>{
{
infoStore.count }}---{
{
infoStore.total}}</h1>
コンポーネント内のウェアハウス内のデータを直接変更するか、**$patch** を使用してウェアハウス内を変更するか、vuex と同様の書き込みメソッドを使用します (ウェアハウス データを変更するメソッドをアクション内に記述すると、コンポーネントはウェアハウスで変更メソッドを呼び出します)
注: この関数には、データを変更するためのコンテキスト オブジェクト、コミット、ミューテーションがありません。これを使用して変更します。
// 组件中
//1 直接修改
const updateCount = ()=> {
infoStore.count++;
}
//2 通过 仓库方法$patch 修改
const updateCount = ()=> {
infoStore.$patch({
count:1111;//新数据替换旧的
})
}
//3 actions中修改,组件中可以传参数过来的
updateNum(a: number, b: number) {
this.count += a;
}
倉庫でのゲッターの使用
getters: {
total() {
let result:any = this.arr.reduce((prev: number, next: number) => {
return prev + next;
}, 0);
return result;
}
}
pinia結合APIの書き方
//定义组合式API仓库
import {
defineStore } from "pinia";
import {
ref, computed,watch} from 'vue';
//创建小仓库,第二个参数是箭头函数
let useTodoStore = defineStore('todo', () => {
let todos = ref([{
id: 1, title: '吃饭' }, {
id: 2, title: '睡觉' }, {
id: 3, title: '打豆豆' }]);
let arr = ref([1,2,3,4,5]);
// 实现getters
const total = computed(() => {
return arr.value.reduce((prev, next) => {
return prev + next;
}, 0)
})
//务必要返回一个对象:属性与方法可以提供给组件使用
return {
todos,
arr,
total,
updateTodo() {
todos.value.push({
id: 4, title: '组合式API方法' });
}
}
});
export default useTodoStore;
結合された API のゲッターは、計算されたプロパティを通じて実装でき、Vue のモニタリングも使用できます。
1.9スロット
スロット: デフォルトのスロット、名前付きスロット、およびスコープ付きスロットは、親子コンポーネント通信を実現できます。
デフォルトのスロット:
サブコンポーネント内のテンプレートにスロット グローバル コンポーネント タグを書き込みます
// 子组件
<template>
<div>
<slot></slot>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
親コンポーネント内に構造を記述する: Todo は子コンポーネントです。親コンポーネント内で使用する場合は、二重タグ内に構造を記述して子コンポーネントに渡します。
プロジェクトを開発する場合、通常、デフォルトのスロットは 1 つだけであることに注意してください。
<Todo>
<h1>我是默认插槽填充的结构</h1>
</Todo>
名前付きスロット:
名前が示すように、この名前のスロットは、コンポーネント内に指定された名前の複数のスロットを残します。
以下はサブコンポーネント内にあり、テンプレートに 2 つのスロットが残ります。
<template>
<div>
<h1>todo</h1>
<slot name="a"></slot>
<slot name="b"></slot>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
親コンポーネントは、構造体を指定された名前付きスロットに内部的に渡します。v-slot: # に置き換えることができることに注意する必要があります。
<template>
<div>
<h1>slot</h1>
<Todo>
<template v-slot:a> //可以用#a替换
<div>填入组件A部分的结构</div>
</template>
<template v-slot:b>//可以用#b替换
<div>填入组件B部分的结构</div>
</template>
</Todo>
</div>
</template>
<script setup lang="ts">
import Todo from "./Todo.vue";
</script>
<style scoped>
</style>
スコープ付きスロット
スコープスロット: 子コンポーネントのデータは親コンポーネントによって提供されることがわかりますが、子コンポーネントの構造と外観(スタイル)は内部では決定できません
サブコンポーネントの Todo コードは次のとおりです。
<template>
<div>
<h1>todo</h1>
<ul>
<!--组件内部遍历数组-->
<li v-for="(item,index) in todos" :key="item.id">
<!--作用域插槽将数据回传给父组件-->
<slot :$row="item" :$index="index"></slot>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
defineProps(['todos']);//接受父组件传递过来的数据
</script>
<style scoped>
</style>
親コンポーネントの内部コードは次のとおりです。
<template>
<div>
<h1>slot</h1>
<Todo :todos="todos">
<template v-slot="{$row,$index}">
<!--父组件决定子组件的结构与外观-->
<span :style="{color:$row.done?'green':'red'}">{
{$row.title}}</span>
</template>
</Todo>
</div>
</template>
<script setup lang="ts">
import Todo from "./Todo.vue";
import {
ref } from "vue";
//父组件内部数据
let todos = ref([
{
id: 1, title: "吃饭", done: true },
{
id: 2, title: "睡觉", done: false },
{
id: 3, title: "打豆豆", done: true },
]);
</script>
<style scoped>
</style>