绝大部分
vue本身提供的通信方式,都是父子组件通信
prop#最常见的组件通信方式之一,由父组件传递到子组件
event#最常见的组件通信方式之一,当子组件发生了某些事,可以通过event通知父组件
style和class#父组件可以向子组件传递style和class,它们会合并到子组件的根元素中
示例
父组件
1<template>
2 <div id="app">
3 <HelloWorld
4 style="color:red"
5 class="hello"
6 msg="Welcome to Your Vue.js App"
7 />
8 </div>
9</template>
10
11<script>
12import HelloWorld from "./components/HelloWorld.vue";
13
14export default {
15 components: {
16 HelloWorld,
17 },
18};
19</script>子组件
1<template>
2 <div class="world" style="text-align:center">
3 <h1>{{ msg }}</h1>
4 </div>
5</template>
6
7<script>
8export default {
9 name: "HelloWorld",
10 props: {
11 msg: String,
12 },
13};
14</script>渲染结果:
1<div id="app">
2 <div class="hello world" style="color:red; text-aling:center">
3 <h1>Welcome to Your Vue.js App</h1>
4 </div>
5</div>attribute#如果父组件传递了一些属性到子组件,但子组件并没有声明这些属性,则它们称之为attribute,这些属性会直接附着在子组件的根元素上
不包括
style和class,它们会被特殊处理
示例
父组件
1<template>
2 <div id="app">
3 <!-- 除 msg(声明过的) 外,其他均为 attribute -->
4 <HelloWorld data-a="1" data-b="2" msg="Welcome to Your Vue.js App" />
5 </div>
6</template>
7
8<script>
9import HelloWorld from "./components/HelloWorld.vue";
10
11export default {
12 components: {
13 HelloWorld,
14 },
15};
16</script>子组件
1<template>
2 <div>
3 <h1>{{ msg }}</h1>
4 </div>
5</template>
6
7<script>
8export default {
9 name: "HelloWorld",
10 props: {
11 msg: String,
12 },
13 created() {
14 console.log(this.$attrs); // 得到: { "data-a": "1", "data-b": "2" }
15 },
16};
17</script>渲染结果:
1<div id="app">
2 <div data-a="1" data-b="2">
3 <h1>Welcome to Your Vue.js App</h1>
4 </div>
5</div>子组件可以通过inheritAttrs: false配置,禁止将attribute附着在子组件的根元素上,但不影响通过$attrs获取
natvie修饰符#在注册事件时,父组件可以使用native修饰符,将事件注册到子组件的根元素上
示例
父组件
1<template>
2 <div id="app">
3 <HelloWorld @click.native="handleClick" />
4 </div>
5</template>
6
7<script>
8import HelloWorld from "./components/HelloWorld.vue";
9
10export default {
11 components: {
12 HelloWorld,
13 },
14 methods: {
15 handleClick() {
16 console.log(1);
17 },
18 },
19};
20</script>子组件
1<template>
2 <div>
3 <h1>Hello World</h1>
4 </div>
5</template>渲染结果
1<div id="app">
2 <!-- 点击该 div,会输出 1 -->
3 <div>
4 <h1>Hello World</h1>
5 </div>
6</div>$listeners#子组件可以通过$listeners获取父组件传递过来的所有事件处理函数
v-model#sync修饰符#和v-model的作用类似,用于双向绑定,不同点在于v-model只能针对一个数据进行双向绑定,而sync修饰符没有限制
实现原理
1<input v-model="loginId" />
2// 相当于
3<input :value="loginId" @input="loginId = $event.target.value" />示例
子组件
1<template>
2 <div>
3 <p>
4 <button @click="$emit(`update:num1`, num1 - 1)">-</button>
5 {{ num1 }}
6 <button @click="$emit(`update:num1`, num1 + 1)">+</button>
7 </p>
8 <p>
9 <button @click="$emit(`update:num2`, num2 - 1)">-</button>
10 {{ num2 }}
11 <button @click="$emit(`update:num2`, num2 + 1)">+</button>
12 </p>
13 </div>
14</template>
15
16<script>
17export default {
18 props: ["num1", "num2"], //父组件的东西,自己不能改
19};
20</script>sync并没有改变这种模式,只是语法糖
父组件
1<template>
2 <div id="app">
3 <Numbers :num1.sync="n1" :num2.sync="n2" />
4 <!-- 等同于 -->
5 <Numbers :num1="n1" @update:num1="n1 = $event"//将传过来的$event赋值给n1
6 :num2="n2" @update:num2="n2 = $event" />
7 </div>
8</template>
9<script>
10import Numbers from "./components/Numbers.vue";
11
12export default {
13 components: {
14 Numbers,
15 },
16 data() {
17 return {
18 n1: 0,
19 n2: 0,
20 };
21 },
22};
23</script>$parent和$children#在组件内部,可以通过$parent和$children属性,分别得到当前组件的父组件和子组件实例
$slots和$scopedSlots#详见 TODO
ref#父组件可以通过ref获取到子组件的实例
Provide提供和Inject获取#示例
1// 父级组件提供 'foo'
2var Provider = {
3 provide: {
4 foo: "bar",
5 },
6 // ...
7};
8
9// 组件注入 'foo'
10var Child = {
11 inject: ["foo"], //我要拿到祖先组件提供的foo数据
12 created() {
13 console.log(this.foo); // => "bar"
14 },
15 // ...
16};router#如果一个组件改变了地址栏,所有监听地址栏的组件都会做出相应反应
最常见的场景就是通过点击router-link组件改变了地址,router-view组件就渲染其他内容
vuex#适用于大型项目的数据仓库
Pinia#您将喜欢使用的 Vue 存储库
store模式#适用于中小型项目的数据仓库
1// store.js
2const store = {
3 loginUser: ...,
4 setting: ...
5}
6// AB共同使用store
7// compA
8const compA = {
9 data(){
10 return {
11 loginUser: store.loginUser
12 }
13 }
14}
15
16// compB
17const compB = {
18 data(){
19 return {
20 setting: store.setting,
21 loginUser: store.loginUser
22 }
23 }
24}缺点:无法跟踪数据的变化,如果组件数变得复杂,任何组件都有权改动他,仓库数据出了问题,难以判断那个步骤出现问题。
eventbus#组件通知事件总线发生了某件事,事件总线通知其他监听该事件的所有组件运行某个函数
$emit和$listeners通信的异同#相同点:均可实现子组件向父组件传递消息
差异点:
$emit更加符合单向数据流,子组件仅发出通知,由父组件监听做出改变;而$listeners则是在子组件中直接使用了父组件的方法。- 调试工具可以监听到子组件
$emit的事件,但无法监听到$listeners中的方法调用。(想想为什么)- 由于
$listeners中可以获得传递过来的方法,因此调用方法可以得到其返回值。但$emit仅仅是向父组件发出通知,无法知晓父组件处理的结果