el-dialog组件二次封装

前端到处需要用到e-dialog,对dialog的样式,close处理,visible处理的重复性代码很多,于是我们尝试进行二次封装。

# 现有问题

项目中el-dialog使用频率很高,到处都会出现相同逻辑,比如

<template>
  <el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>
  
  <el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
    <span>这是一段信息</span>
    <span slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
    </span>
  </el-dialog>
 </template>
  <script>
    export default {
      data() {
        return {
          dialogVisible: false
        };
      },
    };
</script>

visible处理的重复性代码很多,打算对其进行进一步封装。

# 设想

最好情况下,我们希望dialog组件在调用的地方能像普通组件一样,接受是否显示的参数即可,而不是每次交给调用处处理打开关闭的逻辑。

<template>
  <el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>
  <dialog-component :visible.sync="dialogVisible"></dialog-component>
 </template>
  <script>
    export default {
      data() {
        return {
          dialogVisible: false
        };
      },
    };
</script>

vue2之后,子组件不再推荐直接修改父组件数据,所以不能直接修改visible的值,否则会报错

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,因为每当父组件重新渲染时,该值都会被覆盖。而是根据道具的值使用数据或计算属性。

真正的原因:

在 Vue2.X 中,父组件传给子组件的 props 属性是不允许改变的,因为在新的渲染机制中,每当父组件重新渲染时,子组件都会被重新覆盖,所以 props 属性,在子组件内部应该被看做是不可变对象。所以我们必须借助中间变量来做缓冲,通过中间变量的改变发送事件给父组件,父组件接收到后,再对 props 进行更改。

对此我们需要如此处理:

<template>
  <el-dialog :visible.sync="dialogVisible"  :before-close="close">
    <slot />
  </el-dialog>
</template>

<script>
export default {
  name: 'DialogComponent',
  props: {
    dialogVisible: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    close() {
      this.$emit('update:dialogVisible', false)
    },
  }
}
</script>

# 更新下

vue2.4之后,增加的特性 $attrs $listeners,配合使用更加无缝。还可以将使用最多的表单编辑也封装进来

<template>
  <el-dialog
    v-bind="$attrs"
    :visible.sync="dialogVisible"
    :before-close="close"
    v-on="$listeners"
  >
    <div class="dialog-content">
      <el-form ref="elForm" :model="formData" :rules="rules" v-bind="$attrs">
        <slot />
      </el-form>
    </div>
    <span slot="footer" class="dialog-footer">
      <el-button @click="close">取 消</el-button>
      <el-button type="primary" @click="submit">确 定</el-button>
    </span>
  </el-dialog>
</template>

<script>
export default {
  name: 'DialogForm',
  props: {
    dialogVisible: {
      type: Boolean,
      default: false
    },
    rules: {
      type: Object,
      default: () => {
      }
    },
    form: {
      type: Object,
      default: () => {
      }
    }
  },
  data() {
    return {
      formData: {}
    }
  },
  watch: {
    form: {
      handler(val) {
        this.formData = { ...val }
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    onClose() {
      this.$refs['elForm'].resetFields()
    },
    close() {
      this.formData = {}
      this.$emit('update:dialogVisible', false)
    },
    submit() {
      this.$refs['elForm'].validate(valid => {
        if (!valid) return
        this.$emit('submit', { ...this.formData })
        this.close()
      })
    }
  }
}
</script>

# 使用示例

<template>
	<div>
		<el-button size="mini" @click="dialogVisible=true">新增</el-button>
		<el-button size="mini" @click="edit">编辑</el-button>
		<DialogForm :dialog-visible.sync="dialogVisible" size="mini"
		            label-width="55px" :title="title" width="400px"
		            :form="form" :rules="rules"
		            @submit="submit">
			<el-form-item label="编码" prop="code">
				<el-input placeholder="请输入编码" v-model="form.code"/>
			</el-form-item>
			<el-form-item label="名称" prop="name">
				<el-input placeholder="请输入名称" v-model="form.name"/>
			</el-form-item>
			<el-form-item label="描述" prop="description">
				<el-input placeholder="请输入描述" type="textarea" v-model="form.description"/>
			</el-form-item>
		</DialogForm>
	</div>
</template>
<script>
export default {
	name: 'List',
	data(){
		return {
			dialogVisible: false,
			form: {},
			rules: {
				code: [
					{required: true, message: '请输入编码', trigger: 'blur'}
				]
			},
			title: '编辑表单',
		}
	},
	methods: {
		submit( data ){
			console.log(data)
		},
		edit(){
			this.form = {
				code: 123,
				name: '名称'
			}
			this.dialogVisible = true
		}
	}
}
</script>

Show Copy
最近更新
01
echarts扇形模拟镜头焦距与可视化角度示意图
03-10
02
vite插件钩子
03-02
03
vite的依赖预构建
02-13
更多文章>