element-ui实现一个动态布局的对话框

news2024/9/29 17:23:49

前言:在工作中有各种各样的对话框,最多就是填写信息这些的,一般这样的内容都是el-input输入框,el-select选择框等等之内的,这时我们就可以封装成一个组件,想要什么内容就传一个json配置,像其他组件那样,这样可以极大的简化开发,不至于每次都要去写el-input这些细微根节的东西,那问题来了

问题:就是布局,元素少还好,要是多的话,比如有几个输入框,几个选择框,又有几个多选框等等,那就是一排排的排下来难看死了,

解决:我自己琢磨了好久,改进了好多遍,终于是搞出来一个这样的,判断当元素也就是输入框选择框这些加起来大于4个的话就改为一行两个,如图 

 当四个的时候

当大于四个的时候

 

虽然我觉得这样也没有多好看,但比一行一个的好看多了,没办法,封装组件就是这样,细节很难各个把控到位

 有些东西就是那么长,比如这个待缴费金额,光字就五个,如果它所在行搞成两个的话,就太狭小了,所以我除了组件灵活布局外,参数还可以配置是否独占一行,所以当自己可以设置独占一行的时候问题就来了,没有外界的干扰下,我组件布局的逻辑是,元素大于4个时就添加一个class到根元素上,设置下面元素的宽度为50%,display为inline-block,再判断元素个数是否为奇数,为基数最后一个就独占一行,但是我给某个元素设置了独占一行的属性,那它的判断就不准确了,所以最后一个就不会独占一行了,而且设置的独占一行的元素在中间的话还会影响上面的元素,因为如果设置的独占一行的元素是偶数时说明它上面还有一个宽度为50%的元素,所以这个时候又要判断,总之至少要三种判断,话不多说,贴代码

组件代码

<template>
  <div _wid="wdialog">
    <el-dialog :fullscreen="fullscreen || fullscreen1" :class="{mobile:fullscreen,noMobile:!fullscreen}"
      :visible.sync="openSenior1">
      <template slot="title">
        <slot name="title">
        </slot>
        <template v-if="!fullscreen">
          <i v-show="!fullscreen1" class="el-icon-full-screen full" @click="fullscreen1=true"></i>
          <svg-icon icon-class="qxpp" v-show="fullscreen1" class="qxqp full" @click="fullscreen1=false"></svg-icon>
        </template>
      </template>
      <el-form v-if="options1" :validate-on-rule-change="false" :model="content"
        :class="[options1.length<=4?'senior1':'senior2']" :rules="rules" ref="formSenior">
        <el-form-item v-for="(item,index) in options1" :class="{w100:item.yes}" :label="item.label" :prop="item.name">
          <repeat :content="content" v-model="content[item.name]" :item="item"></repeat>
        </el-form-item>
        <el-form-item label="" class="footer">
          <el-button type="primary" @click="submit1('formSenior')">{{confrimLabel}}</el-button>
        </el-form-item>
      </el-form>
      <slot></slot>
    </el-dialog>
  </div>
</template>

