效果如圖,大部分功能和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
}