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毫无成长。多尝试阅读源码,阅读源码不是目的,学会探究问题的本质才是终点。
- 加油 互勉。