├── .npmignore ├── .gitignore ├── tsconfig.json ├── src ├── types.ts ├── error-message-template.ts ├── rules.ts ├── error-message.ts ├── component.ts └── index.ts ├── README.md ├── package.json └── yarn.lock /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | node_modules 3 | .idea 4 | dist 5 | types 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "moduleResolution": "node", 5 | "target": "ES5", 6 | "lib": ["dom", "es6"], 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "declaration": true, 10 | "declarationDir": "./types/", 11 | "outDir": "./dist" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type RuleGetter = (ruleVal?: any) => object; 2 | export type ErrorMessageTemplate = { 3 | empty: string; 4 | length: string; 5 | minLength: string; 6 | number: string; 7 | int: string; 8 | lt: string; 9 | lte: string; 10 | gt: string; 11 | gte: string; 12 | maxDecimalLength: string; 13 | phone: string; 14 | email: string; 15 | verifyCode: string; 16 | [name: string]: string; 17 | }; 18 | -------------------------------------------------------------------------------- /src/error-message-template.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | empty: "请补充该项内容", 3 | length: "请输入{length}位字符", 4 | minLength: "输入内容至少{minLength}位", 5 | number: "请输入数字", 6 | int: "请输入整数", 7 | lt: "输入内容应小于{lt}", 8 | lte: "输入内容不能大于{lte}", 9 | gt: "输入内容应大于{gt}", 10 | gte: "输入内容不能小于{gte}", 11 | maxDecimalLength: "该输入项最多接受{maxDecimalLength}位小数", 12 | phone: "请输入正确的手机号", 13 | email: "请输入正确的邮箱", 14 | verifyCode: "请输入正确的验证码" 15 | }; 16 | -------------------------------------------------------------------------------- /src/rules.ts: -------------------------------------------------------------------------------- 1 | import { RuleGetter } from "./types"; 2 | export type RuleGetters = { [name: string]: RuleGetter }; 3 | const getters: RuleGetters = {}; 4 | function rules(): RuleGetters; 5 | function rules(name: string, getter?: RuleGetter): RuleGetter; 6 | function rules(name?: string, getter?: RuleGetter): any { 7 | if (!name) return getters; 8 | if (getters[name] && getter) 9 | throw Error(`the rule name '${name}' has been used`); 10 | if (getter) getters[name] = getter; 11 | return getters[name]; 12 | } 13 | export default rules; 14 | -------------------------------------------------------------------------------- /src/error-message.ts: -------------------------------------------------------------------------------- 1 | import { ErrorMessageTemplate } from "./types"; 2 | 3 | let template: ErrorMessageTemplate; 4 | type MacroMap = { [macro: string]: string }; 5 | 6 | function createMacroMap(macro: string, value: any): MacroMap { 7 | const obj: any = {}; 8 | obj[macro] = value; 9 | return obj; 10 | } 11 | 12 | export default { 13 | setTemplate(errorMessageTemplate: ErrorMessageTemplate) { 14 | template = errorMessageTemplate; 15 | }, 16 | macroToValue(msg: string, macro: string, value: any): string { 17 | const reg = new RegExp(`{${macro}}`, "g"); 18 | return msg.replace(reg, value); 19 | }, 20 | get(name: string, templateData?: any): string { 21 | let msg = template[name]; 22 | if (!msg) 23 | throw Error(`can't get the value of errorMessageTemplate['${name}']`); 24 | if (arguments.length === 1) return msg; 25 | if (typeof templateData !== "object") 26 | templateData = createMacroMap(name, templateData); 27 | for (let macro in templateData) 28 | msg = this.macroToValue(msg, macro, templateData[macro]); 29 | return msg; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # element-ui-verify 2 | 3 | 如果你受够了饿了么 ElementUI 原生的校验方式,那就来试试它吧! 4 | 5 | ## 前言 6 | 7 | 饿了么 ElementUI 虽好,但表单校验的体验不够理想 8 | 9 | 如果说产品开发要讲究用户体验,那插件开发也要讲究开发体验,而好的开发体验,要靠好的 api 设计来保障 10 | 11 | 本人专注校验插件开发 30 年,有祖传的校验插件 api 设计(玩笑)。主要是参考了之前写的[vue-verify-pop](https://github.com/aweiu/vue-verify-pop)的 api,并加以完善,取其精华,去其糟粕,揉和日月之精华。。。 12 | 13 | 本插件只是对 ElementUI 原本的校验方式做了一层封装,核心的校验器仍然是[async-validator](https://github.com/yiminghe/async-validator),非侵入式,完全不会影响你继续使用 ElementUI 的原生校验 14 | 15 | ## 示例 16 | 17 | ```html 18 | 25 | 36 | ``` 37 | 38 | ok,你已经完成了一个内容为大于 0 的整数校验!([欢迎对比官方版的相似例子](http://element-cn.eleme.io/#/zh-CN/component/form#shu-zi-lei-xing-yan-zheng)) 39 | 40 | ## 文档 41 | 42 | https://aweiu.com/documents/element-ui-verify/ 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "element-ui-verify", 3 | "version": "1.2.6", 4 | "description": "如果你受够了饿了么ElementUI原生的校验方式,那就来试试它吧!一款更懂你的校验插件", 5 | "keywords": [ 6 | "vue", 7 | "element", 8 | "element-ui", 9 | "elementUi", 10 | "elementUI", 11 | "element-ui-validator", 12 | "element-ui-verification", 13 | "element-ui-check" 14 | ], 15 | "main": "dist/index.js", 16 | "typings": "types/index.d.ts", 17 | "scripts": { 18 | "build": "tsc" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/aweiu/element-ui-verify.git" 23 | }, 24 | "author": "aweiu", 25 | "license": "ISC", 26 | "bugs": { 27 | "url": "https://github.com/aweiu/element-ui-verify/issues" 28 | }, 29 | "homepage": "https://github.com/aweiu/element-ui-verify#readme", 30 | "dependencies": { 31 | "vue-property-decorator": "^6.0.0" 32 | }, 33 | "peerDependencies": { 34 | "element-ui": ">=1.1.1", 35 | "vue": "^2.3.0" 36 | }, 37 | "devDependencies": { 38 | "element-ui": "^2.0.10", 39 | "prettier": "^1.18.2", 40 | "typescript": "^2.6.2", 41 | "vue": "^2.5.13" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/component.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import { FormItem } from "element-ui"; 3 | import rules from "./rules"; 4 | import errorMessage from "./error-message"; 5 | import { Component, Prop, Watch } from "vue-property-decorator"; 6 | 7 | // 引用一份,解决某些环境下调用了全局Vue.mixin后再调用原FormItem下的方法会造成调用栈溢出 8 | const ElFormItemMethods: { [methodName: string]: Function } = (FormItem as any) 9 | .methods; 10 | @Component 11 | export default class ElFormItemVerifyComponent extends Vue { 12 | static fieldChange: "verify" | "clear"; 13 | @Prop([String, Function]) 14 | verify?: string | Function; 15 | @Prop() 16 | canBeEmpty?: string; 17 | @Prop() 18 | space?: string; 19 | @Prop() 20 | emptyMessage?: string; 21 | @Prop() 22 | errorMessage?: string; 23 | @Prop() 24 | alias?: string; 25 | @Prop() 26 | watch: undefined; 27 | @Prop() 28 | fieldChange?: string; 29 | 30 | // watch某值并修改该值本身会额外触发一次,性能影响不大,暂不做过滤了。后期可能会用其它方式拦截 31 | @Watch("validateMessage") 32 | onValidateMessageChanged(msg: string) { 33 | if (this._verify && msg !== "") { 34 | const alias = this.alias || (this as any).label || "该输入项"; 35 | (this as any).validateMessage = errorMessage.macroToValue( 36 | (this as any).validateMessage, 37 | "alias", 38 | alias 39 | ); 40 | } 41 | } 42 | 43 | @Watch("watch") 44 | onWatchChanged() { 45 | if (this._verify) (this as any).validate(""); 46 | } 47 | 48 | get _verify(): boolean { 49 | return this.verify !== undefined && (this as any).prop; 50 | } 51 | 52 | getRules(): any[] { 53 | if (!this._verify) return ElFormItemMethods.getRules.apply(this, arguments); 54 | let asyncVerifyRules: any[] = []; 55 | // 空检测 56 | let fieldValue = (this as any).fieldValue; 57 | fieldValue = 58 | [undefined, null].indexOf(fieldValue) === -1 ? fieldValue + "" : ""; 59 | if (this.space === undefined) fieldValue = fieldValue.trim(); 60 | if (fieldValue === "") { 61 | asyncVerifyRules.push({ 62 | validator: (rule: any, val: any, callback: Function) => { 63 | if (this.canBeEmpty !== undefined || (this as any).minLength <= 0) 64 | callback(); 65 | else callback(Error(this.emptyMessage || errorMessage.get("empty"))); 66 | } 67 | }); 68 | } else { 69 | // 合并普通规则 70 | const ruleGetters = rules(); 71 | for (let name in ruleGetters) { 72 | const ruleVal = (this as any)[name]; 73 | if (ruleVal !== undefined) 74 | asyncVerifyRules = asyncVerifyRules.concat( 75 | ruleGetters[name](ruleVal) 76 | ); 77 | } 78 | // 统一处理错误提示(代码块放在此处可以只针对普通规则) 79 | if (this.errorMessage !== undefined) { 80 | for (let rule of asyncVerifyRules) 81 | (rule as any).message = this.errorMessage; 82 | } 83 | // 自定义校验方法置后 84 | if (typeof this.verify === "function") 85 | asyncVerifyRules.push({ validator: this.verify }); 86 | // 当规则为空时,返回一个始终通过的规则来避免空检测错误无法清除 87 | // 也可以通过(this as any).clearValidate()的方式实现,不过不太好 88 | if (asyncVerifyRules.length === 0) { 89 | asyncVerifyRules.push({ 90 | validator(rule: any, val: any, callback: Function) { 91 | callback(); 92 | } 93 | }); 94 | } 95 | } 96 | // 使elementUI可以检测到必填项从而展示*号 97 | asyncVerifyRules[0].required = this.canBeEmpty === undefined; 98 | return asyncVerifyRules; 99 | } 100 | 101 | // 兼容<2.0.0-beta.1 102 | clearValidate() { 103 | if (ElFormItemMethods.clearValidate) { 104 | ElFormItemMethods.clearValidate.apply(this, arguments); 105 | } else { 106 | (this as any).validateState = ""; 107 | (this as any).validateMessage = ""; 108 | (this as any).validateDisabled = false; 109 | } 110 | } 111 | 112 | onFieldChange() { 113 | const fieldChange = 114 | this.fieldChange || ElFormItemVerifyComponent.fieldChange; 115 | if (!this._verify || fieldChange !== "clear") 116 | ElFormItemMethods.onFieldChange.apply(this, arguments); 117 | else if (this._verify && fieldChange === "clear") this.clearValidate(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | async-validator@~1.8.1: 6 | version "1.8.5" 7 | resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-1.8.5.tgz#dc3e08ec1fd0dddb67e60842f02c0cd1cec6d7f0" 8 | integrity sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA== 9 | dependencies: 10 | babel-runtime "6.x" 11 | 12 | babel-helper-vue-jsx-merge-props@^2.0.0: 13 | version "2.0.3" 14 | resolved "https://registry.yarnpkg.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6" 15 | integrity sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg== 16 | 17 | babel-runtime@6.x: 18 | version "6.26.0" 19 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 20 | integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= 21 | dependencies: 22 | core-js "^2.4.0" 23 | regenerator-runtime "^0.11.0" 24 | 25 | core-js@^2.4.0: 26 | version "2.6.9" 27 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" 28 | integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== 29 | 30 | deepmerge@^1.2.0: 31 | version "1.5.2" 32 | resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" 33 | integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== 34 | 35 | element-ui@^2.0.10: 36 | version "2.11.1" 37 | resolved "https://registry.yarnpkg.com/element-ui/-/element-ui-2.11.1.tgz#2b67f9eee3eda2e6884873c1c589cbe30d9a9d60" 38 | integrity sha512-PACNMHPWqm+/Wc2f/q93pLNzbNyVbpMCXCrYe81czengSWj7IBku7F3zccybkxtWn5qdCmMDBCpG5BzGJL4rKA== 39 | dependencies: 40 | async-validator "~1.8.1" 41 | babel-helper-vue-jsx-merge-props "^2.0.0" 42 | deepmerge "^1.2.0" 43 | normalize-wheel "^1.0.1" 44 | resize-observer-polyfill "^1.5.0" 45 | throttle-debounce "^1.0.1" 46 | 47 | normalize-wheel@^1.0.1: 48 | version "1.0.1" 49 | resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45" 50 | integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU= 51 | 52 | prettier@^1.18.2: 53 | version "1.18.2" 54 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" 55 | integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== 56 | 57 | reflect-metadata@^0.1.10: 58 | version "0.1.13" 59 | resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" 60 | integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== 61 | 62 | regenerator-runtime@^0.11.0: 63 | version "0.11.1" 64 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" 65 | integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== 66 | 67 | resize-observer-polyfill@^1.5.0: 68 | version "1.5.1" 69 | resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" 70 | integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== 71 | 72 | throttle-debounce@^1.0.1: 73 | version "1.1.0" 74 | resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-1.1.0.tgz#51853da37be68a155cb6e827b3514a3c422e89cd" 75 | integrity sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg== 76 | 77 | typescript@^2.6.2: 78 | version "2.9.2" 79 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" 80 | integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== 81 | 82 | vue-class-component@^6.1.0: 83 | version "6.3.2" 84 | resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-6.3.2.tgz#e6037e84d1df2af3bde4f455e50ca1b9eec02be6" 85 | integrity sha512-cH208IoM+jgZyEf/g7mnFyofwPDJTM/QvBNhYMjqGB8fCsRyTf68rH2ISw/G20tJv+5mIThQ3upKwoL4jLTr1A== 86 | 87 | vue-property-decorator@^6.0.0: 88 | version "6.1.0" 89 | resolved "https://registry.yarnpkg.com/vue-property-decorator/-/vue-property-decorator-6.1.0.tgz#ef97bcc1bfe794ec060133ca04a5aca02e808828" 90 | integrity sha512-NM4PYPOkOIO7SFtWiQqVrbp+ORzd7CJXcIz0X710PNW9pxGfbil0/x/ULFympzIUoHXBKN2dqoOQzh6oeMzpTQ== 91 | dependencies: 92 | reflect-metadata "^0.1.10" 93 | vue-class-component "^6.1.0" 94 | 95 | vue@^2.5.13: 96 | version "2.6.10" 97 | resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" 98 | integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== 99 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import rules from "./rules"; 2 | import Component from "./component"; 3 | import errorMessage from "./error-message"; 4 | import defaultErrorMessageTemplate from "./error-message-template"; 5 | import { VueConstructor } from "vue"; 6 | import { PropOptions } from "vue/types/options"; 7 | import { RuleGetter, ErrorMessageTemplate } from "./types"; 8 | 9 | export interface VerifyRulePropOptions extends PropOptions { 10 | name: string; 11 | } 12 | 13 | let ElFormItemComponent: VueConstructor; 14 | 15 | function addRule( 16 | name: string | VerifyRulePropOptions, 17 | getter: RuleGetter 18 | ): RuleGetter { 19 | if (!ElFormItemComponent) throw Error("please install me"); 20 | const props: any = {}; 21 | if (typeof name === "string") props[name] = {}; 22 | else props[name.name] = name; 23 | const _name = typeof name === "string" ? name : name.name; 24 | const component: any = { props }; 25 | // 监听prop变化,触发校验 26 | component.watch = {}; 27 | component.watch[_name] = function() { 28 | if (this.verify !== undefined && (this as any).prop) 29 | (this as any).validate(""); 30 | }; 31 | ElFormItemComponent.mixin(component); 32 | return rules(_name, getter); 33 | } 34 | 35 | function getRule(name: string): RuleGetter { 36 | return rules(name); 37 | } 38 | 39 | function getErrorMessage(name: string, templateData?: any): string { 40 | return errorMessage.get(name, templateData); 41 | } 42 | 43 | function init() { 44 | const transform = (value: string) => Number(value); 45 | // 文本长度 46 | addRule({ name: "length", type: Number }, length => ({ 47 | len: length, 48 | message: getErrorMessage("length", length) 49 | })); 50 | // 最小文本长度 51 | addRule({ name: "minLength", type: Number }, minLength => ({ 52 | min: minLength, 53 | message: getErrorMessage("minLength", minLength) 54 | })); 55 | // 数字 56 | addRule("number", () => ({ 57 | validator(rule: any, val: string, callback: Function) { 58 | if (/^([-+])?\d+(\.\d+)?$/.test(val)) callback(); 59 | else callback(Error(getErrorMessage("number"))); 60 | } 61 | })); 62 | // gt 63 | addRule({ name: "gt", type: Number }, gt => [ 64 | getRule("number")(), 65 | { 66 | validator(rule: any, val: number, callback: Function) { 67 | if (val > gt) callback(); 68 | else callback(Error(getErrorMessage("gt", gt))); 69 | } 70 | } 71 | ]); 72 | // gte 73 | addRule({ name: "gte", type: Number }, gte => [ 74 | getRule("number")(), 75 | { 76 | type: "number", 77 | min: gte, 78 | transform, 79 | message: getErrorMessage("gte", gte) 80 | } 81 | ]); 82 | // lt 83 | addRule({ name: "lt", type: Number }, lt => [ 84 | getRule("number")(), 85 | { 86 | validator(rule: any, val: number, callback: Function) { 87 | if (val < lt) callback(); 88 | else callback(Error(getErrorMessage("lt", lt))); 89 | } 90 | } 91 | ]); 92 | // lte 93 | addRule({ name: "lte", type: Number }, lte => [ 94 | getRule("number")(), 95 | { 96 | type: "number", 97 | max: lte, 98 | transform, 99 | message: getErrorMessage("lte", lte) 100 | } 101 | ]); 102 | // 整数类型 103 | addRule("int", () => [ 104 | getRule("number")(), 105 | { 106 | type: "integer", 107 | transform, 108 | message: getErrorMessage("int") 109 | } 110 | ]); 111 | // 最多小数位 112 | addRule({ name: "maxDecimalLength", type: Number }, maxDecimalLength => [ 113 | getRule("number")(), 114 | { 115 | validator(rule: any, val: string | number, callback: Function) { 116 | const decimal = val.toString().split(".")[1]; 117 | if (decimal && decimal.length > maxDecimalLength) 118 | callback( 119 | Error(getErrorMessage("maxDecimalLength", maxDecimalLength)) 120 | ); 121 | else callback(); 122 | } 123 | } 124 | ]); 125 | // 手机号 https://github.com/aweiu/element-ui-verify/issues/24 126 | addRule("phone", () => ({ 127 | pattern: /^(?=\d{11}$)^1(?:3\d|4[57]|5[^4\D]|6[67]|7[^249\D]|8\d|9[189])\d{8}$/, 128 | message: getErrorMessage("phone") 129 | })); 130 | // 邮箱 131 | addRule("email", () => ({ 132 | type: "email", 133 | message: getErrorMessage("email") 134 | })); 135 | // 6位数字验证码 136 | addRule("verifyCode", () => ({ 137 | pattern: /^\d{6}$/, 138 | message: getErrorMessage("verifyCode") 139 | })); 140 | } 141 | 142 | function install( 143 | Vue: VueConstructor, 144 | options: { 145 | errorMessageTemplate?: ErrorMessageTemplate; 146 | fieldChange?: "clear" | "verify"; 147 | } = {} 148 | ) { 149 | ElFormItemComponent = Vue.component("ElFormItem"); 150 | if (!ElFormItemComponent) throw Error("please install element-ui first"); 151 | errorMessage.setTemplate( 152 | options.errorMessageTemplate || defaultErrorMessageTemplate 153 | ); 154 | Component.fieldChange = options.fieldChange || "verify"; 155 | ElFormItemComponent.mixin(Component); 156 | init(); 157 | } 158 | 159 | export default { 160 | install, 161 | addRule, 162 | getRule, 163 | getErrorMessage 164 | }; 165 | --------------------------------------------------------------------------------