<script>
  import repeat from "@/components/topOperation/components/repeat.vue"
  import {
    deepClone,
    judgeType
  } from "@/utils/deepClone.js"
  export default {
    name: "dialogA",
    props: {
      options: {
        type: Array
      },
      rules: {
        type: Object
      },
      openSenior: {
        type: Boolean,
        default: false
      },
      submit: {
        type: Function
      },
      confrimLabel: {
        type: String
      },
      contentP: {
        type: Object,
        default: function() {
          return {}
        }
      },
    },
    model: {
      prop: "openSenior", //用来接收 父组件 传给子组件的值
      event: "openSenior-event" //用来触发的事件
    },
    watch: {
      openSenior: {
        handler() {
          this.openSenior1 = this.openSenior
        },
        immediate: true
      },
      openSenior1: {
        handler() {
          this.$emit("openSenior-event", this.openSenior1);
        },
        immediate: true
      },
      contentP: {
        handler() {
          this.content = this.contentP
        },
        immediate: true,
        deep: true
      },
      options: {
        handler() {
          let o = deepClone(this.options);
          let len = 0;
          let oo = []
          for (var k in o) {
            if (o[k].options1 && judgeType(o[k].options1) == "string") {
              o[k].options1 = JSON.parse(o[k].options1)
            }
            if (o[k].options2 && judgeType(o[k].options2) == "string") {
              o[k].options2 = JSON.parse(o[k].options2)
            }
          }
          for(let k in oo){
            if ((k < oo.length - 1 && (parseInt(k) + 1) % 2 != 0 && (oo[parseInt(k) + 1].leGes || oo[parseInt(k) + 1].wyb ||
                oo[parseInt(k) + 1].type == 5 || oo[parseInt(k) + 1].type == 10 || oo[parseInt(k) + 1].type == 3)) || oo[k]
              .leGes || oo[k].wyb || oo[k].type == 5 || oo[k].type == 10 || oo[k].type == 3) {
              oo[k].yes = true
            } else {
              len++;
              if (k == oo.length - 1 && len % 2 != 0) {
                oo[k].yes = true
              }
            }
          }
          this.options1 = oo;
        },
        deep: true,
        immediate: true,
      }
    },
    data() {
      return {
        content: {},
        openSenior1: false,
        options1: [],
        fullscreen1: false,
      }
    },
    computed: {
      fullscreen() {
        if (this.$store.state.app.device == 'mobile') {
          return true;
        } else {
          return false;
        }
      },
    },
    created() {},
    components: {
      repeat
    }
  }
</script>

<style lang="scss">
  .full {
    float: right;
    margin-right: 30px;
    cursor: pointer;
    color: #909399;
    font-family: element-icons !important;
    speak: none;
    font-style: normal;
    font-weight: 400;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    vertical-align: baseline;
    display: inline-block;
    -webkit-font-smoothing: antialiased;
    margin-top: 1px;

    &:hover {
      color: #409EFF;
    }
  }

  div[_wid="wdialog"] {

    .ax {
      .el-form-item__content {
        width: 75% !important;
      }
    }

    .el-upload {
      width: 100%;

      .el-upload-dragger {
        width: 100%;

        .el-upload__text {
          padding: 20px;
        }
      }
    }

    .noMobile {
      .w100 {
        width: 100% !important;

        .el-form-item__content {
          width: 75% !important;

          .el-select {
            width: 100% !important;
          }

          .el-input {
            width: 100% !important;
          }
        }
      }

      .senior1 {
        width: 100%;

        .el-form-item {
          width: 100%;

          .el-input {
            width: 100% !important;
          }

          .el-form-item__content {
            width: 75%;
          }

        }
      }

      .el-select {
        width: 100%;
      }

      .senior2 {
        .w100 {
          .el-form-item__label {
            width: 16% !important;
          }
        }

        .el-form-item {
          width: 45%;

          .el-form-item__content {
            width: 62%;

            .el-input {
              width: 100%;
            }
          }
        }

        .el-form-item__label {
          width: 36%;
        }
      }

      .el-dialog__body {
        .el-form {
          padding: 0 30px;
        }
      }
    }

    .el-dialog__body {
      .el-form-item {
        padding: 10px;
      }

      .el-form-item__label {
        width: 100px;
      }
    }

    .footer {
      clear: both;
      float: none !important;
      display: block;
      text-align: right;
      width: 100% !important;
      position: absolute;
      bottom: 0;
      left: 0;

      .el-form-item__content {
        float: none !important;
        width: 100% !important;
      }

      padding: 20px !important;
    }

    .el-form-item__error {
      bottom: 100%;
      top: unset;
    }

    $tinput:35px;

    .el-input {
      width: 120px;

      .el-input__suffix {
        cursor: pointer;

        .el-input__icon {
          line-height: $tinput;
        }
      }

      .el-input__inner {
        height: $tinput;
        line-height: $tinput;
      }
    }

    .el-button {
      padding: 9px 15px;
    }

    .el-form {
      display: inline-block;

      .el-form-item {
        float: left;
        margin-right: 10px;
        margin-bottom: 0;

        .el-form-item__content {
          float: left;
        }

        .el-select__caret {
          line-height: 40px;
        }
      }
    }

    .el-date-editor {
      width: 100%;

      .el-range-input {
        width: 100%;
      }
    }
  }
