源码:https://gitee.com/chenxiangzhi/components.git
历史文章:
效果
- 失去焦点时会进行校验
- 更新数据后会传回一个对象,包含
name
和value
使用
<template>
<s-input
@update="updateForm"
name="ip"
:value="state.ip"
:rules="[
{ type: 'required', message: 'ip不能为空' },
{ type: 'ip', message: 'ip格式不对' },
]"
/>
</template>
<script lang="ts" setup>
import { reactive } from "vue"
import { SInput } from "@/components"
const state = reactive({
ip: ""
})
const updateForm = (param) => {
state[param.name] = param.value
}
</script>
校验规则传的是一个数组,里面每个元素包含
type
校验种类与message
校验失败时的提示说明。每个type
校验种类将对应于一个校验函数,这由自己自定义。
Types
// 属性
type InputProp={
type: string, // 输入框类型
name: string,
value: string|number|boolean,
placeholder?: string,
rules?: RuleProp[], // 校验规则
inputStyle: Object // 输入框样式
}
// 校验类型:每个校验类型会对应一个校验函数。
type RuleKeys = "required" | "ip" | "port" | "range";
interface IRuleStrategies {
[index in RuleKeys]: (...params: any[]) => boolean;
[index: string]: (...params: any[]) => boolean;
}
// 校验对象
interface RuleProp {
type: RuleKeys;
message: string;
}
SInput
<template>
<div class="input-container">
<input
:type="type"
class="input-control"
@blur="testError"
:value="value"
@input="input"
:class="{ 'is-invalid': inputRef.error }"
:placeholder="placeholder"
:style="{...inputStyle }"
/>
<div v-if="inputRef.error" class="error-text">
{{ inputRef.message }}
</div>
</div>
</template>
<script lang="ts" setup>
import { PropType, reactive } from "vue"
import { RuleProp } from "@types"
import { ruleStrategies } from "@/utils"
const emitFn = defineEmits(["update"])
const props = defineProps({
type: {
type: String,
default: "text"
},
name: String,
value: [String, Number, Boolean],
placeholder: String,
rules: Array as PropType<RuleProp[]>,
inputStyle: Object
})
// 响应式错误信息
const inputRef = reactive({
error: false,
message: ""
})
// 检查错误
const testError = () => {
if (props.rules) {
// 对所有校验规则进行校验,只要有一个不通过就为不通过
const allPassed = props.rules.every((rule: RuleProp) => {
let passed = true
// 首先将错误说明赋值给响应式对象inputRef
inputRef.message = rule.message
// 接着在校验函数中找到对应的校验函数进行校验
passed = ruleStrategies[rule.type](props.value) // 根据校验类型判断是否通过
return passed
})
// 主要有不通过的,就会显示错误信息
inputRef.error = !allPassed
}
}
// 传回数据
const input = (e: Event) => {
const targetValue = (e.target as HTMLInputElement).value
emitFn("update", { name: props.name, value: targetValue }) // 传回一个对象
}
</script>
<style lang="less">
.input-container {
.input-control{
padding: 4px 10px;
border-radius: @smallRadius;
border: 1px solid @borderColor;
align-items: center;
font-size: 1em;
&:focus{
border: 1px solid @activeColor;
outline: 2px solid @mainColor;
}
}
.error-text{
padding:6px 0 0 1px;
color:@danger;
text-align:left;
}
}
</style>
校验函数
import {IRuleStrategies} from '@types'
// 判断是否为空
const isRequired=(val:string):boolean=>{
return val!== ""
}
// 判断是否为整数
const isInteger=(value:any)=>{
return Number.isInteger(Number(value))
}
// 判断是否为ip
const isIp=(ip:string):boolean=>{
var rep = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
return rep.test(ip)
}
// 判断端口是否合法
const isPort=(port:number):boolean=>{
if(!isInteger(port)||65535<port||port<1){
return false;
}
return true;
}
// 判断整数范围
const isInRange:number,max:number=20,min:number=-10):boolean=>{
if(!isInteger(value)||value>max||min<-10){
return false
}
return true
}
// 导出校验策略
export const ruleStrategies:IRuleStrategies={
"required":isRequired,
"ip":isIp,
"port":isPort,
"range":isInRange
}