react都这么无情了,vue还是那么有义,4种父子组件数据双向传递大法

11,189 阅读4分钟

原本想放张老尤的照片的,烧三根香膜拜一下的,可惜图片和不上去,在前端这么mmp的时代,天天有那么多B事,在数据驱动的时候,大家都推崇数据的走向都是单向数据流,都是通过父组件去向子组件传递数据,还是那句话,那来这么多B事,只要注意点就可以了,合理的运用双向绑定,无论对业务和组件开发来说,都是一件双赢的事,装B可以,但是不能过份!

好了,讲重点,今天我就给大家讲讲VUE四种数据双向传递有那些用法

一.通过$on , $emit 来进行双向通信

使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件

这种用法,其实是我接下来三种用法的根基

先来说说$on 是用来干麻的,是用来监听的事件的,就是监听$emit里(eventName)事件的,一量$emit触发事件,则$on会接收到,则执行函数事件

那我们基本数据单向传递我们都用props来进行传递,那一旦子组件想改变props传过来的数据,我们是不能直接改变Props里的数据,我们还是要改变父组件的数据,用$on和$emit是如何实现的呢

children组件

<template lang="pug">
  .demo
    .demo-example(@click="changePropsValue") {{msg}}
</template>


<script>
export default {
  props: ['msg'],
  methods: {
    changePropsValue () {
      this.$emit('changeMsg', '通过$emit触发事件了')
    }
  }
}
</script>

1.msg是通过父组件传递过来的,我们先前可肯定要在props里声明好
2.在点击的时候,我们触发了changeMsg事件,第二个参数是,你想要传到父组件的参数

parent组件

<template lang="pug">
  div
    demo(:msg="msg" v-on:changeMsg='onChange')
</template>

<script>
import Demo from './demo.vue'
export default {
  data () {
    return {
      msg: '首次数据传递'
    }
  },
  components: {
    Demo
  },
  methods: {
    onChange (msg) {
      this.msg = msg
    }
  }
}
</script>

我们随后把demo引入,传入子组件的msg我们事先在data数据里面定义好,同时在demo组件上进行一个$on的监听
1.$on :(冒号)后面跟的第一个值是$emit触发的事件,也是$on所要监听的事件,一量$emit有触发,则马上执行了onChange函数,但本质上vue还是单向数据流的,虽然props不能改变,但是data里的数据是可以进行改变的,一但data的数据和子组件有传递关系,一旦父data数据有变动,子组件props所对应的数据则同时跟着变动

二.通过 v-model 来进行双父子通信

在vue进入到2.0的时候,取消了.sync的功能,导致了一堆组件库大动脑子,基本都用了v-model去进行双向绑定,本质上v-model适用场景是用在表单上面的,但是既然可以自定义了,那就有它的灵活性

官方说法:

自定义事件可以用来创建自定义的表单输入组件,使用 v-model 来进行数据双向绑定。看看这个:input v-model="something"

那语法糖则是这样的

input
v-bind:value="something"
v-on:input="something = $event.target.value"

这说明了

1.v-model里的something这个变量值在语法糖里代表的是value值,在表单上我们可以看作是input的value值,那在其它标签可以看成一个将要传入的Props数据,那唯一不可变的是这个props的Key必须是value
2.v-on:input="something = $event.target.value"
其实v-model内置也是通过$on和$emit来进行传递的,进行了input输入事件的监听,然后拿到事件上$event.target.value最新的改变something

现在老版本的组件库,当2.0取消.sync的时候,自定义组件的时候,如何巧用v-model来进行双向通信

children组件

<template lang="pug">
  .demo
    .demo-example(@click="changePropsValue") {{value}}
</template>


<script>
export default {
  props: ['value'],
  methods: {
    changePropsValue () {
      this.$emit('input', '通过$emit触发input事件了')
    }
  }
}
</script>

1.这里的value前面说过了就是v-model传过来的value ( v-bind:value="something"),但是只能用value去接收
2.这里主要巧用了一点,平时我们改变input输入框的时候,input事件是自己主动触发的,但是,我们也同时可以给他手动触发,我们用$emit进行了手动触发(input)事件

parent组件

<template lang="pug">
  div
    demo(v-model ='msg')
</template>

<script>
import Demo from './demo.vue'
export default {
  data () {
    return {
      msg: '首次数据传递'
    }
  },
  components: {
    Demo
  }
}
</script>

这个我们直接用v-model像表单那样绑定就直接可以进行父子组件双向绑定了。在v-model的语法糖里封装了v-on:input 去进行监听事件

3.在2.3回归的特性.sync

回归的.sync与1.0版本的写法有所改变,改来改去,不离其实中,还是要通过$emit去显式地触发一个更新事件;

但是相比v-model来说语法上更加直观,更加简洁,毕镜v-model是主要给表单进行又向绑定适用的

如果再进一步往底层说,.sync还是进行了$on进行了监听封装,跟v-model一样也同样是一种语法糖

children组件

<template lang="pug">
  .demo
    .demo-example(@click="changePropsValue") {{msg}}
</template>


<script>
export default {
  props: ['msg'],
  methods: {
    changePropsValue () {
      this.$emit('update:msg', '通过$emit显示触发了更新事件')
    }
  }
}
</script>

1.通过props来进行msg的数据接收
2.通过$emit来进行触发,第一个参数则是显示触发,update:msg (msg)则是你需要改变的props里从父组件里接收的值,第二个参数,还是你要更新的值,从语意上设计的也很有感觉,有木有

parent

<template lang="pug">
  div
    demo(:msg.sync="msg")
</template>

<script>
import Demo from './demo.vue'
export default {
  data () {
    return {
      msg: '首次数据传递'
    }
  },
  components: {
    Demo
  }
}
</script>

主要看demo(:msg.sync="msg") 这里直接在向子组件传递的时候还是像1.0的时候加一个.sync,本质上还是它会被扩展为一个自动更新父组件属性的 v-on 侦听器
(推荐用法,一般对一个模态框进行封装的时候很有用,有了.sync不建议用v-model)

4.$parent用法

这在一些显示操作的时候,向外部暴露props和event的时候是不推荐用的,那有人要问了?parent什么时候用呢,在一些自己内部逻辑操用的时候可以用一下,不用很繁琐的来进行双向来回导,节省代码和逻辑,有时候也可以让人一目了然

children组件

<template lang="pug">
  .demo
    .demo-example(@click="changePropsValue") 点击按钮
</template>


<script>
export default {
  methods: {
    changePropsValue () {
      this.$parent.msg = '通过$parent显改变了更新事件'
    }
  }
}
</script>

1.子组件,通过点击按钮,显示的改变了父组件的parent.msg里面的数据

parent

<template lang="pug">
  div
    demo
    p {{msg}}
</template>

<script>
import Demo from './demo.vue'
export default {
  data () {
    return {
      msg: '第一次写入数据'
    }
  },
  components: {
    Demo
  }
}
</script>

在这种四种方法里,我还是推荐用.sync来进行双向通信,一量旦通信机制深了,组件的嵌到超过3层的话,我还是建议用vuex来进行数据的共享,不然一层一层传,再一层一层的向上导,到最后你页面会把控不住,业务代码也就不直观了