</style>

写的有点乱,如果觉得可以删的话就自己删几个,因为这是我项目里面的,还穿插一些跟其他组件联动的代码,简单解释一下

这个是对话框组件,里面的

repeat:统一输入框,选择框等等组件,传item里面有个type确定类型

options:参数json数组,里面描述的就是多少个输入框,选择框这些,然后每个对象还有专门的配置

rules:校验,我这个对话框直接是填写信息,提交信息一起搞定了

openSenior:这个东西是控制对话框的打开和关闭,openSenior1是组件里面的,少个1的都是父组件传过来的,因为vue子组件不能修改父组件传过来的,所以子组件里面需要改的变量都要在data里面定义然后使其=父组件传过来的

content:数据,填写的数据存放的对象,提交就是把这个对象提交过去

fullscreen1:控制全屏

fullscreen:是否是手机上打开的,是手机上的话铺满屏幕

deepClone:克隆一个新对象
judgeType:校验类型

里面最核心的就是这段代码

for(let k in oo){
            if ((k < oo.length - 1 && (parseInt(k) + 1) % 2 != 0 && (oo[parseInt(k) + 1].leGes || oo[parseInt(k) + 1].wyb ||
                oo[parseInt(k) + 1].type == 5 || oo[parseInt(k) + 1].type == 10 || oo[parseInt(k) + 1].type == 3)) || oo[k]
              .leGes || oo[k].wyb || oo[k].type == 5 || oo[k].type == 10 || oo[k].type == 3) {
              oo[k].yes = true
            } else {
              len++;
              if (k == oo.length - 1 && len % 2 != 0) {
                oo[k].yes = true
              }
            }
          }

这段代码看起来很沉重,是因为我没改,哈哈,因为我想您可能用得着 

这段代码就是控制元素是否独占一行的逻辑判断

deepClone.js

export function judgeType(obj) {
  // tostring会返回对应不同的标签的构造函数
  const toString = Object.prototype.toString;
  const map = {
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Function]': 'function',
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object',
  };
  if (obj instanceof Element) {
    return 'element';
  }
  return map[toString.call(obj)];
}

export function deepClone(data) {
  const type = judgeType(data);
  let obj;
  if (type === 'array') {
    obj = [];
  } else if (type === 'object') {
    obj = {};
  } else {
    // 不再具有下一层次
    return data;
  }
  if (type === 'array') {
    // eslint-disable-next-line
    for (let i = 0, len = data.length; i < len; i++) {
      obj.push(deepClone(data[i]));
    }
  } else if (type === 'object') {
    // 对原型上的方法也拷贝了....
    // eslint-disable-next-line
    for (const key in data) {
      obj[key] = deepClone(data[key]);
    }
  }
  return obj;
}

 repeat.vue

<template>
      <el-input :style="{width: item.width}" :placeholder="item.placeholder" v-model="valueTemp" clearable>
      </el-input>
    </template>
    <template v-if="item.type == 1">
      <el-select filterable :disabled="item.disabled" :style="{width: item.width}" clearable v-change:[valueTemp]="item.change" v-model="valueTemp"
        :placeholder="item.placeholder">
        <el-option v-for="item in item.options1" :key="item.value" :label="item.label" :value="item.value">
        </el-option>
      </el-select>
    </template>
    </template>
  </div>
