父子组件之间的通信
vue本身提供的大部分通信方式都是父子组件之间的
1. props
最常见的通信方式之一,父组件传递给子组件
2. event
最常见的通信方式之一,子组件内发生某些事件,通过event通知父组件
父组件 传递数据给子组件 触发子组件抛出的事件
<template>
<HelloWorld :num="n" @add="n = $event" @decrease="n = $event" />
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: { HelloWorld },
data() {
return {
n: 0,
};
},
};
</script>
子组件 通过props接收数据 通过event通知父组件触发事件
<template>
<div>
<button @click="decrease">-</button>
{{ num }}
<button @click="add">+</button>
</div>
</template>
<script>
export default {
name: 'Helloworld',
props: ['num'],
methods: {
add() {
this.$emit('add', this.num + 1);
},
decrease() {
this.$emit('decrease', this.num - 1);
},
},
};
</script>
3. $attribute
父组件向子组件传递一些特性,直接作用在子组件的根元素上,可以在子组件内通过设置inheritAttrs:false使其不作用在根元素。子组件内可以通过$attrs访问传递进来的值。
不包含style和class 这两个属性vue做了特殊处理。在子组件上加了这两个属性,则会直接将style或class的值与子组件根元素的style和class合并
父组件
<template>
<HelloWorld data-a="n1" data-b="n2" />
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: { HelloWorld },
};
</script>
子组件
<template>
<div>
<h1>$attribute</h1>
</div>
<!-- 最终元素会渲染为 -->
<!-- <div data-a="n1" data-b="n2"></div> -->
</template>
<script>
export default {
name: 'Helloworld',
// inheritAttrs: false,
mounted() {
console.log(this.$attrs);
},
};
</script>
4. $parent和$children
在组件内,可以通过这两个属性分别访问到其父组件和子组件的实例。
5. $listeners
该属性包含了父组件作用(不包含.native修饰符)在子组件上的事件,在子组件内通过$listeners可以触发父作用域的事件。
父组件
<template>
<HelloWorld :num="n" @add="add" />
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: { HelloWorld },
data() {
return {
n: 1,
};
},
methods: {
add(num) {
this.n = num;
},
},
};
</script>
子组件
<template>
<div>
{{ num }}
<button @click="$listeners.add(num + 1)">+</button>
</div>
</template>
<script>
export default {
name: 'Helloworld',
props: ['num'],
mounted() {
console.log(this.$listeners); // 可以访问到父作用域的事件
},
};
</script>
6. 一些其它可以影响子组件或访问子组件的方法
ref 用于访问真实dom元素或子组件实例
ref属性加到dom元素中(ref=[name]),便可以通过$refs.[name]访问该dom元素,添加到组件中,便可以通过$refs.[name]访问该组件的实例。
.native修饰符
在子组件上添加原生事件时并不会被监听。
用法:在事件名后加上.native(eventName.native=fn),相当于在子组件内部的根元素上注册了一个eventName事件。
.sync修饰符
该修饰符的作用与v-model类似,vue2中主要也是为了解决v-model只能作用与表单元素的缺陷。
父组件
<template>
<!-- <HelloWorld
:num1="n1"
:num2="n2"
@update:num1="n1 = $event"
@update:num2="n2 = $event"
/> -->
<!-- 相当于 -->
<HelloWorld :num1.sync="n1" :num2.sync="n2" />
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: { HelloWorld },
data() {
return {
n1: 1,
n2: 0,
};
},
methods: {},
};
</script>
子组件
<template>
<div>
<button @click="$emit('update:num1', num1 - 1)">+</button>
{{ num1 }}
<button @click="$emit('update:num1', num1 + 1)">+</button>
<button @click="$emit('update:num2', num2 - 1)">+</button>
{{ num2 }}
<button @click="$emit('update:num2', num2 + 1)">+</button>
</div>
</template>
<script>
export default {
name: 'Helloworld',
props: ['num1', 'num2'],
};
</script>
注:在父组件中使用sync修饰符时要注意的是:格式必须为x1.sync="data"。子组件中需要注意的是:通过event抛出的事件命名格式必须为xxx:x1。x1为子组件接收的prop的name值
7. Provide和Inject
这种通信方式不仅限于父子组件,可以进行根组件和子孙组件之间的通信,但不能进行兄弟组件之间的通信。
用法:根组件通过provide提供数据,后代组件通过inject按需注入依赖,必须是根组件provide提供的数据。
根组件 App
<template>
<h1>
我是app组件,是根组件
<HelloWorld />
</h1>
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: { HelloWorld },
provide: {
a: 1,
b: 2,
},
};
</script>
子组件HelloWorld
<template>
<div>
我是组件HelloWorld,是app组件的子组件
{{ a }}
<Test />
</div>
</template>
<script>
import Test from './test1';
export default {
name: 'Helloworld',
components: {
Test,
},
inject: ['a'],
};
</script>
孙子组件
<template>
<div>
我是组件test,是HelloWorld的子组件
{{ b }}
</div>
</template>
<script>
export default {
name: 'WorkspaceJsonTest',
inject: ['b'],
};
</script>
跨组件通信
主要都是通过第三方介入来实现跨组件之间的通信,如:router、vuex、store模式、eventbus 只对store模式作详细介绍
store模式:store模式主要是通过一个普通的js'模块,定义一个store数据仓库(非响应式),在任意一个组件内都可以访问仓库中的数据,将其作为data中的数据的入口,则该数据会变为响应式的。
只适用于中小型项目。在大型项目中无法直接改变仓库的数据,会导致数据改变难以被追踪。建议直接使用vuex。
store模块
export default {
userInfo: {
name: 'hh',
id: 1,
sex: 0,
age: 15,
},
};
根组件 App
<template>
<h1>
store中的userInfo:{{ user }}
<B />
<A />
</h1>
</template>
<script>
import A from './components/HelloWorld';
import B from './components/test1';
import store from './store';
export default {
name: 'App',
components: { A, B },
data() {
return {
user: store.userInfo,
};
},
};
</script>
组件A,App的子组件, B的兄弟组件
<template>
<div>store中的userInfo.age: {{ age }}</div>
</template>
<script>
import store from '../store';
export default {
name: 'A',
data() {
return {
age: store.userInfo.age,
};
},
};
</script>
组件B App的子组件, A的兄弟组件
<template>
<div>store中的userInfo.name:{{ name }}</div>
</template>
<script>
import store from '../store';
export default {
name: 'B',
data() {
return {
name: store.userInfo.name,
};
},
};
</script>
router: 如:组件改变地址栏状态,组件渲染不同的页面
vuex: 适用于大型项目。
eventbus:事件总线。两个组件a,b。a组件监听事件1,b组件抛出事件1,a组件执行相应的方法。
如有错误,欢迎评论指出。谢谢!