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组件封装,真的好用,可以让你开发效率提高的主要内容,如果未能解决你的问题,请参考以下文章

在Vue中将echart封装为可复用组件

微信小程序uniapp封装多列选择器组件

HBase实践|说好不哭,但HBase2.0真的好用到哭

微信小程序-自己封装一个弹窗组件

基于ElementUI封装可复用的表格组件

使用element-ui二次封装一个可复用编辑表单组件