</template>

<script>

  export default {
    name: "repeat",

    directives: {
      change: {
        // 指令的定义
        update: function(el, binding) {
          if (binding.value.change) {
            binding.value(binding.arg)
          }
        }
      }
    },
    props: {
      value: "",
      sign: "",
      item: {
        type: Object
      },
    },
    model: {
      prop: 'value',
      event: 'change'
    },
    data() {
      return {
        valueTemp: "",
      }
    },
    watch: {
      valueTemp(val) {
        this.$emit('change', val)
      },
      value: {
        handler(val) {
          this.valueTemp = val
        },
        immediate: true
      },
    },
  }
</script>

<style lang="scss">
  .w100 {
    width: 100%;

    .el-form-item__content {
      width: 45%;
    }
  }

  div[_wid="repeat"] {
    .el-radio {
      margin-right: 15px;
    }

    .xs {
      .el-input {
        width: 42% !important;
      }
    }

    .leGes {
      div[_wid='numberInput'] {
        display: inline-block;
        margin: 1px;
        .el-input{
          width: 100%;
          height: 33px;
          line-height: 33px;
          input{
            height: 33px;
            line-height: 33px;
          }
        }
      }
      .el-input__inner1{
        position: absolute;
        top: 0;
        left: 0;
        height: 35px;
      }
      box-sizing: border-box;
      display: inline-block;
      width: 220px;
      border-radius: 4px;
      line-height: 35px;
      .el-select {
        width: 20% !important;

        .el-input {
          width: 100% !important;
          line-height: 35px;
          input {
            border: none;
            text-align: center;
          }
        }

        .el-input__suffix {
          display: none;

        }
      }

      .el-date-editor {
        margin: 1px;
        .el-input__prefix {
          display: none;
        }
        .el-input__suffix {
          display: none;

        }
        height: 33px;
        line-height: 33px;
        input {
          cursor: pointer;
          padding: 0;
          padding-left: 20px;
          padding-right: 20px;
          height: 33px;
          line-height: 33px;
        }
      }

      .el-input {
        .el-input__prefix {
        }
        .el-input__suffix{
          top: 1px;
        }
        input {
          border: none;
        }
      }
    }

    .close {
      text-align: center;
      cursor: pointer;
      position: absolute;
      right: 20px;
      color: #C0C4CC;
      top: 1px;
    }
    .hover{
      border-color: #C0C4CC;
    }
  }

  .leGesDrop {
    margin: 0;
  }
</style>

里面就实现了type=0 输入框和type=1的选择框,我自己的是有10个类型了,但涉及太多,所以就放了这两个

使用

<template>
<div>
<dialogA confrimLabel="确定搜索"  :options="options" v-model="openSenior">
      <template slot="title">
        <svg-icon icon-class="sx" />高级筛选
      </template>
</dialogA>
<span @click="openSenior=true">打开高级筛选框</span>
<div>
</template>

<script>
export default{
    data(){
        return{
            options:  [{
              name: "name",
              label: "名称",
              placeholder: "名称",
              type: 0, //类型 0 输入框 1 选择框
              width: "120px", 
              }, {
              name: "status",
              label: "状态",
              placeholder: "状态",
              type: 1, //类型 0 输入框 1 选择框 
              width: "120px",
              options1: [{
                value: 0,
                label: "未通过"
              }, {
                value: 1,
                label: "通过"
              }],

            }],
            openSenior: false
      }
    }
}
</script>

这是简单示例

options 其他配置:

wyb:当前元素独占一行

change:选择框值改变触发,可以传多个值,在

v-change:[valueTemp]="{change:item.change,sign:sign}"

里设置,valueTemp是当前绑定的参数,item.change是配置的函数,sign就是你想传的其他参数,在自定义指令里面这样写就行

