官网: https://baianat.github.io/vee-validate/
# install with npm
npm install vee-validate
# install with yarn
yarn add vee-validate
main.js 加入 VeeValidate 模块
import Vue from 'vue';
import VeeValidate from 'vee-validate';
Vue.use(VeeValidate);
<input type="username" v-validate="{required:true}" class="form-control" name="username" v-model="username" >
<span class="errorHint">{{errors.first("username")}}span>
效果: 当节点input[name='username']
为空时提示"The username field is required."
验证规则:
key | 参数 | 描述 |
required | true|false | 字段是否必须填写 |
is | 目标字段对象 | 当前字段与目标字段值是否相等 |
邮箱 | 验证邮箱格式 | |
date_format | 日期 | 验证日期格式 |
length | 字符串 | 长度必须等于XX |
min | 字符串 | 最小长度 |
max | 字符串 | 最大长度 |
min_value | 数字 | 最小值 |
max_value | 数字 | 最大值 |
regex | 正则表达式字符串 | 当前字段的值是否能通过正则验证 |
更多验证规则参见官网: https://baianat.github.io/vee-validate/guide/rules.html#after
本节阐述如何在http请求时,对返回的内容进行处理。 属于原理内容
服务端错误
{
"success": 30,
"message": "验证信息错误",
"data": {
"password": "密码不能为空",
"username": "用户名不能为空"
}
}
客户端请求示例:
httputil.post('/api/login/account',{username:this.username,password:this.password},{validate:{error:this.errors,validator:this.$validator}}).then((res) =>{
// 客户端对服务端返回对象的<>的处理
})
加入两个参数:{validate:{error:this.errors,validator:this.$validator}}
1. this.errors 用于添加服务端返回的异常
2. this.$validator 用于验证请求字段
以及 找到服务端返回的字段对应本地字段的id
客户端请求
// manager 组
<input type="text" class="form-control" v-validate="{required:'手机'}" data-vv-scope="manager" name="phone" v-model="changeManager.phone">
<span class="errorHint">{{errors.first("phone","manager")}}</span>
//password组
<input type="password" v-validate="{required:'原密码'}" data-vv-scope="password" class="form-control" name="password" v-model="password"/>
<span class="errorHint">{{errors.first("password","password")}}</span>
与基本使用的区别如下
1. 通过 data-vv-scope
指定验证分组
2. errors.first(nane字段,分组)
import cn from 'vee-validate/dist/locale/zh_CN';
import VeeValidate, { Validator } from 'vee-validate';
Validator.localize('cn', cn);
通过 Validator.localize 指定语言会覆盖默认的报错信息
在main.js 中 自定义错误信息
// 修改默认错误信息
const dict = {
cn: {messages: {
is: (name,param) =>{
if(param === null || param === undefined || param.length===0){
throw "验证字段的别名不存在:"+name;
}
return param[1];
}
}} // name接受alias的值.
}
Validator.localize(dict);
dict 对象说明:
1. cn 指定语言是中文
2. cn.messages 覆盖消息
3. cn.messages.is 当指定验证规则v-validate="{ is: confirmation }"
时, password和password_confirmation标签的内容不一致时,返回错误is的自定义错误信息
is 标签:
"{ is: [confirmation,'is的自定义错误信息'] }" type="text" name="password">
"confirmation" type="text" name="password_confirmation">
例如
Validator.localize('cn', cn);
Validator.localize(dict);
http.js 请求封装
import Vue from 'vue'
import api from '../../config/api'
import router from '../router'
// 中断信号类
class HttpBreakPromise{
constructor(){}
}
//删除undifined对象
function deleteEmptyProperty(object){
for (var i in object) {
var value = object[i];
if (typeof value === 'object') {
if (Array.isArray(value)) {
if (value.length == 0) {
delete object[i];
continue;
}
}
deleteEmptyProperty(value);
if (isEmpty(value)) {
delete object[i];
}
} else {
if (value === '' || value === null || value === undefined) {
delete object[i];
} else {
}
}
}
}
function isEmpty(object) {
for (let name in object) {
return false;
}
return true;
}
// 客户端本地验证
const validateSimpleFilter = (info)=> {
if(!info || !info.validate){
return Promise.resolve();
}
let validator = info.validate.validator;
let errors = info.validate.error;
let scope = info.validate.scope;
scope = scope ? scope + ".*" : '*';
return validator.validate(scope).then((descriptor, value, options) => {
if (!descriptor) {
throw "验证错误";
}
})
}
// 服务端返回内容验证
const validateFilter = (promise,info)=>{
if(!info || !info.validate){
return promise;
}
let validator = info.validate.validator;
let errors = info.validate.error;
let scope = info.validate.scope;
scope = scope?scope+".*":'*';
return validator.validate(scope).then((descriptor, value, options)=>{
if(!descriptor){
throw "验证错误";
}
}).then(()=>{
mask(promise,info);
return promise.then(res=>{
if(res.success !== 30){
// 只针对状态码为30的,进行错误值绑定
return res;
}
let resData = res.data;
errors.clear();
let fields = validator.fields;
for(let eIndex in resData){
let findItem = fields.find({name:eIndex});
let errorObj = {
field: eIndex,
msg: resData[eIndex],
id: findItem.id
};
errors.add(errorObj)
}
return res;
});
})
}
// 请求处理器
const requestHandler=(promise,info)=>{
// 添加遮罩
mask(promise,info);
//服务端返回验证
validateFilter(promise,info)
//登录过滤器
loginFilter(promise,info);
// 返回值 处理
return resultFilter(promise,info);
}
// 遮罩
const mask = (promise,info)=>{
var index = layer.load(2, {content:'加载中...',success: function(layero){
layero.find('.layui-layer-content').css({'padding-top':'50px',"text-align":"center","width":"100px","background-position": "34px 12px","background-color": "white","box-shadow": "0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12)","border-radius": "6px","height":"85px"});
}
})
return promise.then(res=>{
//获得结果后,弹出遮罩
let toast = info ? info.toast:{};
let result = res.body;
if (result.success === 20) {
if(toast&&toast.success){
layer.msg(toast.success, {
icon: 1,
shade: 0.2,
scrollbar: false,
shadeClose:true
});
}
}else{
if(toast&&toast.fail){
layer.msg(toast.fail, {
icon: 2,
shade: 0.2,
scrollbar: false,
shadeClose:true
});
}
}
//获得结果后,删除遮罩
layer.closeAll('loading')
})
}
// 返回值过滤器
const resultFilter = (promise,info) => {
return promise.then(res => {
let result = res.body;
if(result.success!==20){
throw new HttpBreakPromise();
// Promise.break; ES6 原生 不提供 Promise.break; 形式中断promise调用链。
// 只能抛出异常,在调用者那边处理异常
}
if(info && info.allObj){
return result;
}
return result.data
}).catch((err)=>{
//加入HTTP调试错误
console.log("http调试错误:",err);
return new Promise((resolve, reject)=>{});
});
}
const loginFilter = (promise,info)=>{
return promise.then(function(response){
layer.closeAll('loading')
let success = response.body.success;
if(success===900){
layer.msg("登录已过期", {
icon: 2,
shade: 0.2,
scrollbar: false,
shadeClose:true,
time:2000
})
router.push('/');
return response;
}
var errorType=info&&info.error;
if(errorType && success!==20){
router.push('/error/error');
}
return response;
})
}
const info= {toast :{},allObj:false,page:{}}
const httputil = {
name:"httputil",
get(url = {},params = {},info = info) {
if(info&&info.page){
params = $.extend({},{currentPage:info.page.currentPage,showCount:info.page.showCount},params);
}
// delete info.error
deleteEmptyProperty(params);
return validateSimpleFilter(info).then(()=>{
return requestHandler(Vue.http.get(api.BASE_URL + url,{params:params,withCredentials: true}),
info);
});
},
post(url = {}, params = {},info= info) {
return validateSimpleFilter(info).then(()=>{
return requestHandler(Vue.http.post(api.BASE_URL + url, params,{withCredentials: true})
,info);
})
},
put(url = {}, params = {},info= info) {
return validateSimpleFilter(info).then(()=>{
return requestHandler(
Vue.http.put(api.BASE_URL + url, params, {withCredentials: true})
,info);
})
},
delete(url = {}, params = {},info= info) {
return validateSimpleFilter(info).then(()=>{
return requestHandler(
Vue.http.delete(api.BASE_URL + url, {body:params},{withCredentials: true})
,info);
})
},
}
export default httputil;