element中el-dialog的:visible.sync理解

今天一直在纠结dialog中的sync有什么用??

因为在官方文档的在线运行中,没有发现其他方法;

所以一度认定,sync就是起一个关闭弹层的作用;原本在子组件中使用el-dialog时,去掉sync修饰

的visible点击关闭按钮无法关闭弹窗,更让我确信就是这个用处

但是********************

加上sync后再次点击右上角的关闭按钮,此处报了个警告,有道翻译后是:

【避免直接改变道具,因为每当父组件重新呈现时,道具的值会被覆盖。相反,应根据道具的值使用数据或计算属性。道具被突变:“showDialog”】

/*弹窗子组件*/  
<el-dialog
    title="提示"
    :visible.sync="showDialog"
    width="35%"
  >
/*父组件*/
 <add-dep :show-dialog.sync="showDialog" 
:current-node="currentNode" 
@addDepts="getDepartmentsList" />

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "showDialog"

found in

---> <AddDep> at src/views/departments/components/add-dep.vue

此处报错的原因在于,我的showDialog是从父组件中调用过来的,但是此时点击关闭按钮的时候:visible.sync修改了showDialog的值,与官网不同的地方在于,官网中的变量是声明在data中的;

翻看了这部分的源码后发现:

源码中在data中定义了一个closed属性来控制弹窗的开关并且监听了一个变量visible用来控制是否展示弹窗,此处就与我们使用的el-dialog关联起来了

不难看出,

在mounted 中判断了visible是否为true,为true且构建dom后调用了open打开弹窗并判断是否要追加到页面结构中;

watch中根据visible的val来控制closed的值从而来改变弹窗是否打开,与此同时,监听了在 Dialog 出现时锁定body 滚动

点击关闭按钮调用的handleClose方法,此方法中调用的hide才是点击关闭按钮真正关闭弹窗的方法

//copy部分源代码做解释,想看完整的建议问度娘
<template>
  <transition
    name="dialog-fade"
    @after-enter="afterEnter"
    @after-leave="afterLeave"
  >
    <div v-show="visible" class="el-dialog__wrapper" @click.self="handleWrapperClick">
      <div
        ref="dialog"
        role="dialog"
        aria-modal="true"
        :aria-label="title || 'dialog'"
        class="el-dialog"
        :class="[{ 'is-fullscreen': fullscreen, 'el-dialog--center': center }, customClass]"
        :style="style"
      >
        <div class="el-dialog__header">
          <slot name="title">
            <span class="el-dialog__title">{{ title }}</span>
          </slot>
          <button
            v-if="showClose"
            type="button"
            class="el-dialog__headerbtn"
            aria-label="Close"
            @click="handleClose"
          >
            <i class="el-dialog__close el-icon el-icon-close" />
          </button>
        </div>
        <div v-if="rendered" class="el-dialog__body"><slot /></div>
        <div v-if="$slots.footer" class="el-dialog__footer">
          <slot name="footer" />
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
  data() {
    return {
      closed: false
    }
  },
  watch: {
    // 是否显示 Dialog,支持 .sync 修饰符
    visible(val) {
      if (val) {
        this.closed = false
        this.$emit('open')
        this.$el.addEventListener('scroll', this.updatePopper)
        this.$nextTick(() => {
          this.$refs.dialog.scrollTop = 0
        })
        if (this.appendToBody) {
          document.body.appendChild(this.$el)
        }
      } else {
        this.$el.removeEventListener('scroll', this.updatePopper)
        if (!this.closed) this.$emit('close')
      }
    }
  },

  mounted() {
    if (this.visible) {
      this.rendered = true
      this.open()
      if (this.appendToBody) {
        document.body.appendChild(this.$el)
      }
    }
  }, 
methods: {
 // 关闭dialog
    handleClose() {
      // 如果有beforeClose,执行beforeClose
      if (typeof this.beforeClose === 'function') {
        this.beforeClose(this.hide)
      } else {
        // 否则隐藏
        this.hide()
      }
    },
    // 隐藏dialog
    hide(cancel) {
      if (cancel !== false) {
        this.$emit('update:visible', false)
        this.$emit('close')
        this.closed = true
      }
    }
}
</script>

结论:

将dialog直接使用时

<el-dialog>封装前(源码中)有一个visible属性来控制弹层是否显示,并且监听了弹层的值,sync是<el-dialog>里面定义的一个标识,用来双向绑定,修改了值就会触发源代码中的监听,从而运行$emit的逻辑

将dialog作为弹层子组件使用时,如果不对其进行一些设置,点击关闭后会以上警告且无法再次打开该弹窗。

可以去掉关闭按钮:show-close="false"和sync修饰符仅使用确认取消按钮中emit的方法来关闭弹层

<el-dialog

    title="提示"

    :visible="showDialog"

    width="35%"

    @close="closeFn"

  > 
// 添加子部门
    async addDepartment() {
      try {
        await this.$refs.departForm.validate()
        // 新增部门
        await addDepartments({ ...this.departForm, pid: this.currentNode.id })
        // 修改视图
        this.$emit('addDepts')
        // 提示消息
        this.$message.success('成功添加子部门')
        // 关闭弹层
        this.$emit('update:showDialog', false)
      } catch (error) {
        console.log(error)
      }
    },
    closeFn() {
      // 重置数据  因为resetFields 只能重置 表单上的数据 非表单上的 比如 编辑中id 不能重置
      this.departForm= {
        name: '',
        code: '',
        manager: '',
        introduce: ''
      }
      this.$refs.departForm.resetFields() // 重置校验字段
      // 关闭弹层
      this.$emit('update:showDialog', false)
    }

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值