怎么个百变法呢,就是做一个组件,可以实现 input 的各种形态。
原生input的类型
先整理一下 input 的 type 都提供了哪些类型。
原:HTML5之前的类型。
新:HTML5提供的新的类型。
这里没有写 radio 和 checkbox,因为这两个被我划分为选择类型,同理还有submit。
我们可以依据这个类型定义一个属性:
const type = {
100: 'textarea', // 多行文本框
101: 'text', // 单行文本框
102: 'password', // 密码
103: 'tel', // 电话
104: 'email', // 电子邮件
105: 'url', // url
106: 'search', // 搜索
107: 'color', // 颜色
108: 'text', // 弹窗选择记录
110: 'date', // 日期
111: 'datetime-local', // 日期时间
112: 'time', // 时间
113: 'week', // 年月
114: 'month', // 年周
120: 'number', // 数字
121: 'range', // 滑块
130: 'file', // 上传文件
131: 'file', // 上传图片
140: 'fulltext', // 富文本编辑器
150: 'checkbox', // 勾选
152: 'checkboxs', // 多选组
153: 'radios', // 单选组
170: 'select', // 下拉列表框 单选
171: 'selects', // 列表框 多选
172: 'selectMore' // 联动下拉列表框
}
具体使用方式下面说。
依据 input 的属性定义一个对象
然后我把可以把input的其他属性整理出来做一个对象:
const meta = reactive({
controlId: 1000,
colName: 'companyName',
controlType: 101,
isClear: true,
disabled: false,
required: true,
readonly: false,
pattern: '',
class: '',
placeholder: '请输入公司名称',
title: '公司名称',
autocomplete: 'on',
size: 30,
maxlength: 100,
optionList: [],
tdCount: 1
})
准备工作做好了,我们开始做组件。
做一个多功能的 文本类 控件
模板部分
<template>
<!---->
<input :id="'c' + meta.controlId"
:type="type[meta.controlType]"
:name="'c' + meta.controlId"
:value="modelValue"
:disabled="meta.disabled"
:readonly="meta.readonly"
:class="meta.class"
:placeholder="meta.placeholder"
:title="meta.title"
:size="meta.size"
:maxlength="meta.maxlength"
:autocomplete="meta.autocomplete"
:list="meta.optionKey"
@input="myInput"
:key="'ckey_'+meta.controlId">
<!--文本框的备选项-->
<datalist v-if="typeof(meta.optionKey)!=='undefined'" :id="meta.optionKey">
<option :key="item.value" v-for="item in meta.optionList" :label="item.title" :value="item.value" />
</datalist>
</template>
这个比较简单,就是把 input 具有的属性都给绑定上。
这里要感谢vue的数据绑定功能,没有设置的属性会自动省略,这就不用我们一个一个判断是不是 undefined 了。
代码部分
export default {
name: 'nf-h5-form-text',
props: {
modelValue: String,
meta: metaInput
},
emits: ['input'],
setup (props, context) {
console.log(props)
// 提交数据
const myInput = (e) => {
console.log(e)
console.log(context)
context.emit('update:modelValue', e.target.value)
}
return {
type,
myInput
}
}
}
这个比较简单了,设计两个属性,一个是 modelValue 绑定 input 的 value 的。
另一个是 meta,后面跟了一个 metaInput ,这个就是上面整理的 input 的属性对象,在组件的属性里面,改成了带验证的形式。
// 定义属性
const metaInput = {
type: Object,
default: () => {
return {
// 通用
controlId: Number, // 编号,区别同一个表单里的其他控件
colName: String, // 字段名称
controlType: Number, // 用类型编号表示type
isClear: {
// isClear 连续添加时是否恢复默认值
type: Boolean,
default: false
},
defaultValue: String, // 默认值
autofocus: { // 是否自动获得焦点
type: Boolean,
default: false
},
disabled: {
// 是否禁用
type: Boolean,
default: false
},
required: { // 必填
type: Boolean,
default: true
},
readonly: { // 只读
type: Boolean,
default: false
},
pattern: String, // 用正则做验证。
class: {
type: String,
default: 'ant-input ant-input-sm'
},
placeholder: String,
title: String, // 提示信息
size: Number, // 字符宽度
maxlength: Number, // 最大字符数
autocomplete: { // off
type: String,
default: 'on'
},
optionKey: String, // 备选文字标识
optionItem: Object // 备选的选项
}
}
}
这种方式,不仅可以定义组件的属性,而且还能对属性做类型限制、设置默认值等功能。
这样可以让属性设置的更严谨一些。
如果父组件里面设置属性不符合要求,那么浏览器里面会给出来警告提示。
设计目的
为什么要这么设计呢?因为表单里面的元素是各种各样的,比如文本、日期、选择等等,一般需要一个一个写,即是是使用UI库里的form,也还是需要进行具体属性设置。
这个就有点郁闷了,说好的数据绑定呢?
我比较懒,对于这种需要一行一行写的情况比较厌恶,那么能不能简单一点呢,比如使用v-for进行循环?
想要循环,那么就必须规范接口,也就是属性和事件,这两个统一之后我们就可以进行循环了。
如果可以循环的话,那么再大的表单也不用担心了,一个循环搞定。
这里只是处理了一下文本类的控件,后面还要处理选择类的控件,还有其他控件。一路封装下来,最后就可以实现v-for的目的了。
网友评论