directives: {
      change: {
        // 指令的定义
        update: function(el, binding) {
          if (binding.value.change) {
            binding.value.change(binding.arg,binding.value.sign)
          }
        }
      }
    },

这就有关自定义指令的学习了,也简单,想了解的可以去官网看看

自定义指令 — Vue.js 中文文档

好了,也没啥好说的了,最核心的就是那段判断是否独占一行的代码,另外自行扩展

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

适合Python初学者阅读的Github开源代码

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store 你想要的&#xff0c;这里都有&#xff01; Python作为一门热门的编程语言&#xff0c;在Github上想要找Python项目可以说是「多如牛毛」。 无论是Star数量还是项目数量&#xff0c;都稳居前3名。 项…

5分钟搭建一个粗粒度「视频去重」系统

Jupyter Notebook 教程: How to Build a Video Deduplication System 「视频去重」可以在海量的视频数据中实现侵权片段或者删除掉重复冗余的内容 。随着抖音、快手、Bilibili 等视频平台的兴起和火爆&#xff0c;类似视频这样的非结构化数据在数量上有了极大的增长。 视频平台…

【数据可视化】第四章—— 基于pandas的数据可视化(pandas基本操作)

图形绘制的代码&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1pgS60sry6XDILIhth8bAvA?pwdabcd 提取码&#xff1a;abcd 文章目录1. Pandas库的数据运算1.1 方法形式的运算1.2 比较运算法则1.3 排序2. 基本统计分析函数2.1 基本统计分析函数2.2 累计统计分析函数2.3 …

[附源码]计算机毕业设计JAVA学生量化考核管理系统

[附源码]计算机毕业设计JAVA学生量化考核管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

基于PHP+MySQL高校毕业设计管理系统的设计与实现

直以来我国领导人提倡以人为本的治国方案,而大学是未来人才的培养基地,如何能够更好的对高校毕业设计信息进行管理,是很多高校一直在研究的一个问题,只有更加科学的对高校毕业设计信息进行管理,才能够更加积极的培养国家的栋梁之才。 管理员部分功能 1&#xff1a;教师新管理…

第二十二章《记事本》第1节:记事本项目简介

记事本软件能够打开、编辑、保存各种类型的文本文档,也能在文本文档中查找特定的关键字,此外在还能设定文本文档的字体、字号以及风格等。 22.1.1记事本功能简介 记事本软件的运行结果如图22-1所示。 图22-1记事本软件界面 从图21-1可以看到:记事本程序运行开始后,在没有…

OpenFeign动态代理、源码分析

1、OpenFeign概述 OpenFeign 组件的前身是 Netflix Feign 项目&#xff0c;由 Netflix 公司开发。后来 Feign 项目被贡献给了开源组织&#xff0c;随后Feign退出历史舞台。 OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解&#xff0c;如RequestMapping等等。O…

基于springboot的家装平台设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

牛客练习赛106 三子棋

牛客练习赛106 三子棋 2022.12.02 题目描述 给定一个 333 \times 333 的棋盘&#xff0c;共有 3393 \times 3 9339 个格子&#xff0c;初始时每个格子均没有放置棋子。 A 和 B 轮流行动&#xff0c;每次行动的人&#xff0c;必须在当前棋盘上选择一个没有放置棋子的格子…

基于PHP+MySQL学生成绩管理系统的设计与实现

基于PHP的学生成绩管理系统主要高校内部提供服务,系统分为管理员,教师用户和学生用户三部分。 在基于PHP的学生成绩管理系统中分为管理员用户,教师用户和学生用户三部分,其中管理员用户主要是用来管理教师信息,学生信息,课程信息,专业信息和班级信息等内容,教师用户主要是用来管…

业务流程管理的未来趋势:个性化定制

自进入互联网时代以来、甚至更早&#xff0c;无论是从物质还是精神层面&#xff0c;“个性化”已经成为大众所普遍追求的东西。个性化定制允许买家按照自身偏好对产品进行二次改造&#xff0c;例如许多汽车品牌&#xff0c;就可以根据车主的想法来实现定制。 其实&#xff0c;…

