聊聊使用vue的.sync修饰符遇到的问题

1,550 阅读2分钟

这是我参与11月更文挑战的第29天,活动详情查看:2021最后一次更文挑战

问题

由于业务需求,今天把饿了么的弹窗封装成组件,供别的页面调用,三下五除二就封装好了,文档写的很详细,功能也正常,点击取消按钮可以正常关闭弹框。但是点击弹框空白的地方关闭弹框时突然看到控制台报错:

image.png

经常写vue的同学,就应该知道这个问题。这个是因为vue的单向数据流,数据从父组件传向子组件,子组件不能修改从父组件传的数据,只能通过父组件去修改。 如果你在子组件修改,就会报这个错。

下面我通过代码模拟一下

父组件

<template>
  <div>
    <el-button @click="showFn">show</el-button>
    <Dialog v-model="dialogVisible"></Dialog>
  </div>
</template>

<script>
import Dialog from './components/Dialog.vue'
export default {
  name: "App",
  components: {
    Dialog
  },
  data () {
    return {
      dialogVisible: false
    }
  },
  methods: {
    showFn () {
      this.dialogVisible = true
    }
  }
};
</script>

Dialog组件:

<template>
  <el-dialog
    title="我是dialog头部"
    :visible.sync="value"
  >
    <div>我是dialog内容</div>
    <span slot="footer">
      <el-button @click="close()">取消</el-button>
    </span>
  </el-dialog>
</template>

<script>
export default {
  name: 'Dialog',
  props: {
    value: {
      type: Boolean,
      required: true
    }
  },
  methods: {
    close () {
      this.$emit('input', false)
    }
  }
}
</script>

v-model

我是通过v-model来控制Dialog的显示的。

这个v-model是结合prop为valueinput事件的语法糖,传入prop为value的值,如果value需要改变的时候,触发input事件,同时把改变的值当作参数传回。

sync修饰符

在Dialog组件里面,我把prop传入的value又传给el-dialog组件,这里使用了.sync修饰符。

我讲讲.sync修饰符,其实它跟v-model类似,它是 绑定值@update:绑定值的语法糖。

绑定值加上sync修饰符,传入子组件,然后在子组件中需要改变绑定值时,通过触发@update:绑定值事件,然后把改变的值传给父组件,这样子达到单向数据流的目的。

问题分析

说说我遇到的这个报错问题,点击取消按钮可以正常关闭弹框。但是点击弹框空白的地方关闭弹框时控制台却报错。

这个是因为在el-dialog组件上使用了.sync修饰符,弹框关闭的时候同时把value的值改变了,而这个是在字组件里改变,所以导致了报错。

那为什么点击取消按钮可以正常关闭弹框? 因为它是通过事件触发通知父组件来修改,所以不会报错。

解决问题

那该怎么解决呢?

我们也参照取消按钮通过事件触发的方式,前面我们说了,sync修饰符也是有事件触发的,我这里不用语法糖,而是使用事件触发,使用是@update:visible

elemnetUI的dialog组件部分源码:

image.png

修改后的代码:

  <el-dialog
    title="我是dialog头部"
    :visible="value"
    @update:visible="close"
  >
    <div>我是dialog内容</div>
    <span slot="footer">
      <el-button @click="close()">取消</el-button>
    </span>
  </el-dialog>

运行,没有报错了。