自定义 cube-ui 弹出框dialog支持多个且多种类型的input框

start

  • 最近遇到一个需求,给一个移动端项目加一点小功能。
  • 移动端 UI 组件库使用的是 cube-ui。
  • 但是基础的 cube-ui 不太满足我的需求…
  • 重点是记录一下我的思路,其次才是实现的代码。

1. 需求

需要点击按钮弹出一个弹出框,然后再弹出框中可以输入内容,点击确定的时候,调用接口保存。

原生的 cube-ui 仅支持一个输入框,而且这个输入框类型不可控

我接到的需求呢,是支持多个输入框,且输入框类型还不一样。

基础cube-ui的prompt弹出框效果如下图:
在这里插入图片描述

2. 寻找解决方案

cube-ui是支持插槽的,具体的代码中createElement这个函数结构有点类似于h函数。

通过这个插槽插入文字图片什么的还是可以的。

我如果通过这个函数,向对话框中,插入几个input框。第一有点麻烦。第二可操作性有点低。

基础cube-ui的弹出框-插槽 代码以及效果如下图:
在这里插入图片描述

3. 最终的解决方案

正当我思索的时候,我突发奇想,先看看它的对话框源码是怎么写的。

cube-ui的dialog源码
在这里插入图片描述

看了一眼他的源码之后,我有解决方案了。他的源码无非就是一个vue组件。我直接cv一套出来,自己加一些自己的额外定制化配置,这样不就可以符合我的需求了?

4.结果

自定义的 基于 cube-ui的一个对话框

<template>
  <transition name="cube-dialog-fade">
    <cube-popup
      ref="selfPopup"
      type="self-dialog"
      :z-index="zIndex"
      :mask="true"
      :center="true"
      @mask-click="maskClick"
      @click.stop="say()"
    >
      <div class="self-dialog-main cube-dialog-main" @click.stop="say()">
        <!-- <span v-show="showClose" class="cube-dialog-close">
          <i class="cubeic-close"></i>
        </span> -->
        <div :class="containerClass">
          <h2 v-if="title || $slots.title" class="cube-dialog-title">
            <slot name="title">
              <p class="cube-dialog-title-def">
                {{ title }}
              </p>
            </slot>
          </h2>
          <div class="cube-dialog-content">
            <slot name="content">
              <div v-if="promptList && promptList.length > 0" class="cube-dialog-content-def">
                <div v-for="(item, index) in promptList" :key="index">
                  <div>
                    {{ item.label }}
                  </div>

                  <div v-if="item.type === 'text' || item.type === 'number'">
                    <cube-input
                      v-model="item.value"
                      :type="item.type"
                      :placeholder="item.placeholder"
                    />
                  </div>

                  <div v-if="item.type === 'select'">
                    <cube-input
                      v-model="item.value"
                      :type="item.type"
                      :placeholder="item.placeholder"
                      :readonly="true"
                      @focus="showPicker(item, index)"
                    />
                  </div>
                </div>
              </div>
            </slot>
          </div>
          <div class="cube-dialog-btns" :class="{ 'border-right-1px': isConfirm || isPrompt }">
            <slot name="btns">
              <a
                v-if="isConfirm || isPrompt"
                :href="cancelBtn.href"
                class="cube-dialog-btn border-top-1px"
                :class="{
                  'cube-dialog-btn_highlight': cancelBtn.active,
                  'cube-dialog-btn_disabled': cancelBtn.disabled
                }"
                @click="cancel"
              >
                {{ cancelBtn.text }}
              </a>
              <a
                :href="confirmBtn.href"
                class="cube-dialog-btn border-top-1px"
                :class="{
                  'cube-dialog-btn_highlight': confirmBtn.active,
                  'cube-dialog-btn_disabled': confirmBtn.disabled
                }"
                @click="confirm"
              >
                {{ confirmBtn.text }}
              </a>
            </slot>
          </div>
        </div>
      </div>
    </cube-popup>
  </transition>
</template>

<script>
export default {
  props: {
    zIndex: {
      type: Number,
      default: 100
    },
    type: {
      require: true,
      type: String,
      default: 'prompt'
    },
    title: {
      type: String,
      default: ''
    },
    promptList: {
      type: Array,
      default() {
        return []
      }
    },
    cancelBtn: {
      type: Object,
      default() {
        return {
          href: 'javascript:;',
          active: false,
          disabled: false,
          text: '关闭'
        }
      }
    },
    confirmBtn: {
      type: Object,
      default() {
        return {
          href: 'javascript:;',
          active: true,
          disabled: false,
          text: '确认'
        }
      }
    }
  },
  data() {
    return {}
  },
  computed: {
    containerClass() {
      return `cube-dialog-${this.type}`
    },
    isPrompt() {
      return this.type === 'prompt'
    },
    isConfirm() {
      return this.type === 'confirm'
    }
  },
  methods: {
    show() {
      this.$refs.selfPopup.show()
    },
    hide() {
      this.$refs.selfPopup.hide()
    },
    maskClick(e) {
      this.maskClosable && this.cancel(e)
    },
    confirm(e) {
      if (this.confirmBtn.disabled) {
        return
      }
      this.$emit('EVENT_CONFIRM', e, this.promptValue)
    },
    cancel(e) {
      if (this.cancelBtn.disabled) {
        return
      }
      this.$refs.selfPopup.hide()
      this.$emit('EVENT_CANCEL', e)
    },
    close(e) {
      this.$refs.selfPopup.hide()
      this.$emit('EVENT_CLOSE', e)
    },

    showPicker(item, index) {
      this.picker = this.$createPicker({
        title: item.label,
        data: [item.column],
        onSelect: (value, i, text) => {
          this.promptList[index].value = text[0]
          this.promptList[index].key = value[0]
        }
        // onCancel: this.cancelHandle
      })
      this.picker.show()
    },
    say() {}
  }
}
</script>

<style>
.self-dialog-main .cube-input {
  border: 0.071429rem solid #ebebeb !important;
}
.self-dialog-main .cube-input-field {
  padding: 0.714286rem !important;
}
</style>

主要差异
在这里插入图片描述

主要差异就是对cube-dialog-content的内容进行了扩展,支持传入配置文件进行扩展。其次就是做了一下样式兼容以及点击事件的处理。

演示一下传入的 额外配置文件

 [
  {
      type: 'number',
      value: '',
      require: true,
      label: '数量',
      placeholder: '数量',
      rules: {
        positiveInteger: true // 正整数
      }
    },
    {
      type: 'select',
      value: '',
      key: '',
      label: '原因',
      require: true,
      placeholder: '请选择原因',
      column: [
        { text: '破损', value: 'A' },
        { text: '丢失', value: 'B' },
        { text: '其他', value: 'C' }
      ]
    },
    {
      type: 'text',
      value: '',
      label: '其他',
      placeholder: '请输入'
    }
  ]

end

  • 当然可能目前认知有限,这个可能不是最优解。
  • 但是这也是一个可以借鉴的思路,基于原本的ui组件,二次创作,满足定制化需求,也不是不可以。
  • 其实我更想说的一个想法是什么,不要仅限于去使用ui框架。总是cv毫无成长。多尝试阅读源码,阅读源码不是目的,学会探究问题的本质才是终点。
  • 加油 互勉。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lazy_tomato

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值