el-dialog-form组件封装,真的好用,可以让你开发效率提高
Posted zcm1688
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了el-dialog-form组件封装,真的好用,可以让你开发效率提高相关的知识,希望对你有一定的参考价值。
1、新建DialogForm.vue文件
<template> <div class="base-dialog"> <el-dialog :type="type" :custom-class="customClass" :close-on-click-modal="closeOnClickModal" :visible="visible" :title="title" :width="width" :show-close="true" :before-close="beforeClose" > <!-- <el-card> --> <el-form ref="d-form" :model="form" :label-position="labelPosition" label- > <el-row :gutter="20"> <el-col v-for="(item, index) in items" v-show="item.hidden ? !item.hidden(form) : true" :key="index" :span="item.span || 20" > <el-form-item :label="item.label" :prop="item.prop" :rules="item.hidden && item.hidden(form) ? null : item.rules" > <el-tooltip :disabled="!item.tip" effect="dark" :content="item.tip" placement="top" > <slot v-if="item.elName === \'slot\'" :name="item.prop" :form="form" ></slot> <el-component v-else v-model="form[item.prop]" :el-name="item.elName" :on="item.on || " :attrs="item.attrs || " :options="item.options || []" :disabled="item.disabled ? item.disabled(form) : false" ></el-component> </el-tooltip> </el-form-item> </el-col> <slot></slot> </el-row> </el-form> <!-- </el-card> --> <span slot="footer" class="dialog-footer"> <el-button size="small" @click="onCancel">取 消</el-button> <el-button type="primary" size="small" @click="onSubmit" >确 定</el-button > </span> </el-dialog> </div> </template> <script> // 验证器文档地址:https://github.com/yiminghe/async-validator import elComponent from "@/lib/elComponent.js"; export default name: "ElDialogForm", components: elComponent , props: closeOnClickModal: type: Boolean, default: false , // 是否可以点击关闭 type: String, // 对话框类型:1.基础表单[base-dialog-form] 2.表格[base-dialog-table] 3.全屏 [base-dialog-fullscreen] // 是否显示dialog visible: type: Boolean, default: false , // 标题 title: type: String, default: "" , // 宽度 width: type: String, default: "" , // 表单项 items: type: Array, default: () => [] , // 表单值 form: type: Object, default: () => return ; , labelPosition: type: String, default: "right" , computed: customClass() let className = ""; switch (this.type) case "form": className = "base-dialog-form"; break; case "table": className = "base-dialog-table"; break; case "fullscreen": className = "base-dialog-fullscreen"; break; return className; , created() this.type === "fullscreen" && (this.fullscreen = true); , methods: onSubmit() this.$refs["d-form"].validate(valid => if (valid) this.$emit("submit", this.form); ); , onCancel() this.$emit("update:visible", false); this.$emit("cancel"); this.$refs[\'d-form\'].resetFields(); , close() this.$emit("update:visible", false); this.$refs[\'d-form\'].resetFields(); , beforeClose() this.$emit("update:visible", false); this.$refs[\'d-form\'].resetFields(); ; </script> <style lang="scss"> .el-form-item margin-bottom: 15px !important; .base-dialog text-align: left; .el-dialog__wrapper // overflow: hidden; .el-dialog display: flex; flex-direction: column; .el-dialog__header height: 40px; line-height: 40px; padding: 0px 20px; background: #eff3fa; color: #fff; border-bottom: 1px solid #dcdfe6; border-top-left-radius: 0; border-top-right-radius: 0; .el-dialog__title font-size: 16px; // font-weight: bold; .el-dialog__headerbtn top: 12px; .el-dialog__body flex: 1; overflow: auto; padding: 20px !important; .el-dialog__footer text-align: center; border-top: 1px solid #eee; padding: 8px 20px; background: #fefefe; .base-dialog-form height: auto; margin-top: 15vh !important; .el-dialog__body padding: 20px 20px 0 20px !important; .el-dialog__footer border: none; padding: 10px 20px 20px; background: none; .custom-table // 取消表格下边线 tbody tr:last-child td border-bottom: none !important; .base-dialog-table height: 90vh; margin-top: 5vh !important; .el-dialog__body .base-dialog-fullscreen height: 100vh; width: 100vw; .el-dialog__body padding: 10px; .el-date-editor.el-input width: 100% !important; .el-select width: 100% !important; .el-range-editor.el-input__inner width: 100% !important; .el-cascader width: 100% !important; </style>
2、新建lib文件夹,文件夹下面创建三个文件,分别是defaultAttrs.js,elComponent.js,slots.js,代码分别如下
defaultAttrs.js
const map = \'el-time-picker\': \'size\': \'small\', \'placeholder\': \'请选择时间\', \'value-format\': \'HH:mm:ss\', , \'el-date-picker\': \'size\': \'small\', \'placeholder\': \'请选择日期\', \'value-format\': \'yyyy-MM-dd\', \'type\': \'date\', \'start-placeholder\': \'开始日期\', \'end-placeholder\': \'结束日期\', , ; export function getDefaultAttrs(elName) return ( map[elName] || size: \'small\', );
elComponent.js
// 获取默认attrs import getDefaultAttrs from \'./defaultAttrs.js\'; // 获取子组件 import getChild from \'./slots.js\'; // 导出新组件 export default props: [\'value\', \'elName\', \'options\', \'disabled\'], name: \'el-component\', render(h) const self = this; const slots = Object.keys(this.$slots) .reduce((arr, key) => arr.concat(this.$slots[key]), []) .map(vnode => vnode.context = this._self; return vnode; ); // 获取子组件,如果有的话 const child = getChild(this.elName, h, this.options); // 获取事件监听 const events = this.$attrs.on || ; // 渲染函数中没有与 v-model 的直接对应——必须自己实现相应的逻辑 events[\'input\'] = function(event) self.$emit(\'input\', event); ; // 参数传进来的attrs const attrsinset = this.$attrs.attrs || ; // 默认的attrs const defaultAttrs = getDefaultAttrs(this.elName); // 根据type渲染组件 return h( `$this.elName`, on: events, props: ...this.$props, ...attrsinset, , // 透传 scopedSlots scopedSlots: this.$scopedSlots, attrs: ...attrsinset, ...defaultAttrs, disabled: this.disabled, , , [...slots, ...child], ); , ;
slots.js
const map = \'el-radio-group\': \'el-radio\', \'el-checkbox-group\': \'el-checkbox\', \'el-select\': \'el-option\', ; export function getChild(elName, h, options = []) const arr = []; if (map[elName] !== undefined) for (const i of options) const label = elName === \'el-select\' ? i.label : i.value; const value = elName === \'el-select\' ? i.value : i.label; arr.push( h( `$map[elName]`, props: label, value, , , [h(\'span\', i.label)] ) ); return arr;
3、如何在页面调用,代码如下
//在main.js中全局注册组件 import DialogFrom from \'@/components/Table/DialogForm.vue\' Vue.component(\'DialogFrom\', DialogFrom)
<!-- 按钮触发弹窗 --> <el-button type="primary" size="small" @click="dialog = true">打开表单</el-button> <!-- 表单 --> <DialogFrom ref="DialogFrom" type="form" :visible.sync="dialog" title="表单标题" width="50%" :items="items" :form="form" @submit="onSubmit" > <template slot="image"> <div class="upLoadPicBox" title="750*750px" @click="modalPicTap(\'1\', \'image\')" > <div v-if="form.image" class="pictrue"> <img :src="form.image" /> </div> <div v-else class="upLoad"> <i class="el-icon-picture cameraIconfont" /> </div> </div> </template> </DialogFrom>
//JS的data部分 form: input: "", inputNumber: 0, switch: false, timePicker: "", datePicker: "", radioGroup: 1, checkboxGroup: [], select: [], checkbox: 1, datePickerTwo: "", image: "", cascader: [] , dialog: false, items: [ elName: "el-input", span: 12, label: "普通输入", prop: "input", rules: [ required: true, message: "请输入名称", trigger: "blur" ], attrs: placeholder: "请输入名称" , hidden: function() return false; , disabled: e => if (this.form.checkbox == 1) return true; else return false; , on: blur: e => console.log(e); , elName: "el-date-picker", span: 12, label: "日期选择", prop: "datePicker", attrs: "value-format": "yyyy-MM-dd" , elName: "el-date-picker", span: 12, label: "日期范围选择", prop: "datePickerTwo", attrs: type: "daterange" , elName: "el-time-picker", span: 12, label: "时间选择", prop: "timePicker", on: , elName: "el-switch", span: 12, label: "开关", prop: "switch", on: , elName: "slot", span: 12, label: "上传图片", prop: "image" , elName: "el-radio-group", span: 12, label: "单选框组", prop: "radioGroup", tip: "", options: [ label: "苹果", value: 1 , label: "西瓜", value: 2 ], on: change: e => , elName: "el-cascader", span: 12, label: "下拉级联选择", prop: "cascader", options: [], attrs: placeholder: "请选择级联", multiple: false , on: change: e => console.log("-----------"); console.log(e); , elName: "el-select", span: 12, label: "下拉选择", prop: "select", options: [ label: "鼠标", value: 1 , label: "键盘", value: 2 ], attrs: placeholder: "请输入名称", multiple: true , on: change: e => console.log("-----------"); console.log(e); , elName: "el-checkbox", span: 12, label: "选择", prop: "checkbox", attrs: label: "我同意", "true-label": 1, "false-label": 0 , on: change: e => console.log("-----------"); console.log(e); , elName: "el-checkbox-group", span: 12, label: "多选框组", prop: "checkboxGroup", options: [ label: "鼠标", value: 1 , label: "键盘", value: 2 , label: "电脑", value: 3 ], on: change: e => console.log("-----------"); console.log(e); ],
//JS的methods方法部分 modalPicTap(tit, type) const _this = this; const attr = []; this.$modalUpload(function(img) if (tit === "1" && type == "image") _this.form.image = img[0]; , tit); , onSubmit(form) console.log(form); ,
vue 封装可复用列表组件
参考技术A 在开发过程当中,列表页面会有很多,比如:消息列表、用户列表等。我们可以为这样的页面封装一个可复用性的列表组件。
这些页面的共性:
1、后端接口非常相似:请求列表数据 需要提交的参数 请求的页数pageIndex 和 每页的个数 pageSize ,返回参数 data 里边基本会有 list数组。
2、分页加载,也就是上拉加载更多,或者点击页面加载更多。
不同之处:
1、每个列表项的UI布局不同。比如:消息列表,每个消息大概内容包括:消息标题,描述,时间等信息。用户列表,每个用户项,大概内容包括:用户的姓名,联系方式等等。
2、每个列表项有自己的业务逻辑,点击事件等等
3、后端接口请求参数,pageIndex和pageSize之外的参数。
封装可复用列表组件涉及到的vue 技术点
1、props 父组件 把 请求api地址和请求参数传递给组件。
2、v-slot 作用域插槽 父组件可以访问子组件 item 数据,解耦UI布局。
3、mint-ui Loadmore 组件 实现上拉加载更多。
我们在封装复用性组件的时候,组件名建议使用多个单词,避免跟现有的以及未来的 HTML 元素相冲突。
v-list 组件
使用 v-list
好,到了这里我们就封装并使用了一个可复用列表组件。
总结:
封装这个列表组件,可以解决大部分列表页,列表组件完成了,数据请求,加载更多,是不是最后一页等功能,不必在每个列表页,处理这些问题。
我们通过作用域插槽,父级可以访问每个列表项的数据,可以解耦UI布局,自己定义自己的UI布局,添加事件等。
以上是关于el-dialog-form组件封装,真的好用,可以让你开发效率提高的主要内容,如果未能解决你的问题,请参考以下文章