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

这篇具有很好参考价值的文章主要介绍了element-ui实现一个动态布局的对话框。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 我把组件上传到npm了,具体使用方法请看:https://gitee.com/zengyanfang/tablelist-way/blob/master/README.md#%E5%8F%82%E6%95%B0

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

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

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

 当四个的时候

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

当大于四个的时候

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

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

 有些东西就是那么长,比如这个待缴费金额,光字就五个,如果它所在行搞成两个的话,就太狭小了,所以我除了组件灵活布局外,参数还可以配置是否独占一行,所以当自己可以设置独占一行的时候问题就来了,没有外界的干扰下,我组件布局的逻辑是,元素大于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 中文文档

好了,也没啥好说的了,最核心的就是那段判断是否独占一行的代码,另外自行扩展文章来源地址https://www.toymoban.com/news/detail-427212.html

到了这里,关于element-ui实现一个动态布局的对话框的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端css + js +vue +element-ui 实现响应式布局,根据浏览器窗体大小自动响应

    我的环境是element-ui vue版的,其他的也可以,主要是css和js的内容 首先在data中定义一个对象 其实就是css的样式,不过放在了js 里面而已 这里css设置了两个属性 一个是transform 这个属性对div标签的缩放作用,当浏览器窗口或者屏幕大小改变时,就调整这个属性的值,来等比缩放

    2024年02月13日
    浏览(46)
  • 解决 element-ui 中From 表单和Dialog 对话框搭配使用时 resetFields重置方法无法清空数据的问题

    在实际开发实现表格的增删改查的时候,新增和修改通常共用一个弹窗以节省代码量  当我们先点击修改的时候,会对弹窗表单进行赋值,这个时候我们再点击新增,会发现刚刚的表单数据仍然躺在表单中,并且使用resetFields没有清除数据 其实resetFields()是生效了的,resetFie

    2024年02月16日
    浏览(40)
  • element-ui实现动态添加表单项并实现事件触发验证验证

    需求分析:点击新增后新增一个月度活动详情,提交时可同时提交多个月度活动详情。点击某一个月度活动信息的删除后可删除对应月度活动信息 H5部分: 抽取H5部分的主要框架: js部分 页面中form数据对象声明 表单验证 完整demo 整体效果及功能: 删除某个月度活动:

    2024年02月03日
    浏览(29)
  • element-ui整体页面布局

    以上所有代码:

    2024年02月12日
    浏览(33)
  • element-UI Pagination 分页 布局,自定义布局

    分页左右布局,自定义布局 elm 分页默认布局是 左对齐的 我们这节要实现的效果是这样 (主要是拆分 分页每个一项) 两端对齐用的比较多 或者这样 直接上代码 主要通过 loyout 属性 如果你想要图2上的布局如上代码 你想要左中右布局图三效果 你需要用三个 el-pagination 只需要指

    2024年02月16日
    浏览(30)
  • VUE element-ui实现表格动态展示、动态删减列、动态排序、动态搜索条件配置、表单组件化。

        1、本组件支持列表的表头自定义配置,checkbox实现 2、本组件支持列表列排序,vuedraggable是拖拽插件,上图中字段管理里的拖拽效果 ,需要的话请自行npm install 3、本组件支持查询条件动态配置,穿梭框实现 https://download.csdn.net/download/askuld/88216937

    2024年01月16日
    浏览(48)
  • vue element-ui响应式布局(记录)

    1.可以实现Vue移动端和PC端的响应式布局适配 实现方法:通过 postcss-px-to-viewport 来自动将我们开发时的px单位计算转换为vw/rem视口单位,完成响应式布局 。 安装插件 PC端适配,在项目根目录下创建 postcss.config.js 配置文件 移动端适配,也是在根目录下创建 postcss.config.js 配置文件

    2024年02月11日
    浏览(26)
  • vue结合element-ui实现(按钮控制)动态增加减少input框功能。

    一、template部分 二、script部分 三、效果展示 这是初始页面  这是点击添加 这是删除的     四、详细说明 v-for=\\\"(item,index)in array\\\" :key = \\\"index\\\" 这个是重点!!! ! 通俗点将,就是用一个div(盒子)将input输入框包括起来,然后在div中使用 v-for=\\\"(item,index)in array\\\" :key = \\\"ind

    2024年02月12日
    浏览(47)
  • element-ui在下拉选项框中添加一个按钮,实现子选项的添加

    父组件 子组件

    2024年03月14日
    浏览(38)
  • Vue+element-ui的el-cascader实现动态添加删除级联地点输入框

    实现省市区三级地点级联选择,可联想; 包括始发地点、途径地点、终止地点,始发地点、终止地点均为一个,途径地点可以没有也可以是多个; 用户可以动态添加/删除途径地点。 使用级联选择器Cascader需要的树形数据,前端请求到后端获取省市区数据并处理为elementui官网

    2024年02月04日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包