Spring Boot 集成 EasyExcel 3.x 优雅实现Excel导入导出

Spring Boot 集成 EasyExcel 3.x 本章节将介绍 Spring Boot 集成 EasyExcel&#xff08;优雅实现Excel导入导出&#xff09;。 &#x1f916; Spring Boot 2.x 实践案例&#xff08;代码仓库&#xff09; 介绍 EasyExcel 是一个基于 Java 的、快速、简洁、解决大文件内存溢出的…

CSS盒子模型(上)

&#x1f353;个人主页&#xff1a;bit.. &#x1f352;系列专栏&#xff1a;Linux(Ubuntu)入门必看 C语言刷题 数据结构与算法 HTML和CSS3 目录 1.盒子模型 1.2盒子模型&#xff08;Box Model&#xff09;组成 1.3边框&#xff08;border&#xff09; 1.4 表格的…

这才是Git的正确学习方式

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store 你想要的&#xff0c;这里都有&#xff01; 我认为学习一门知识最怕的就是一知半解、草草了事&#xff0c;对于Git这种工具类更是如此。 有很多同学工作后&#xff0c;日常用到git clone、git add、g…

ubuntu18.04下cmake的安装

一.使用安装命令 sudo apt install cmake这种方式安装最为简单&#xff0c;但是&#xff0c;这种方式安装的不是最新版本的Cmake。 我此次安装cmake是因为要编译fastdds&#xff0c;其实之前系统中有cmake&#xff0c;但是在编译fastdds的过程中依然提示我&#xff1a; CMake…

第二证券|千亿巨头飙涨,消费板块掀起涨停潮!

消费板块复苏可期。 外围股市团体大反弹&#xff0c;隔夜纳斯达克指数大涨超4&#xff05;&#xff0c;标普500指数涨超3&#xff05;&#xff0c;道琼斯指数涨逾2%。跟着近两个月来的持续反弹&#xff0c;道琼斯指数自阶段底已反弹超20%&#xff0c;进入技术性牛市。早盘A股同…

留言墙项目【Vue3 + nodejs + express + mysql】——上

创建项目 如何使用 mddir 命令生成目录结构树 规范文件目录 ## 默认目录 |-- undefined|-- .gitignore|-- babel.config.js|-- jsconfig.json|-- package.json|-- README.md|-- vue.config.js|-- yarn.lock|-- 开发文档.md|-- public| |-- favicon.ico| |-- index.html|-…

[激光原理与应用-29]:典型激光器 -1- 固体激光器

目录 第1章 什么是固体激光器 1.1 什么是固体激光器 1.2 固体激光器特点 1.3 特性 1.4 分类 1.5 波长 第2章 固体激光器的组成 2.1 固体工作物质 2.2 激励源 第1章 什么是固体激光器 1.1 什么是固体激光器 用固体激光材料作为工作介质的激光器。 固体激光材料是在作…

老杨说运维 | 想转型的请注意!这几点不容忽视

随着各行各业数字化转型的持续推进&#xff0c;以及信息化建设的不断深入&#xff0c;IT系统规模及复杂程度日趋增长。据IDC预测&#xff0c;2021年中国金融行业IT支出规模&#xff08;包括&#xff1a;软件、硬件、IT服务等&#xff09;达到2186.02亿元&#xff0c;到2025年将…

Go-Excelize API源码阅读(三十九)——SetCellHyperLink

Go-Excelize API源码阅读&#xff08;三十九&#xff09;——SetCellHyperLink 开源摘星计划&#xff08;WeOpen Star&#xff09; 是由腾源会 2022 年推出的全新项目&#xff0c;旨在为开源人提供成长激励&#xff0c;为开源项目提供成长支持&#xff0c;助力开发者更好地了解…