效果如图,大部分功能和elment-ui差不多
新增type属性
type支持一些常用的正则匹配
number:数字
positiveNumber:正数
mobile:手机号
telephone:电话号
email:邮箱
webUrl:网址
Chinese:中文
IDcard:身份证
custom:自定义
当type属性为自定义时
你可以传入customReg属性(该属性必须是一个正则表达式)来实现自定义正则匹配
除了type参数
还新增了一个mustFill属性来表示该项是否为必填项,具体效果可以自己试试
拥有type属性的输入框可以自定义错误信息,你可以通过errorMsg来自定义错误提示信息
除此之外,我将输入框和搜索框拆分成了两个组件,因此本组件不支持搜索
下面是源码:
<-- zhInput.vue -->
<template>
<div class="zhInputCtn">
<!-- 前置元素 -->
<div class="zhInputPrepend"
v-if="$slots.prepend">
<slot name="prepend"></slot>
</div>
<div class="zhInputBox"
@mouseenter="hovering = true"
@mouseleave="hovering = false">
<input class="zhInput"
:class="{'typeError':!unShowError,'hasAppend':$slots.append,'hasPrepend':$slots.prepend}"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur"
@change="handleChange"
v-bind="$attrs"
ref="input" />
<div class="zhInputClose"
v-show="!($attrs.disabled===''|| $attrs.disabled) && clearable && (focused || hovering)"
@mousedown="clear">×</div>
</div>
<!-- 后置元素 -->
<div class="zhInputAppend"
v-if="$slots.append">
<slot name="append"></slot>
</div>
<!-- 错误信息 -->
<div class="zhErrorMsg right"
v-show="!unShowError && errorShow">{{errorMessage}}</div>
</div>
</template>
<script>
import './zhInput.less'
import { evil } from '../common.js'
export default {
props: {
value: [String, Number],
// 数据类型
type: {
type: String,
default: 'text'
},
// 数据类型为custom时生效,传入一个正则表达式
customReg: {
validator: function (value) {
if (!(evil(value) instanceof RegExp)) {
console.error('请传入正确的正则表达式')
}
return evil(value) instanceof RegExp
}
},
// 有type值生效
errorMsg: {
type: String
},
// 有type值生效
errorPosition: {
type: String,
default: 'bottom',
validator: function (value) {
return ['bottom', 'right'].indexOf(value) !== -1
}
},
// 是否展示错误信息
errorShow: {
type: Boolean,
default: true
},
// 是否必填项
mustFill: {
type: Boolean,
default: false
},
// 是否可清空
clearable: {
type: Boolean,
default: false
}
},
data () {
return {
focused: false,
unShowError: true,
errorMessage: '',
hovering: false
}
},
watch: {
// props value 突变触发更新
value (val) {
this.getInputDom().value = val === null || val === undefined ? '' : String(val)
}
},
computed: {
nativeInputValue () {
return this.value === null || this.value === undefined ? '' : String(this.value)
}
},
methods: {
getInputDom () {
return this.$refs.input
},
errorRegExp (val) {
// 非必填项忽略空值
if (this.type === 'number') {
this.unShowError = this.mustFill ? /^-?\d+\.?\d*$/.test(val) : !val || /^-?\d+\.?\d*$/.test(val)
} else if (this.type === 'positiveNumber') {
this.unShowError = this.mustFill ? /^(?:[1-9]\d*|0)(?:\.\d+)?$/.test(val) : !val || /^(?:[1-9]\d*|0)(?:\.\d+)?$/.test(val)
} else if (this.type === 'mobile') {
this.unShowError = this.mustFill ? /^1[3456789]\d{9}$/.test(val) : !val || /^1[3456789]\d{9}$/.test(val)
} else if (this.type === 'telephone') {
this.unShowError = this.mustFill ? /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/.test(val) : !val || /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/.test(val)
} else if (this.type === 'email') {
this.unShowError = this.mustFill ? /^\w+[@]\w{2,5}([.]\w{2,3}){1,3}$/i.test(val) : !val || /^\w+[@]\w{2,5}([.]\w{2,3}){1,3}$/i.test(val)
} else if (this.type === 'webUrl') {
this.unShowError = this.mustFill ? /[a-zA-z]+:\/\/[^\s]*/.test(val) : !val || /[a-zA-z]+:\/\/[^\s]*/.test(val)
} else if (this.type === 'Chinese') {
this.unShowError = this.mustFill ? /^[\u4e00-\u9fa5]{0,}$/.test(val) : !val || /^[\u4e00-\u9fa5]{0,}$/.test(val)
} else if (this.type === 'IDcard') {
this.unShowError = this.mustFill ? /^\d{15}|\d{18}$/.test(val) : !val || /^\d{15}|\d{18}$/.test(val)
} else if (this.type === 'custom') {
let reg = evil(this.customReg)
if (reg instanceof RegExp) {
this.unShowError = this.mustFill ? reg.test(val) : !val || reg.test(val)
}
}
},
// 输入触发父组件value更新
handleInput (ev) {
this.$emit('input', ev.target.value)
this.errorRegExp(ev.target.value)
},
handleChange (ev) {
this.$emit('change', ev.target.value)
},
handleFocus (ev) {
this.focused = true
this.$emit('focus', ev.target.value)
},
handleBlur (ev) {
this.focused = false
this.$emit('blur', ev.target.value)
// 输入值不符合时触发
if (!this.unShowError) {
this.$emit('errorInput', ev.target.value)
}
},
// 清空输入库
clear () {
this.$emit('input', '')
this.$emit('change', '')
this.$emit('clear')
this.errorRegExp()
}
},
mounted () {
// 初始化输入框
this.getInputDom().value = this.nativeInputValue
// 初始化errorMessage
if (this.type === 'number') {
this.errorMessage = this.errorMsg || '请输入数字!'
} else if (this.type === 'positiveNumber') {
this.errorMessage = this.errorMsg || '请输入正数!'
} else if (this.type === 'telephone') {
this.errorMessage = this.errorMsg || '请输入正确格式固话号!'
} else if (this.type === 'mobile') {
this.errorMessage = this.errorMsg || '请输入正确格式手机号!'
} else if (this.type === 'email') {
this.errorMessage = this.errorMsg || '请输入正确格式邮箱!'
} else if (this.type === 'webUrl') {
this.errorMessage = this.errorMsg || '请输入正确格式网址!'
} else if (this.type === 'Chinese') {
this.errorMessage = this.errorMsg || '请输入中文!'
} else if (this.type === 'IDcard') {
this.errorMessage = this.errorMsg || '请输入正确身份证号'
} else if (this.type === 'custom') {
let reg = evil(this.customReg)
if (reg instanceof RegExp) {
this.errorMessage = this.errorMsg || '请输入正确值'
}
}
this.errorRegExp(this.nativeInputValue)
}
}
</script>
//zhInput.less
.zhInputCtn{
height: 40px;
line-height: 40px;
display: inline-flex;
font-size: 14px;
position: relative;
.zhInputPrepend{
height: 40px;
padding: 0 12px;
background: #f5f7fa;
border:1px solid #dcdfe6;
border-right: 0;
box-sizing: border-box;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
.zhInputAppend{
height: 40px;
padding: 0 12px;
background: #f5f7fa;
border:1px solid #dcdfe6;
border-left: 0;
box-sizing: border-box;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
.zhInputBox{
height: 40px;
flex:1;
&:hover{
.zhInput{
border-color: #c0c4cc;
}
}
.zhInput{
height: 100%;
box-sizing: border-box;
font-size: inherit;
padding: 0px 15px;
border: 1px solid #dcdfe6;
border-radius: 2px;
&.hasAppend{
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
}
&.hasPrepend{
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
&:focus{
outline: none;
border-color: #1A95FF;
}
&:disabled{
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor: not-allowed;
}
&.typeError{
border-color: #F56C6C;
}
}
.zhInputClose{
cursor: pointer;
position: absolute;
top:0;
bottom: 0;
right: 12px;
font-size: 14px;
margin: auto 0;
width: 14px;
height: 14px;
text-align: center;
line-height: 14px;
border-radius: 50%;
&:hover{
color: #fff;
background: #1A95FF;
}
}
}
.zhErrorMsg{
font-size: 12px;
position: absolute;
color: #F56C6C;
white-space: nowrap;
font-weight: bold;
&.right{
left: 100%;
padding-left: 5px;
}
&.bottom{
top: 100%;
}
}
}
//common.js
// evil等同于eval方法,接收一个字符串转换成可执行的JavaScript代码,重写是为了躲避eslint检查
function evil (fn) {
var Fn = Function
return new Fn('return ' + fn)()
}
export {
evil
}