Vue的几种通信方式,今天这里做点笔记,源码使用的是非构建版的代码
1、父子组件之间通信
父组件通过props
的方式向子组件传递数据
<div id="app">
{{msg}}
<component-p :text="text"/>
</div>
const componentParent = {
template:`<h2>我是组件A---{{text}}</h2>`,
props:['text'],
data(){
return{
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
}
})
2、子组件与父组件通信
通过$emit
子组件可以向父组件通信。
<div id="app">
{{msg}}
<component-p :text="text" @changedtext="changedtext2"/>
</div>
const componentParent = {
template:`<h2 @click='changedText'>我是组件A---{{text}}</h2>`,
props:['text'],
data(){
return{
}
},
methods:{
changedText(){
this.$emit('changedtext')
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
},
methods:{
changedtext2(){
this.text = "我是被子组件修改了...."
}
}
})
触发的时候还可以传递参数
<div id="app">
{{msg}}
<component-p :text="text" @changedtext="changedtext2('参数测试22')"/>
</div>
const componentParent = {
template:`<h2 @click='changedText'>我是组件A---{{text}}</h2>`,
props:['text'],
data(){
return{
}
},
methods:{
changedText(value){
this.$emit('changedtext',value)
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
},
methods:{
changedtext2(value){
this.text = "我是被子组件修改了...."+value
}
}
})
3、通过$parent
和$children
就可以访问组件的实例
拿到实例代表什么?代表可以访问此组件的所有方法和data
。接下来就是怎么实现拿到指定组件的实例。
子组件通过this.$parent.attr 直接到父组件的属性,通过计算属性,赋值给子组件
<div id="app">
{{msg}}
<component-p />
</div>
const componentParent = {
template:`<h2>我是组件A---{{text}}</h2>`,
data(){
return{
}
},
computed: {
text() {
return this.$parent.text;
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
}
})
子组件触发父组件的事件:
const componentParent = {
template:`<h2 @click='clickHandle'>我是组件A---{{text}}</h2>`,
data(){
return{
}
},
computed: {
text() {
return this.$parent.text;
}
},
methods:{
clickHandle(){
this.$parent.showSomething();
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
},
methods:{
showSomething(){
console.log('我是父组件的时间被触发啊')
}
}
})
上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。
四、provide
/ reject vue
2.2.0 新增
具体的解释:https://cn.vuejs.org/v2/api/#provide-inject
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。
父组件provide一个对象,里面包含要让子组件接收的属性
new Vue({
el:"#app",
provide:{
slogon:'hello world'
},
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
}
})
子组件注入相应的属性
const componentParent = {
template:`<h2>我是组件A---{{text}}</h2>`,
inject:['slogon'],
data(){
return{
}
},
computed:{
text(){
return this.slogon;
}
}
}
以上是父子组件的,两个层级,现在我们再测试下父子孙的三层数据provide和eject
const componentSon = {
template:`<h2>我是组件Son---{{text}}</h2>`,
inject:['slogon'],
computed:{
text(){
return this.slogon;
}
}
}
const componentParent = {
template:`<div>
<h2>我是组件A---{{text}}</h2>
<component-s />
</div>`,
inject:['slogon'],
data(){
return{
}
},
components:{
'component-s': componentSon
},
computed:{
text(){
return this.slogon;
}
}
}
new Vue({
el:"#app",
provide:{
slogon:'hello world'
},
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
}
})
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref
特性为这个子组件赋予一个 ID 引用。
<div id="app">
{{msg}}
<component-p />
</div>
const componentParent = {
template:`<h2 ref="compS" @click="clickHanlde">我是组件A--</h2>`,
data(){
return{
name:'我是父组件内的内容'
}
},
methods:{
clickHanlde(){
console.log(123)
console.log(this.$refs.compS)
this.$refs.compS.style.background = "red"
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是一个app",
text:"我是父组件的内容"
},
components:{
'component-p':componentParent
},
methods:{
}
})
当ref挂在到子组件上是,获取到的就是子组件实例,因此可以拿到子组件的属性方法
<div id="app">
<component-a />
</div>
var componnetB = {
template: `<div><h2>我是组件B</h2></div>`,
data() {
return {
name: 'hello world'
}
}
}
var componentA = {
template: `<div><h2 @click="showSon">我是组件A</h2><component-b ref="comB"/></div>`,
components: {
'component-b': componnetB
},
methods: {
showSon() {
console.log('showSon')
console.log(this.$refs.comB.name)
}
}
}
new Vue({
el: "#app",
data: {
test: 'hello world'
},
components: {
'component-a': componentA
}
})
五、兄弟组件间的通信 bus
创建一个事件bus
参考地址https://cn.vuejs.org/v2/guide/migration.html#dispatch-%E5%92%8C-broadcast-%E6%9B%BF%E6%8D%A2
var bus = new Vue()
下面我们就来两个兄弟组件试试
var componnetB = {
template: `<div>
<h2 >我是组件B</h2>
{{count}}
</div>`,
data() {
return {
name: 'hello world_B',
count: 0
}
},
mounted() {
//监听兄弟组件的触发,在组件被挂在的时候进行监听
var self = this;
eventHub.$on('add', function () { //此处有个坑,要改变this指向
console.log(222)
self.count++;
})
/* eventHub.$on('add', () => { //此处有个坑,要使用箭头函数
console.log(222)
this.count++;
}) */
},
methods: {
/* additionHandle() {
this.data++;
} */
}
}
var componnetC = {
template: `<div><h2 @click="additionHandle">我是组件C</h2></div>`,
data() {
return {
name: 'hello world_C'
}
},
methods: {
additionHandle() {
eventHub.$emit('add') //触发兄弟组件的事件
}
}
}
var componentA = {
template: `<div>
<h2 @click="showSon">我是组件A</h2>
<component-b />
<component-c />
</div>`,
components: {
'component-b': componnetB,
'component-c': componnetC
},
methods: {
showSon() {
console.log('showSon')
console.log(this.$refs.comB.name)
}
}
}
new Vue({
el: "#app",
data: {
test: 'hello world'
},
components: {
'component-a': componentA
}
})
移除事件监听
eventHub.$off('add', {})
6.vuex介绍此处略,会有专门的来记录这个
7.localStorage
/ sessionStorage
这里是数据化的处理方式,不仔细说了,有相应的api,进行存取值
8.$attrs
与 $listeners
https://cn.vuejs.org/v2/api/#vm-attrs
接下来我们实战,情景是A>>>>B>>>>C,父,子,孙的层级关系
<div id="app">
<component-a :name="name" :age="age" sex="中性a" color="golderna" />
</div>
总结一:子组件需要父组件的data,必须要一层一层的绑定v-bind='$attrs',组件D在组件C中使用的时候未进行绑定,打印出的是{}对象
总结二:color属性是通过props传递,默认的是不显示在$attrs中,
var componnetD = {
template: `<div><h2>我是组件D</h2></div>`,
data() {
return {
name: 'hello world_D'
}
},
mounted() {
console.log(this.$attrs, 'D')
},
inheritAttrs: false,
methods: {}
}
var componnetC = {
template: `<div>
<h2>我是组件C</h2>
<componnet-d />
</div>`,
data() {
return {
name: 'hello world_C'
}
},
mounted() {
console.log(this.$attrs, 'C')
},
inheritAttrs: false,
components: {
'componnet-d': componnetD
},
methods: {}
}
var componnetB = {
template: `<div>
<h2 >我是组件B</h2>
<component-c v-bind="$attrs"/>
</div>`,
data() {
return {
name: 'hello world_B',
count: 0
}
},
mounted() {
console.log(this.$attrs, 'B')
},
components: {
'component-c': componnetC,
}
}
var componentA = {
template: `<div>
<h2>我是组件A</h2>
<p>{{$attrs}}</p>
<component-b v-bind="$attrs"/>
</div>`,
props: ['color'],
components: {
'component-b': componnetB,
},
methods: {
}
}
new Vue({
el: "#app",
data: {
test: 'hello world',
name: 'my name',
age: '100'
},
components: {
'component-a': componentA
}
})