Vue父子组件通信和双向绑定

2019-07-29  本文已影响0人  Wermdany

本篇文章主要介绍父子组件传值,组件的数据双向绑定。

1. 基础父子组件传值

父子组件传值,这是Vue组件传值最常见,最基础的传值方法。
父组件向子组件传值使用Props,子组件定义期望接收传值的名字、类型、默认值等等,父组件Props值的改变会自动同步到子组件。
子组件向父组件传值使用事件触发,即使用$emit注册事件,在父组件触发,这个事件可以携带值,而且一个事件的触发本身就是在传递信息。
代码实现:

//父组件
<template>
  <div id="parent">
  父组件的text:{{text}}
    <Child :text="text" @changeText="prentEvent"></Child>
  </div>
</template>
<script>
export default {
  components: {
    Child: () => import('@/components/Child')
   },
  data() {
    return {
      text: 'a'
    }
  },
  methods: {
    prentEvent(value) {
      this.text = value
    },
}
</script>
//子组件
<template>
  <div class="child">
    <p>子组件text:{{text}}</p>
    <button @click="changeParent">改变父组件text</button>
  </div>
</template> 
<script>
export default {
  name: 'Child',
  props: {
    text: {
      type: String,
      required: true
    }
  },
  data() {
    return {}
  },
  methods: {
    changeParent() {
      this.$emit('changeText', 'b')
    },
  },
}
</script>
1.gif

由于父组件的Props改变会自动传递到子组件,所以会同步变化。

2. 父子组件传值的双向绑定

上述例子有点双向绑定的意思,但这并不是双向绑定,Vue的数据都是单向流动的,而且Vue中从来就没有任何的双向绑定,那些双向绑定只是语法糖而已
我们都知道v-model可以用在 input标签上,实现双向绑定,其实Vue已经把input标签进行了修改,也就是 input标签已经是一个Vue的内置组件了,同样的内置组件还有很多,比如,用于缓存的keep-alive,用于路由链接的router-like,用于路由视图展示的router-view等等。
实现一个自定组件的v-model之前,我们先实现一个双向绑定,代码如下:

//Com1
<template>
  <div class="com1">
    Com1:
    <input type="text" :value="value" @input="changeSelf" />
    <Com2 :value="value" @input="changes"></Com2>
  </div>
</template>
<script>
export default {
  name: 'Com1',
  components: {
    Com2: () => import('./Com2')
  },
  data() {
    return {
      value: ''
    }
  },
  methods: {
    changes(values) {
      this.value = values
    },
    changeSelf(e) {
      this.value = e.target.value;
    },
  },
}
</script>
//Com2
<template>
  <div class="com2">
    Com2:
    <input type="text" :value="value" @input="Com2Input" />
  </div>
</template>
<script>
export default {
  name: 'Com2',
  props: {
    value: {
      type: String,
      required: true,
    }
  },
  methods: {
    Com2Input(e) {
      this.$emit('input', e.target.value)
    }
  },
}
</script>
2.gif
我们没用Vue的v-model同样可以实现数据的双向绑定。我们如何改造成v-model呢?只能改变父组件Com1,子组件不能更改,代码如下:
//Com1
<template>
  <div class="com1">
    Com1:
    <!--下面这行改变是为了精简代码,使用input标签的v-model--!>
    <!-- <input type="text" :value="value" @input="changeSelf" /> -->
    <input type="text" v-model="value" />
    <!-- <Com2 :value="value" @input="changes"></Com2> -->
    <Com2 v-model="value"></Com2>
  </div>
</template>
<script>
export default {
  name: 'Com1',
  components: {
    Com2: () => import('./Com2')
  },
  data() {
    return {
      value: ''
    }
  },
  methods: {
    // changes(values) {
    //   this.value = values
    // },
    // changeSelf(e) {
    //   this.value = e.target.value;
    // },
  },
}
</script>
3.gif

由此我们实现了Com2这个组件的v-model,改变的是取消了Com2的事件监听@input,Propsvalue,换来了v-model,这个简化的过程就是语法糖。v-model会自动处理那些注释掉的操作,即v-model会自动处理一个组件的input事件和valueProps,让两者绑定。
input的v-model已经实现,我们来说一说自定义组件的v-model,v-model会检测组件的input事件和valueProps,这显然是不行的,自定义组件需要的不一定是这两个东西,幸好子组件里还有一个属性mode,可以用来改变v-model默认监听的Props和event,代码如下:

export default {
  name: 'Com2',
  model: {
    //默认监听的事件和prop
    // event: 'input',
    // prop: 'value',
    //自定义的监听子组件触发事件和传进去的prop
    event: 'change',
    prop: 'datas'
  },
  //其他代码
}

这时在父组件使用子组件的时候,在子组件使用v-model就会自动处理change事件和datasProps,这样就可以随意定义想要的双向绑定属性了,但是一个组件只能有一个v-model
在Vue 2.3.0 中加入了.sync 修饰符,也是用来处理双向绑定的,封装流程和v-model类似,在子组件需要这样操作,代码如下:

//在需注册事件的地方这样写
this.$emit('update:datas', newDatas)
//在父组件调用这个子组件的时候这样写
<Com3
  v-bind:datas="datas"
  v-on:update:datas="datas = $event"
></Com3>
//使用.sync 修饰符简化为
<Com3 :datas.sync="datas"></Com3>
//子组件的事件注册不改动

这样同样可以实现双向绑定,一个组件可以有多个.sync修饰符双向绑定。

上一篇下一篇

猜你喜欢

热点阅读