父组件使用 props 传递数据给子组件,子组件怎么跟父组件通信呢?这时,vue 的自定义事件就派上用场了。本文将详细介绍 Vue 自定义事件
每个 Vue 实例都实现了事件接口 (Events interface),即
- 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
[注意]Vue 的事件系统分离自浏览器的 EventTarget API。尽管它们的运行类似,但是
和
- $on
不是
- $emit
和
- addEventListener
的别名
- dispatchEvent
另外,父组件可以在使用子组件的地方直接用
来监听子组件触发的事件
- v-on
[注意] 不能用
侦听子组件抛出的事件,而必须在模板里直接用
- $on
绑定
- v-on
- <div id="example">
- <parent></parent>
- </div>
- <script>
- var childNode = {
- template: ` < button@click = "incrementCounter" > {
- {
- counter
- }
- } < /button>`,
- data(){
- return {
- counter: 0
- }
- },
- methods:{
- incrementCounter(){
- this.counter ++;
- this.$emit('increment');
- }
- },
- }
- var parentNode = {
- template: `
- <div class="parent">
- <p>{{total}}</p > <child@increment = "incrementTotal" > </child>
- <child @increment="incrementTotal"></child > </div>
- `,
- components: {
- 'child': childNode
- },
- data(){
- return {
- 'total':0
- }
- },
- methods:{
- incrementTotal(){
- this.total ++;
- }
- }
- };
- / / 创建根实例new Vue({
- el: '#example',
- components: {
- 'parent': parentNode
- }
- })
- </script>
自定义事件的命名约定与组件注册及 props 的命名约定都不相同,由于自定义事件实质上也是属于 html 的属性,所以其在 HTML 模板中,最好使用中划线形式
- <child @pass-data="getData"></child>
而子组件中触发事件时,同样使用中划线形式
- this.$emit('pass-data', this.childMsg)
子组件通过 $emit 可以触发事件,第一个参数为要触发的事件,第二个事件为要传递的数据
- this.$emit('pass-data', this.childMsg)
父组件通过 $on 监听事件,事件处理函数的参数则为接收的数据
- getData(value) {
- this.msg = value;
- }
- <div id="example">
- <parent></parent>
- </div>
- <script>
- var childNode = {
- template: ` < div class = "child" > <div > <span > 子组件数据 < /span>
- <input v-model="childMsg" @input="data">
- </div > <p > {
- {
- childMsg
- }
- } < /p>
- </div > `,
- data() {
- return {
- childMsg: ''
- }
- },
- methods: {
- data() {
- this.$emit('pass-data', this.childMsg)
- }
- }
- }
- var parentNode = {
- template: ` < div class = "parent" > <div > <span > 父组件数据 < /span>
- <input v-model="msg">
- </div > <p > {
- {
- msg
- }
- } < /p>
- <child @pass-data="getData"></child > </div>
- `,
- components: {
- 'child': childNode
- },
- data(){
- return {
- 'msg':'match'
- }
- },
- methods:{
- getData(value){
- this.msg = value;
- }
- }
- };
- / / 创建根实例new Vue({
- el: '#example',
- components: {
- 'parent': parentNode
- }
- })
- </script>
下面示例中,修改子组件中的 input 值,则父组件到接收到相同值,则显示出来
在一些情况下,可能会需要对一个 prop 进行双向绑定。事实上,这正是 Vue1.x 中的
修饰符所提供的功能。当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定的值。这很方便,但也会导致问题,因为它破坏了单向数据流的假设。由于子组件改变 prop 的代码和普通的状态改动代码毫无区别,当光看子组件的代码时,完全不知道它何时悄悄地改变了父组件的状态。这在 debug 复杂结构的应用时会带来很高的维护成本,上面所说的正是在 2.0 中移除
- .sync
的理由
- .sync
从 2.3.0 起重新引入了
修饰符,但是这次它只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的
- .sync
侦听器
- v-on
- <comp :foo.sync="bar"></comp>
会被扩展为:
- <comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件需要更新
的值时,它需要显式地触发一个更新事件:
- foo
- this.$emit('update:foo', newValue)
因此,可以使用. sync 来简化自定义事件的操作,实现子组件向父组件的数据传递
- <div id="example">
- <parent>
- </parent>
- </div>
- <script src="https://unpkg.com/vue">
- </script>
- <script>
- var childNode = {
- template: ` < div class = "child" > <div > 子组件数据: {
- {
- childMsg
- }
- } < /div>
- <input v-model="childMsg">
- <button @click=add >+1</button > </div>
- `,
- data(){
- return{
- childMsg: 0
- }
- },
- methods:{
- add(){
- this.childMsg++;
- this.$emit('update:foo',this.childMsg);
- }
- }
- };
- var parentNode = {
- template: `
- <div class="parent">
- <p>父组件数据:{{msg}}</p > <child: foo.sync = "msg" > </child>
- </div > `,
- components: {
- 'child': childNode
- },
- data() {
- return {
- 'msg': 0
- }
- }
- };
- // 创建根实例
- new Vue({
- el: '#example',
- components: {
- 'parent': parentNode
- }
- })
- </script>
来源: http://www.cnblogs.com/xiaohuochai/p/7389934.html