├── example ├── wechat │ ├── app.js │ ├── pages │ │ └── index │ │ │ ├── index.json │ │ │ ├── index.wxss │ │ │ ├── index.wxml │ │ │ └── index.js │ ├── app.json │ ├── project.config.json │ └── js │ │ └── we-validator.js ├── mpvue │ ├── static │ │ └── .gitkeep │ ├── config │ │ ├── prod.env.js │ │ ├── dev.env.js │ │ └── index.js │ ├── src │ │ ├── pages │ │ │ └── index │ │ │ │ ├── main.js │ │ │ │ └── index.vue │ │ ├── main.js │ │ └── App.vue │ ├── .postcssrc.js │ ├── .editorconfig │ ├── .gitignore │ ├── index.html │ ├── build │ │ ├── dev-client.js │ │ ├── vue-loader.conf.js │ │ ├── build.js │ │ ├── check-versions.js │ │ ├── utils.js │ │ ├── webpack.base.conf.js │ │ ├── webpack.dev.conf.js │ │ ├── dev-server.js │ │ └── webpack.prod.conf.js │ ├── .babelrc │ ├── README.md │ ├── project.config.json │ └── package.json ├── nodejs │ ├── server │ │ ├── router │ │ │ ├── router.js │ │ │ └── home.js │ │ └── view │ │ │ └── index.ejs │ ├── package.json │ └── app.js ├── web │ └── index.html └── complex │ └── index.html ├── assets ├── v2.png └── demo_multi.png ├── .npmignore ├── .travis.yml ├── .gitignore ├── types └── index.d.ts ├── LICENSE ├── package.json ├── webpack.config.js ├── UPGRADE.md ├── CHANGELOG.md ├── test └── we-validator.test.js ├── src ├── rules.js └── we-validator.js ├── dist ├── we-validator.min.js └── we-validator.js ├── README.md └── lib └── we-validator.js /example/wechat/app.js: -------------------------------------------------------------------------------- 1 | App({}) -------------------------------------------------------------------------------- /example/mpvue/static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChanceYu/we-validator/HEAD/assets/v2.png -------------------------------------------------------------------------------- /example/mpvue/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /example/wechat/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "we-validator" 3 | } -------------------------------------------------------------------------------- /assets/demo_multi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChanceYu/we-validator/HEAD/assets/demo_multi.png -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | dist 3 | example 4 | test 5 | node_modules 6 | *.js.map 7 | webpack.config.js 8 | UPGRADE.md -------------------------------------------------------------------------------- /example/mpvue/src/pages/index/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './index' 3 | 4 | const app = new Vue(App) 5 | app.$mount() 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | install: 5 | - npm install 6 | script: 7 | - npm run build 8 | after_success: 9 | - npm run test 10 | -------------------------------------------------------------------------------- /example/mpvue/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-mpvue-wxss": {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /example/mpvue/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /example/wechat/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | input{ 2 | margin: 10px; 3 | padding: 10px; 4 | border: 1px solid #eee; 5 | font-size: 16px; 6 | } 7 | 8 | button{ 9 | margin: 10px; 10 | } -------------------------------------------------------------------------------- /example/mpvue/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /example/mpvue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | *.sln 14 | -------------------------------------------------------------------------------- /example/mpvue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mpvue 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /example/nodejs/server/router/router.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router') 2 | 3 | const home = require('./home') 4 | 5 | // 装载所有子路由 6 | let router = new Router() 7 | 8 | router.use('', home.routes(), home.allowedMethods()) 9 | 10 | module.exports = router; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | package-lock.json 5 | 6 | ._* 7 | 8 | .Spotlight-V100 9 | .Trashes 10 | 11 | Thumbs.db 12 | ehthumbs.db 13 | 14 | Desktop.ini 15 | 16 | $RECYCLE.BIN/ 17 | 18 | .idea 19 | 20 | *.sublime-* 21 | 22 | .vscode 23 | 24 | node_modules 25 | *.js.map -------------------------------------------------------------------------------- /example/mpvue/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /example/wechat/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index" 4 | ], 5 | "window": { 6 | "backgroundTextStyle": "light", 7 | "navigationBarBackgroundColor": "#32b16c", 8 | "navigationBarTitleText": "we-validator", 9 | "navigationBarTextStyle": "white" 10 | } 11 | } -------------------------------------------------------------------------------- /example/wechat/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 |
-------------------------------------------------------------------------------- /example/nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "test": "echo \"Error: no test specified\" && exit 1" 6 | }, 7 | "dependencies": { 8 | "ejs": "^2.5.7", 9 | "koa": "^2.5.1", 10 | "koa-bodyparser": "^3.2.0", 11 | "koa-router": "^7.4.0", 12 | "koa-views": "^5.2.1", 13 | "we-validator": "^2.1.10" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/mpvue/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["istanbul"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/mpvue/README.md: -------------------------------------------------------------------------------- 1 | # mpvue 2 | 3 | > A Mpvue project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /example/mpvue/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | // var isProduction = process.env.NODE_ENV === 'production' 4 | // for mp 5 | var isProduction = true 6 | 7 | module.exports = { 8 | loaders: utils.cssLoaders({ 9 | sourceMap: isProduction 10 | ? config.build.productionSourceMap 11 | : config.dev.cssSourceMap, 12 | extract: isProduction 13 | }), 14 | transformToRequire: { 15 | video: 'src', 16 | source: 'src', 17 | img: 'src', 18 | image: 'xlink:href' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/mpvue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | Vue.config.productionTip = false 5 | App.mpType = 'app' 6 | 7 | const app = new Vue(App) 8 | app.$mount() 9 | 10 | export default { 11 | // 这个字段走 app.json 12 | config: { 13 | // 页面前带有 ^ 符号的,会被编译成首页,其他页面可以选填,我们会自动把 webpack entry 里面的入口页面加进去 14 | pages: ['^pages/index/main'], 15 | window: { 16 | backgroundTextStyle: 'light', 17 | navigationBarBackgroundColor: '#fff', 18 | navigationBarTitleText: 'WeChat', 19 | navigationBarTextStyle: 'black' 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /example/mpvue/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "setting": { 4 | "urlCheck": true, 5 | "es6": false, 6 | "postcss": true, 7 | "minified": true, 8 | "newFeature": true 9 | }, 10 | "miniprogramRoot": "./dist/", 11 | "compileType": "miniprogram", 12 | "appid": "touristappid", 13 | "projectname": "mpvue", 14 | "condition": { 15 | "search": { 16 | "current": -1, 17 | "list": [] 18 | }, 19 | "conversation": { 20 | "current": -1, 21 | "list": [] 22 | }, 23 | "game": { 24 | "currentL": -1, 25 | "list": [] 26 | }, 27 | "miniprogram": { 28 | "current": -1, 29 | "list": [] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/wechat/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "libVersion": "2.2.1", 15 | "appid": "wxd15c2ae504af0dca", 16 | "projectname": "we-validator-wechat", 17 | "isGameTourist": false, 18 | "condition": { 19 | "search": { 20 | "current": -1, 21 | "list": [] 22 | }, 23 | "conversation": { 24 | "current": -1, 25 | "list": [] 26 | }, 27 | "game": { 28 | "currentL": -1, 29 | "list": [] 30 | }, 31 | "miniprogram": { 32 | "current": -1, 33 | "list": [] 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /example/mpvue/src/App.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 32 | -------------------------------------------------------------------------------- /example/nodejs/app.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa') 2 | const path = require('path') 3 | const views = require('koa-views') 4 | const Router = require('koa-router') 5 | const bodyParser = require('koa-bodyparser') 6 | 7 | const routers = require('./server/router/router') 8 | 9 | const app = new Koa() 10 | 11 | app.use(bodyParser()) 12 | 13 | // 加载模板引擎 14 | app.use(views(path.join(__dirname, './server/view'), { 15 | extension: 'ejs' 16 | })) 17 | 18 | app.use(async (ctx, next) => { 19 | let url = ctx.request.url 20 | 21 | console.log(url); 22 | await next(); 23 | }) 24 | 25 | // 加载路由中间件 26 | app.use(routers.routes()).use(routers.allowedMethods()) 27 | 28 | app.use(async (ctx) => { 29 | let url = ctx.request.url 30 | 31 | url = 'router: ' + url 32 | 33 | ctx.body = url 34 | }) 35 | 36 | app.listen(3000, () => { 37 | console.log('server is starting at http://localhost:3000/') 38 | }) -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "we-validator" { 2 | type Rule = Function | RegExp; 3 | type RuleOption = { rule: Rule; message: string }; 4 | type Options = { 5 | rules: object, 6 | messages: object, 7 | onMessage?: Function, 8 | multiCheck?: boolean 9 | } 10 | class WeValidator { 11 | constructor(options: Options); 12 | static RULES: object; 13 | static addRule(ruleName: string, ruleOption: RuleOption): void; 14 | static checkValue(ruleName: string, value: string, param: any, skip: boolean): boolean; 15 | options: Options; 16 | required: Function; 17 | checkData(data: object, onMessage?: Function, showMessage?: boolean, fieldMap?: object): boolean; 18 | checkFields(data: object, onMessage?: Function, showMessage?: boolean): boolean; 19 | isValid(data: object, fields: Array): boolean; 20 | addRules(options: Options): void; 21 | removeRules(fields: Array): void; 22 | } 23 | export = WeValidator 24 | } 25 | 26 | -------------------------------------------------------------------------------- /example/wechat/pages/index/index.js: -------------------------------------------------------------------------------- 1 | const WeValidator = require('../../js/we-validator') 2 | 3 | Page({ 4 | onReady() { 5 | this.initValidator() 6 | }, 7 | onSubmitForm(e) { 8 | let { value } = e.detail 9 | 10 | console.log(value) 11 | if (!this.validatorInstance.checkData(value)) return 12 | 13 | // 开始提交表单 14 | // wx.request 15 | console.log('submiting') 16 | }, 17 | initValidator() { 18 | this.validatorInstance = new WeValidator({ 19 | rules: { 20 | username: { 21 | required: true 22 | }, 23 | phoneno: { 24 | required: true, 25 | mobile: true 26 | }, 27 | str: { 28 | length: 3 29 | }, 30 | }, 31 | messages: { 32 | username: { 33 | required: '请输入用户名' 34 | }, 35 | phoneno: { 36 | required: '请输入手机号', 37 | mobile: '手机号格式不正确' 38 | }, 39 | str: { 40 | length: '请输入长度为3的字符串' 41 | }, 42 | }, 43 | }) 44 | }, 45 | }) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ChanceYu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/mpvue/build/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | var ora = require('ora') 6 | var rm = require('rimraf') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var webpack = require('webpack') 10 | var config = require('../config') 11 | var webpackConfig = require('./webpack.prod.conf') 12 | 13 | var spinner = ora('building for production...') 14 | spinner.start() 15 | 16 | rm(path.join(config.build.assetsRoot, '*'), err => { 17 | if (err) throw err 18 | webpack(webpackConfig, function (err, stats) { 19 | spinner.stop() 20 | if (err) throw err 21 | process.stdout.write(stats.toString({ 22 | colors: true, 23 | modules: false, 24 | children: false, 25 | chunks: false, 26 | chunkModules: false 27 | }) + '\n\n') 28 | 29 | if (stats.hasErrors()) { 30 | console.log(chalk.red(' Build failed with errors.\n')) 31 | process.exit(1) 32 | } 33 | 34 | console.log(chalk.cyan(' Build complete.\n')) 35 | console.log(chalk.yellow( 36 | ' Tip: built files are meant to be served over an HTTP server.\n' + 37 | ' Opening index.html over file:// won\'t work.\n' 38 | )) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /example/mpvue/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | var shell = require('shelljs') 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | } 15 | ] 16 | 17 | if (shell.which('npm')) { 18 | versionRequirements.push({ 19 | name: 'npm', 20 | currentVersion: exec('npm --version'), 21 | versionRequirement: packageConfig.engines.npm 22 | }) 23 | } 24 | 25 | module.exports = function () { 26 | var warnings = [] 27 | for (var i = 0; i < versionRequirements.length; i++) { 28 | var mod = versionRequirements[i] 29 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 30 | warnings.push(mod.name + ': ' + 31 | chalk.red(mod.currentVersion) + ' should be ' + 32 | chalk.green(mod.versionRequirement) 33 | ) 34 | } 35 | } 36 | 37 | if (warnings.length) { 38 | console.log('') 39 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 40 | console.log() 41 | for (var i = 0; i < warnings.length; i++) { 42 | var warning = warnings[i] 43 | console.log(' ' + warning) 44 | } 45 | console.log() 46 | process.exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/nodejs/server/router/home.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router') 2 | const WeValidator = require('we-validator') 3 | 4 | let router = new Router() 5 | 6 | let validatorInstance = new WeValidator({ 7 | multiCheck: true, 8 | rules: { 9 | username: { 10 | required: true 11 | }, 12 | pwd: { 13 | required: true 14 | }, 15 | repeatPwd: { 16 | required: true, 17 | equalTo: 'pwd' 18 | }, 19 | phoneno: { 20 | required: true, 21 | mobile: true 22 | }, 23 | str: { 24 | rangeChinese: [1,4] 25 | } 26 | }, 27 | messages: { 28 | username: { 29 | required: '请输入用户名' 30 | }, 31 | pwd: { 32 | required: '请输入密码' 33 | }, 34 | repeatPwd: { 35 | required: '请输入确认密码', 36 | equalTo: '两次密码不一致' 37 | }, 38 | phoneno: { 39 | required: '请输入手机号', 40 | mobile: '手机号格式不正确' 41 | } 42 | } 43 | }); 44 | 45 | // 首页 46 | router.get('/', async (ctx) => { 47 | await ctx.render('index') 48 | }) 49 | 50 | // 提交表单 51 | router.post('/form', async (ctx) => { 52 | let formData = ctx.request.body 53 | 54 | if(!validatorInstance.checkData(formData, onMessage)) return 55 | 56 | ctx.body = { 57 | status: 'success', 58 | msg: '校验通过' 59 | } 60 | 61 | function onMessage(params){ 62 | ctx.body = { 63 | status: 'failure', 64 | errors: params 65 | } 66 | } 67 | }) 68 | 69 | module.exports = router; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "we-validator", 3 | "version": "2.1.17", 4 | "description": "简单灵活的表单验证插件,支持小程序、浏览器、Nodejs", 5 | "main": "lib/we-validator.js", 6 | "scripts": { 7 | "dev": "NODE_ENV=development webpack --watch --config webpack.config --colors", 8 | "build": "NODE_ENV=production webpack --config webpack.config --colors", 9 | "test": "mocha test/*.js", 10 | "prepublish": "npm run build" 11 | }, 12 | "types": "./types/index.d.ts", 13 | "files": [ 14 | "lib", 15 | "dist", 16 | "types" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/ChanceYu/we-validator.git" 21 | }, 22 | "keywords": [ 23 | "we-validator", 24 | "validator", 25 | "validation", 26 | "weapp", 27 | "wechat", 28 | "mini-program", 29 | "weapp-validator", 30 | "node-validator" 31 | ], 32 | "author": "ChanceYu ", 33 | "license": "MIT", 34 | "devDependencies": { 35 | "babel-cli": "^6.26.0", 36 | "babel-core": "^6.26.0", 37 | "babel-loader": "^7.1.2", 38 | "babel-plugin-add-module-exports": "^0.2.1", 39 | "babel-plugin-transform-object-assign": "^6.22.0", 40 | "babel-preset-es2015": "^6.24.1", 41 | "babel-preset-stage-0": "^6.24.1", 42 | "babel-register": "^6.26.0", 43 | "babelify": "^7.3.0", 44 | "chai": "^3.5.0", 45 | "mocha": "^2.4.5", 46 | "uglify-js": "^3.1.3", 47 | "webpack": "^3.6.0" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/ChanceYu/we-validator/issues" 51 | }, 52 | "homepage": "https://github.com/ChanceYu/we-validator#readme" 53 | } 54 | -------------------------------------------------------------------------------- /example/mpvue/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: false, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | // 在小程序开发者工具中不需要自动打开浏览器 28 | autoOpenBrowser: false, 29 | assetsSubDirectory: 'static', 30 | assetsPublicPath: '/', 31 | proxyTable: {}, 32 | // CSS Sourcemaps off by default because relative paths are "buggy" 33 | // with this option, according to the CSS-Loader README 34 | // (https://github.com/webpack/css-loader#sourcemaps) 35 | // In our experience, they generally work as expected, 36 | // just be aware of this issue when enabling this option. 37 | cssSourceMap: false 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const path = require('path'); 5 | const isProduction = process.env.NODE_ENV === 'production'; 6 | 7 | const packageJSON = require('./package.json'); 8 | 9 | const getConfig = function (outputPath, min) { 10 | let config = { 11 | entry: path.join(__dirname, 'src/we-validator.js'), 12 | output: { 13 | path: outputPath, 14 | filename: min ? 'we-validator.min.js' : 'we-validator.js', 15 | library: 'WeValidator', 16 | libraryTarget: 'umd', 17 | umdNamedDefine: true 18 | }, 19 | module: { 20 | rules: [{ 21 | test: /\.(js)$/, 22 | exclude: /node_modules/, 23 | loader: 'babel-loader', 24 | options: { 25 | presets: ['es2015', 'stage-0'] 26 | } 27 | }] 28 | }, 29 | plugins: [ 30 | new webpack.BannerPlugin( 31 | `${packageJSON.name} 32 | version: ${packageJSON.version} 33 | address: ${packageJSON.homepage} 34 | author: ${packageJSON.author} 35 | license: ${packageJSON.license}`) 36 | ], 37 | resolve: { 38 | extensions: ['.js'] 39 | } 40 | } 41 | 42 | if(min){ 43 | config.plugins.push( 44 | new webpack.optimize.UglifyJsPlugin({ 45 | warnings: false, 46 | sourceMap: false, 47 | mangle: false 48 | }) 49 | ) 50 | } 51 | 52 | return config 53 | } 54 | 55 | let configs = [ 56 | getConfig(path.join(__dirname, 'lib')), 57 | getConfig(path.join(__dirname, 'example/wechat/js')) 58 | ] 59 | 60 | if(isProduction){ 61 | configs.push( getConfig(path.join(__dirname, 'dist')) ) 62 | configs.push( getConfig(path.join(__dirname, 'dist'), true) ) 63 | } 64 | 65 | module.exports = configs -------------------------------------------------------------------------------- /example/mpvue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mpvue", 3 | "version": "1.0.0", 4 | "description": "A Mpvue project", 5 | "author": "ChanceYu ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "mpvue": "^1.0.11", 14 | "vuex": "^3.0.1", 15 | "we-validator": "^2.1.10" 16 | }, 17 | "devDependencies": { 18 | "mpvue-loader": "1.0.13", 19 | "mpvue-webpack-target": "^1.0.0", 20 | "mpvue-template-compiler": "^1.0.11", 21 | "portfinder": "^1.0.13", 22 | "postcss-mpvue-wxss": "^1.0.0", 23 | "prettier": "~1.12.1", 24 | "px2rpx-loader": "^0.1.10", 25 | "babel-core": "^6.22.1", 26 | "glob": "^7.1.2", 27 | "webpack-mpvue-asset-plugin": "0.0.2", 28 | "babel-loader": "^7.1.1", 29 | "babel-plugin-transform-runtime": "^6.22.0", 30 | "babel-preset-env": "^1.3.2", 31 | "babel-preset-stage-2": "^6.22.0", 32 | "babel-register": "^6.22.0", 33 | "chalk": "^2.4.0", 34 | "connect-history-api-fallback": "^1.3.0", 35 | "copy-webpack-plugin": "^4.5.1", 36 | "css-loader": "^0.28.11", 37 | "cssnano": "^3.10.0", 38 | "eventsource-polyfill": "^0.9.6", 39 | "express": "^4.16.3", 40 | "extract-text-webpack-plugin": "^3.0.2", 41 | "file-loader": "^1.1.11", 42 | "friendly-errors-webpack-plugin": "^1.7.0", 43 | "html-webpack-plugin": "^3.2.0", 44 | "http-proxy-middleware": "^0.18.0", 45 | "webpack-bundle-analyzer": "^2.2.1", 46 | "semver": "^5.3.0", 47 | "shelljs": "^0.8.1", 48 | "uglifyjs-webpack-plugin": "^1.2.5", 49 | "optimize-css-assets-webpack-plugin": "^3.2.0", 50 | "ora": "^2.0.0", 51 | "rimraf": "^2.6.0", 52 | "url-loader": "^1.0.1", 53 | "vue-style-loader": "^4.1.0", 54 | "webpack": "^3.11.0", 55 | "webpack-dev-middleware-hard-disk": "^1.12.0", 56 | "webpack-merge": "^4.1.0", 57 | "postcss-loader": "^2.1.4" 58 | }, 59 | "engines": { 60 | "node": ">= 4.0.0", 61 | "npm": ">= 3.0.0" 62 | }, 63 | "browserslist": [ 64 | "> 1%", 65 | "last 2 versions", 66 | "not ie <= 8" 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /example/mpvue/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | 15 | var cssLoader = { 16 | loader: 'css-loader', 17 | options: { 18 | minimize: process.env.NODE_ENV === 'production', 19 | sourceMap: options.sourceMap 20 | } 21 | } 22 | 23 | var postcssLoader = { 24 | loader: 'postcss-loader', 25 | options: { 26 | sourceMap: true 27 | } 28 | } 29 | 30 | var px2rpxLoader = { 31 | loader: 'px2rpx-loader', 32 | options: { 33 | baseDpr: 1, 34 | rpxUnit: 0.5 35 | } 36 | } 37 | 38 | // generate loader string to be used with extract text plugin 39 | function generateLoaders (loader, loaderOptions) { 40 | var loaders = [cssLoader, px2rpxLoader, postcssLoader] 41 | if (loader) { 42 | loaders.push({ 43 | loader: loader + '-loader', 44 | options: Object.assign({}, loaderOptions, { 45 | sourceMap: options.sourceMap 46 | }) 47 | }) 48 | } 49 | 50 | // Extract CSS when that option is specified 51 | // (which is the case during production build) 52 | if (options.extract) { 53 | return ExtractTextPlugin.extract({ 54 | use: loaders, 55 | fallback: 'vue-style-loader' 56 | }) 57 | } else { 58 | return ['vue-style-loader'].concat(loaders) 59 | } 60 | } 61 | 62 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 63 | return { 64 | css: generateLoaders(), 65 | wxss: generateLoaders(), 66 | postcss: generateLoaders(), 67 | less: generateLoaders('less'), 68 | sass: generateLoaders('sass', { indentedSyntax: true }), 69 | scss: generateLoaders('sass'), 70 | stylus: generateLoaders('stylus'), 71 | styl: generateLoaders('stylus') 72 | } 73 | } 74 | 75 | // Generate loaders for standalone style files (outside of .vue) 76 | exports.styleLoaders = function (options) { 77 | var output = [] 78 | var loaders = exports.cssLoaders(options) 79 | for (var extension in loaders) { 80 | var loader = loaders[extension] 81 | output.push({ 82 | test: new RegExp('\\.' + extension + '$'), 83 | use: loader 84 | }) 85 | } 86 | return output 87 | } 88 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | ## 1.x 升级到 2.x 指南 2 | 3 | 2.x 和 1.x 版本有所差别,如果您要升级到 2.x 版本,请根据以下内容做修改。 4 | 5 | ### 添加自定义规则 6 | > WeValidator.addRule 7 | 8 | 1.x 版本 9 | ```javascript 10 | WeValidator.addRule('theRuleName', function(value, param){ 11 | return /\d/.test(value) 12 | }) 13 | ``` 14 | 2.x 版本 15 | ```javascript 16 | WeValidator.addRule('theRuleName', { 17 | message: '默认错误提示文字', 18 | rule(value, param){ 19 | return /\d/.test(value) 20 | } 21 | }) 22 | 23 | // 或者 24 | WeValidator.addRule('theRuleName', { 25 | message: '默认错误提示文字', 26 | rule: /\d/ 27 | }) 28 | ``` 29 | 30 | ### 单独校验某个内容 31 | > WeValidator.checkValue 32 | 33 | 1.x 版本 34 | ```javascript 35 | let b1 = WeValidator.mobile('str') 36 | let b2 = WeValidator.chinese('str') 37 | ``` 38 | 2.x 版本 39 | ```javascript 40 | let b1 = WeValidator.checkValue('mobile', 'str') 41 | let b2 = WeValidator.checkValue('chinese', 'str') 42 | ``` 43 | 44 | ### 默认校验规则的变化 45 | 2.x 的校验规则大部分重写,删除了不常用的规则,并添加了新的规则 46 | 47 | ##### 删除的规则(可使用 2.x 相关规则替代) 48 | ```diff 49 | - bankCard: true 50 | + range: [16, 19] 51 | 52 | - mobileWithSpace 53 | + pattern: /^1\d{2}\s?\d{4}\s?\d{4}$/ 54 | 55 | - noZeroStart 56 | + pattern: /^([1-9][0-9]*)$/ 57 | 58 | - specialStr 59 | + pattern: /[^%&',;=?$\x22]+/ 60 | 61 | - money 62 | + pattern: /^\d+\.\d{2}$/ 63 | 64 | - month 65 | + pattern: /^(0?[1-9]|1[0-2])$/ 66 | 67 | - day 68 | + pattern: /^((0?[1-9])|((1|2)[0-9])|30|31)$/ 69 | 70 | - html 71 | + pattern: /<(.*)>(.*)<\/(.*)>|<(.*)\/>/ 72 | 73 | - spaceEnter 74 | + pattern: /\n[\s| ]*\r/ 75 | 76 | - qq 77 | + pattern: /^[1-9][0-9]{4,}$/ 78 | 79 | - zip 80 | + pattern: /^[\d]{6}/ 81 | 82 | - doubleByte 83 | + pattern: /[^\x00-\xff]/ 84 | 85 | - intLength: 2 86 | + pattern: /^\d{2}$/ 87 | 88 | - decimalLength: 2 89 | + pattern: /^[0-9]+(.[0-9]{2}$/ 90 | 91 | - decimalLengthRange: [2, 4] 92 | + pattern: /^[0-9]+(.[0-9]{2,4}$/ 93 | 94 | - stringLetter: 'a' 95 | + pattern: /^[a-z]+$/ 96 | 97 | - stringLetterDefault 98 | + pattern: /^\w+$/ 99 | ``` 100 | 101 | ##### 规则名称变化 102 | ```diff 103 | - idCard 104 | + idcard 105 | 106 | - chinese2to8: true 107 | + rangeChinese: [2, 8] 108 | 109 | - intOrFloat 110 | + number 111 | 112 | - int 113 | + digits 114 | 115 | - httpUrl 116 | + url 117 | 118 | - equal: WeValidator.$value('field') 119 | + equalTo: 'field' 120 | 121 | - intLessLength: 2 122 | + min: 2 123 | 124 | - intGreater: 2 125 | + max: 2 126 | 127 | - intLengthRange: [2, 6] 128 | + range: [2, 6] 129 | 130 | - stringLength: 6 131 | + length: 6 132 | ``` 133 | 134 | ##### 2.x 新增规则[参考](./README.md#默认支持的规则) -------------------------------------------------------------------------------- /example/nodejs/server/view/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | we-validator (nodejs端校验) 8 | 38 | 39 | 40 |
41 | 42 |

43 | 44 | 45 |

46 | 47 | 48 |

49 | 50 | 51 |

52 | 53 | 54 |

55 | 56 | 57 |
58 | 59 | 60 | 61 | 62 | 90 | 91 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | > 更新日志(推荐使用最新版本) 4 | 5 | ## Released 6 | 7 | ### [v2.1.17](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.17) 8 | - 修复:multiple 类型声明错误[issue](https://github.com/ChanceYu/we-validator/issues/25) 9 | 10 | 11 | ### [v2.1.16](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.16) 12 | - 修复:错误 message 的显示优化[pull](https://github.com/ChanceYu/we-validator/pull/16) 13 | - 修复:修改空指针和语法修改[pull](https://github.com/ChanceYu/we-validator/pull/17) 14 | - 修复:required: false 不进行“必须”验证[pull](https://github.com/ChanceYu/we-validator/pull/18) 15 | 16 | 17 | ### [v2.1.15](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.15) 18 | - 修复:部分ts定义错误[issue](https://github.com/ChanceYu/we-validator/issues/15) 19 | 20 | 21 | ### [v2.1.14](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.14) 22 | - 新增:添加ts的定义文件[merge](https://github.com/ChanceYu/we-validator/pull/14) 23 | 24 | 25 | ### [v2.1.11](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.11) 26 | - 修复:手机号以 `16` 开头的校验问题[issue](https://github.com/ChanceYu/we-validator/issues/12) 27 | 28 | 29 | ### [v2.1.10](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.10) 30 | - 新增:`.checkFields` 方法,可校验对应的字段,[参考](./README.md#checkfieldsdata-fields-onmessage) 31 | - 修改:`.isValid` 方法,可校验对应的字段,[参考](./README.md#isvaliddata-fields) 32 | 33 | 34 | ### [v2.1.9](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.9) 35 | - 优化:部分规则 36 | - 补充文档和增加动态字段校验使用示例 37 | 38 | 39 | ### [v2.1.8](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.8) 40 | - 修复:中文校验规则 41 | - 修复:多个实例参数覆盖问题 42 | 43 | 44 | ### [v2.1.7](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.7) 45 | - 优化:校验逻辑 46 | 47 | 48 | ### [v2.1.6](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.6) 49 | - 修复:`WeValidator.checkValue` 校验空字段不符合预期 50 | - 优化:`multiCheck` 为 `true` 时错误显示 51 | 52 | 53 | ### [v2.1.5](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.5) 54 | - 修改:通用正则校验 55 | ```diff 56 | - regex 57 | + pattern 58 | ``` 59 | - 增加:1.x 到 2.x [升级指南](./UPGRADE.md) 60 | 61 | 62 | ### [v2.1.4](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.4) 63 | - 优化:自定义规则添加方式 64 | 65 | 66 | ### [v2.1.2](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.2) 67 | - 修改:静态方法 `WeValidator.checkValue` 68 | ```diff 69 | - WeValidator.checkField 70 | + WeValidator.checkValue 71 | ``` 72 | - 修改文档 73 | 74 | 75 | ### [v2.1.1](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.1) 76 | - 新增:规则:`notEqualTo、notContains、integer、ipv4、ipv6` 77 | - 新增:示例:[复杂的校验案例-自定义规则](./example/complex/index.html) 78 | 79 | 80 | ### [v2.1.0](https://github.com/ChanceYu/we-validator/releases/tag/v2.1.0) 81 | - 重构:核心方法 82 | - 重写:核心校验规则和默认提供的自定义规则 83 | - 单独校验字段方法修改 84 | 85 | 86 | ### [v1](https://github.com/ChanceYu/we-validator/releases/tag/v1)(v1.0.0 - v1.4.3) 87 | - v1 版本 `we-validator` -------------------------------------------------------------------------------- /example/mpvue/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var fs = require('fs') 3 | var utils = require('./utils') 4 | var config = require('../config') 5 | var vueLoaderConfig = require('./vue-loader.conf') 6 | var MpvuePlugin = require('webpack-mpvue-asset-plugin') 7 | var glob = require('glob') 8 | 9 | function resolve (dir) { 10 | return path.join(__dirname, '..', dir) 11 | } 12 | 13 | function getEntry (rootSrc, pattern) { 14 | var files = glob.sync(path.resolve(rootSrc, pattern)) 15 | return files.reduce((res, file) => { 16 | var info = path.parse(file) 17 | var key = info.dir.slice(rootSrc.length + 1) + '/' + info.name 18 | res[key] = path.resolve(file) 19 | return res 20 | }, {}) 21 | } 22 | 23 | const appEntry = { app: resolve('./src/main.js') } 24 | const pagesEntry = getEntry(resolve('./src'), 'pages/**/main.js') 25 | const entry = Object.assign({}, appEntry, pagesEntry) 26 | 27 | module.exports = { 28 | // 如果要自定义生成的 dist 目录里面的文件路径, 29 | // 可以将 entry 写成 {'toPath': 'fromPath'} 的形式, 30 | // toPath 为相对于 dist 的路径, 例:index/demo,则生成的文件地址为 dist/index/demo.js 31 | entry, 32 | target: require('mpvue-webpack-target'), 33 | output: { 34 | path: config.build.assetsRoot, 35 | filename: '[name].js', 36 | publicPath: process.env.NODE_ENV === 'production' 37 | ? config.build.assetsPublicPath 38 | : config.dev.assetsPublicPath 39 | }, 40 | resolve: { 41 | extensions: ['.js', '.vue', '.json'], 42 | alias: { 43 | 'vue': 'mpvue', 44 | '@': resolve('src') 45 | }, 46 | symlinks: false, 47 | aliasFields: ['mpvue', 'weapp', 'browser'], 48 | mainFields: ['browser', 'module', 'main'] 49 | }, 50 | module: { 51 | rules: [ 52 | { 53 | test: /\.vue$/, 54 | loader: 'mpvue-loader', 55 | options: vueLoaderConfig 56 | }, 57 | { 58 | test: /\.js$/, 59 | include: [resolve('src'), resolve('test')], 60 | use: [ 61 | 'babel-loader', 62 | { 63 | loader: 'mpvue-loader', 64 | options: { 65 | checkMPEntry: true 66 | } 67 | }, 68 | ] 69 | }, 70 | { 71 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 10000, 75 | name: utils.assetsPath('img/[name].[ext]') 76 | } 77 | }, 78 | { 79 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 80 | loader: 'url-loader', 81 | options: { 82 | limit: 10000, 83 | name: utils.assetsPath('media/[name].[ext]') 84 | } 85 | }, 86 | { 87 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 88 | loader: 'url-loader', 89 | options: { 90 | limit: 10000, 91 | name: utils.assetsPath('fonts/[name].[ext]') 92 | } 93 | } 94 | ] 95 | }, 96 | plugins: [ 97 | new MpvuePlugin() 98 | ] 99 | } 100 | -------------------------------------------------------------------------------- /example/mpvue/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | // var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // copy from ./webpack.prod.conf.js 10 | var path = require('path') 11 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 12 | var CopyWebpackPlugin = require('copy-webpack-plugin') 13 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 14 | 15 | // add hot-reload related code to entry chunks 16 | // Object.keys(baseWebpackConfig.entry).forEach(function (name) { 17 | // baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 18 | // }) 19 | 20 | module.exports = merge(baseWebpackConfig, { 21 | module: { 22 | rules: utils.styleLoaders({ 23 | sourceMap: config.dev.cssSourceMap, 24 | extract: true 25 | }) 26 | }, 27 | // cheap-module-eval-source-map is faster for development 28 | // devtool: '#cheap-module-eval-source-map', 29 | devtool: '#source-map', 30 | output: { 31 | path: config.build.assetsRoot, 32 | // filename: utils.assetsPath('js/[name].[chunkhash].js'), 33 | // chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 34 | filename: utils.assetsPath('js/[name].js'), 35 | chunkFilename: utils.assetsPath('js/[id].js') 36 | }, 37 | plugins: [ 38 | new webpack.DefinePlugin({ 39 | 'process.env': config.dev.env 40 | }), 41 | 42 | // copy from ./webpack.prod.conf.js 43 | // extract css into its own file 44 | new ExtractTextPlugin({ 45 | // filename: utils.assetsPath('css/[name].[contenthash].css') 46 | filename: utils.assetsPath('css/[name].wxss') 47 | }), 48 | // Compress extracted CSS. We are using this plugin so that possible 49 | // duplicated CSS from different components can be deduped. 50 | new OptimizeCSSPlugin({ 51 | cssProcessorOptions: { 52 | safe: true 53 | } 54 | }), 55 | new webpack.optimize.CommonsChunkPlugin({ 56 | name: 'vendor', 57 | minChunks: function (module, count) { 58 | // any required modules inside node_modules are extracted to vendor 59 | return ( 60 | module.resource && 61 | /\.js$/.test(module.resource) && 62 | module.resource.indexOf('node_modules') >= 0 63 | ) || count > 1 64 | } 65 | }), 66 | new webpack.optimize.CommonsChunkPlugin({ 67 | name: 'manifest', 68 | chunks: ['vendor'] 69 | }), 70 | // copy custom static assets 71 | new CopyWebpackPlugin([ 72 | { 73 | from: path.resolve(__dirname, '../static'), 74 | to: config.build.assetsSubDirectory, 75 | ignore: ['.*'] 76 | } 77 | ]), 78 | 79 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 80 | // new webpack.HotModuleReplacementPlugin(), 81 | new webpack.NoEmitOnErrorsPlugin(), 82 | // https://github.com/ampedandwired/html-webpack-plugin 83 | // new HtmlWebpackPlugin({ 84 | // filename: 'index.html', 85 | // template: 'index.html', 86 | // inject: true 87 | // }), 88 | new FriendlyErrorsPlugin() 89 | ] 90 | }) 91 | -------------------------------------------------------------------------------- /example/mpvue/src/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 102 | 103 | 133 | -------------------------------------------------------------------------------- /example/mpvue/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | // var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var portfinder = require('portfinder') 14 | var webpackConfig = require('./webpack.dev.conf') 15 | 16 | // default port where dev server listens for incoming traffic 17 | var port = process.env.PORT || config.dev.port 18 | // automatically open browser, if not set will be false 19 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 20 | // Define HTTP proxies to your custom API backend 21 | // https://github.com/chimurai/http-proxy-middleware 22 | var proxyTable = config.dev.proxyTable 23 | 24 | var app = express() 25 | var compiler = webpack(webpackConfig) 26 | 27 | // var devMiddleware = require('webpack-dev-middleware')(compiler, { 28 | // publicPath: webpackConfig.output.publicPath, 29 | // quiet: true 30 | // }) 31 | 32 | // var hotMiddleware = require('webpack-hot-middleware')(compiler, { 33 | // log: false, 34 | // heartbeat: 2000 35 | // }) 36 | // force page reload when html-webpack-plugin template changes 37 | // compiler.plugin('compilation', function (compilation) { 38 | // compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 39 | // hotMiddleware.publish({ action: 'reload' }) 40 | // cb() 41 | // }) 42 | // }) 43 | 44 | // proxy api requests 45 | Object.keys(proxyTable).forEach(function (context) { 46 | var options = proxyTable[context] 47 | if (typeof options === 'string') { 48 | options = { target: options } 49 | } 50 | app.use(proxyMiddleware(options.filter || context, options)) 51 | }) 52 | 53 | // handle fallback for HTML5 history API 54 | app.use(require('connect-history-api-fallback')()) 55 | 56 | // serve webpack bundle output 57 | // app.use(devMiddleware) 58 | 59 | // enable hot-reload and state-preserving 60 | // compilation error display 61 | // app.use(hotMiddleware) 62 | 63 | // serve pure static assets 64 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 65 | app.use(staticPath, express.static('./static')) 66 | 67 | // var uri = 'http://localhost:' + port 68 | 69 | var _resolve 70 | var readyPromise = new Promise(resolve => { 71 | _resolve = resolve 72 | }) 73 | 74 | // console.log('> Starting dev server...') 75 | // devMiddleware.waitUntilValid(() => { 76 | // console.log('> Listening at ' + uri + '\n') 77 | // // when env is testing, don't need open it 78 | // if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 79 | // opn(uri) 80 | // } 81 | // _resolve() 82 | // }) 83 | 84 | module.exports = new Promise((resolve, reject) => { 85 | portfinder.basePort = port 86 | portfinder.getPortPromise() 87 | .then(newPort => { 88 | if (port !== newPort) { 89 | console.log(`${port}端口被占用,开启新端口${newPort}`) 90 | } 91 | var server = app.listen(newPort, 'localhost') 92 | // for 小程序的文件保存机制 93 | require('webpack-dev-middleware-hard-disk')(compiler, { 94 | publicPath: webpackConfig.output.publicPath, 95 | quiet: true 96 | }) 97 | resolve({ 98 | ready: readyPromise, 99 | close: () => { 100 | server.close() 101 | } 102 | }) 103 | }).catch(error => { 104 | console.log('没有找到空闲端口,请打开任务管理器杀死进程端口再试', error) 105 | }) 106 | }) 107 | -------------------------------------------------------------------------------- /test/we-validator.test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect 2 | const WeValidator = require('../lib/we-validator') 3 | 4 | describe('testing: we-validator', () => { 5 | 6 | it('WeValidator.checkValue', () => { 7 | expect(WeValidator.checkValue('required')).to.not.be.ok 8 | expect(WeValidator.checkValue('required', '')).to.not.be.ok 9 | expect(WeValidator.checkValue('required', 'a')).to.be.ok 10 | 11 | expect(WeValidator.checkValue('chinese')).to.not.be.ok 12 | expect(WeValidator.checkValue('chinese', '')).to.not.be.ok 13 | expect(WeValidator.checkValue('chinese', 'a')).to.not.be.ok 14 | expect(WeValidator.checkValue('chinese', '好的')).to.be.ok 15 | 16 | expect(WeValidator.checkValue('mobile')).to.not.be.ok 17 | expect(WeValidator.checkValue('mobile', '')).to.not.be.ok 18 | expect(WeValidator.checkValue('mobile', '111')).to.not.be.ok 19 | expect(WeValidator.checkValue('mobile', '15812345678')).to.be.ok 20 | }) 21 | 22 | it('WeValidator.addRule', () => { 23 | WeValidator.addRule('theRuleName', { 24 | rule(value){ 25 | return /\d/.test(value) 26 | } 27 | }) 28 | expect(WeValidator.checkValue('theRuleName')).to.not.be.ok 29 | expect(WeValidator.checkValue('theRuleName', '')).to.not.be.ok 30 | expect(WeValidator.checkValue('theRuleName', 'a')).to.not.be.ok 31 | expect(WeValidator.checkValue('theRuleName', '1')).to.be.ok 32 | }) 33 | 34 | it('new WeValidator({ onMessage })', () => { 35 | let validatorInstance = null 36 | let _name = 'username' 37 | let _rule= 'required' 38 | let _msg = '提示信息' 39 | 40 | validatorInstance = new WeValidator({ 41 | rules: { 42 | username: { 43 | required: true 44 | } 45 | }, 46 | messages: { 47 | username: { 48 | required: _msg 49 | } 50 | }, 51 | onMessage: function(data){ 52 | expect(data.msg).to.equal(_msg) 53 | expect(data.name).to.equal(_name) 54 | expect(data.rule).to.equal(_rule) 55 | } 56 | }) 57 | 58 | validatorInstance.checkData({}) 59 | }) 60 | 61 | it('validatorInstance.checkData', () => { 62 | let validatorInstance = new WeValidator({ 63 | rules: { 64 | username: { 65 | required: true 66 | } 67 | }, 68 | messages: { 69 | username: { 70 | required: '提示信息' 71 | } 72 | } 73 | }) 74 | 75 | expect(validatorInstance.checkData({})).to.not.be.ok 76 | 77 | }) 78 | 79 | it('WeValidator.onMessage', () => { 80 | let validatorInstance = null 81 | let _name = 'username' 82 | let _rule= 'required' 83 | let _msg = '提示信息' 84 | 85 | WeValidator.onMessage = function(data){ 86 | expect(data.msg).to.equal(_msg) 87 | expect(data.name).to.equal(_name) 88 | expect(data.rule).to.equal(_rule) 89 | } 90 | 91 | validatorInstance = new WeValidator({ 92 | rules: { 93 | username: { 94 | required: true 95 | } 96 | }, 97 | messages: { 98 | username: { 99 | required: _msg 100 | } 101 | }, 102 | }) 103 | 104 | validatorInstance.checkData({}) 105 | }) 106 | 107 | }) -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | we-validator 8 | 38 | 39 | 40 |
41 | 42 |

43 | 44 | 45 |

46 | 47 | 48 |

49 | 50 | 51 |

52 | 53 | 54 |

55 | 56 | 57 |
58 | 59 | 60 | 61 | 62 | 63 | 128 | 129 | -------------------------------------------------------------------------------- /example/mpvue/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var UglifyJsPlugin = require('uglifyjs-webpack-plugin') 8 | var CopyWebpackPlugin = require('copy-webpack-plugin') 9 | // var HtmlWebpackPlugin = require('html-webpack-plugin') 10 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | 13 | var env = config.build.env 14 | 15 | var webpackConfig = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ 18 | sourceMap: config.build.productionSourceMap, 19 | extract: true 20 | }) 21 | }, 22 | devtool: config.build.productionSourceMap ? '#source-map' : false, 23 | output: { 24 | path: config.build.assetsRoot, 25 | // filename: utils.assetsPath('js/[name].[chunkhash].js'), 26 | // chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 27 | filename: utils.assetsPath('js/[name].js'), 28 | chunkFilename: utils.assetsPath('js/[id].js') 29 | }, 30 | plugins: [ 31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 32 | new webpack.DefinePlugin({ 33 | 'process.env': env 34 | }), 35 | new UglifyJsPlugin({ 36 | sourceMap: true 37 | }), 38 | // extract css into its own file 39 | new ExtractTextPlugin({ 40 | // filename: utils.assetsPath('css/[name].[contenthash].css') 41 | filename: utils.assetsPath('css/[name].wxss') 42 | }), 43 | // Compress extracted CSS. We are using this plugin so that possible 44 | // duplicated CSS from different components can be deduped. 45 | new OptimizeCSSPlugin({ 46 | cssProcessorOptions: { 47 | safe: true 48 | } 49 | }), 50 | // generate dist index.html with correct asset hash for caching. 51 | // you can customize output by editing /index.html 52 | // see https://github.com/ampedandwired/html-webpack-plugin 53 | // new HtmlWebpackPlugin({ 54 | // filename: config.build.index, 55 | // template: 'index.html', 56 | // inject: true, 57 | // minify: { 58 | // removeComments: true, 59 | // collapseWhitespace: true, 60 | // removeAttributeQuotes: true 61 | // // more options: 62 | // // https://github.com/kangax/html-minifier#options-quick-reference 63 | // }, 64 | // // necessary to consistently work with multiple chunks via CommonsChunkPlugin 65 | // chunksSortMode: 'dependency' 66 | // }), 67 | // keep module.id stable when vender modules does not change 68 | new webpack.HashedModuleIdsPlugin(), 69 | // split vendor js into its own file 70 | new webpack.optimize.CommonsChunkPlugin({ 71 | name: 'vendor', 72 | minChunks: function (module, count) { 73 | // any required modules inside node_modules are extracted to vendor 74 | return ( 75 | module.resource && 76 | /\.js$/.test(module.resource) && 77 | module.resource.indexOf('node_modules') >= 0 78 | ) || count > 1 79 | } 80 | }), 81 | // extract webpack runtime and module manifest to its own file in order to 82 | // prevent vendor hash from being updated whenever app bundle is updated 83 | new webpack.optimize.CommonsChunkPlugin({ 84 | name: 'manifest', 85 | chunks: ['vendor'] 86 | }), 87 | // copy custom static assets 88 | new CopyWebpackPlugin([ 89 | { 90 | from: path.resolve(__dirname, '../static'), 91 | to: config.build.assetsSubDirectory, 92 | ignore: ['.*'] 93 | } 94 | ]) 95 | ] 96 | }) 97 | 98 | // if (config.build.productionGzip) { 99 | // var CompressionWebpackPlugin = require('compression-webpack-plugin') 100 | 101 | // webpackConfig.plugins.push( 102 | // new CompressionWebpackPlugin({ 103 | // asset: '[path].gz[query]', 104 | // algorithm: 'gzip', 105 | // test: new RegExp( 106 | // '\\.(' + 107 | // config.build.productionGzipExtensions.join('|') + 108 | // ')$' 109 | // ), 110 | // threshold: 10240, 111 | // minRatio: 0.8 112 | // }) 113 | // ) 114 | // } 115 | 116 | if (config.build.bundleAnalyzerReport) { 117 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 118 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 119 | } 120 | 121 | module.exports = webpackConfig 122 | -------------------------------------------------------------------------------- /src/rules.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * 必填 4 | */ 5 | required: { 6 | message: '此字段必填', 7 | rule(value){ 8 | if(typeof value === 'number'){ 9 | value = value.toString() 10 | }else if(typeof value === 'boolean'){ 11 | return true 12 | } 13 | return !!(value && value.length > 0) 14 | } 15 | }, 16 | /** 17 | * 正则通用 18 | */ 19 | pattern: { 20 | message: '不符合此验证规则', 21 | rule(value, param){ 22 | return param.test(value) 23 | } 24 | }, 25 | /** 26 | * 电子邮件 27 | */ 28 | email: { 29 | message: '请输入有效的电子邮件地址', 30 | rule: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ 31 | }, 32 | /** 33 | * 手机号码 34 | */ 35 | mobile: { 36 | message: '请输入 11 位的手机号码', 37 | rule: /^1[3456789]\d{9}$/ 38 | }, 39 | /** 40 | * 座机号,例如:010-1234567、0551-1234567 41 | */ 42 | tel: { 43 | message: '请输入座机号', 44 | rule: /^(\d{3,4}-)?\d{7,8}$/ 45 | }, 46 | /** 47 | * URL网址 48 | */ 49 | url: { 50 | message: '请输入有效的网址', 51 | rule: /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i 52 | }, 53 | /** 54 | * 身份证号 55 | */ 56 | idcard: { 57 | message: '请输入 18 位的有效身份证', 58 | rule: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/ 59 | }, 60 | /** 61 | * 字段值相同校验(例如:密码和确认密码) 62 | */ 63 | equalTo: { 64 | message: '输入值必须和字段 {0} 相同', 65 | rule(value, param){ 66 | return value === this.data[param] 67 | } 68 | }, 69 | /** 70 | * 字段值不相同校验,与 equalTo 相反 71 | */ 72 | notEqualTo: { 73 | message: '输入值不能和字段 {0} 相同', 74 | rule(value, param){ 75 | return value !== this.data[param] 76 | } 77 | }, 78 | /** 79 | * 是否包含某字符 80 | */ 81 | contains: { 82 | message: '输入值必须包含 {0}', 83 | rule(value, param){ 84 | return value.indexOf(param) > -1 85 | } 86 | }, 87 | /** 88 | * 不能包含某字符 89 | */ 90 | notContains: { 91 | message: '输入值不能包含 {0}', 92 | rule(value, param){ 93 | return value.indexOf(param) === -1 94 | } 95 | }, 96 | /** 97 | * 长度为多少的字符串 98 | */ 99 | length: { 100 | message: '请输入 {0} 个字符', 101 | rule(value, param){ 102 | return value.length == param 103 | } 104 | }, 105 | /** 106 | * 最少多长的字符串 107 | */ 108 | minlength: { 109 | message: '最少要输入 {0} 个字符', 110 | rule(value, param){ 111 | return value.length >= param 112 | } 113 | }, 114 | /** 115 | * 最多多长的字符串 116 | */ 117 | maxlength: { 118 | message: '最多可以输入 {0} 个字符', 119 | rule(value, param){ 120 | return value.length <= param 121 | } 122 | }, 123 | /** 124 | * 某个范围长度的字符串 125 | */ 126 | rangelength: { 127 | message: '请输入长度在 {0} 到 {1} 之间的字符', 128 | rule(value, param){ 129 | return value.length >= param[0] && value.length <= param[1] 130 | } 131 | }, 132 | /** 133 | * 数字 134 | */ 135 | number: { 136 | message: '请输入有效的数字', 137 | rule: /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/ 138 | }, 139 | /** 140 | * 正整数数字 141 | */ 142 | digits: { 143 | message: '只能输入正整数数字', 144 | rule: /^\d+$/ 145 | }, 146 | /** 147 | * 正整数或负整数数字 148 | */ 149 | integer: { 150 | message: '只能输入整数数字', 151 | rule: /^-?\d+$/ 152 | }, 153 | /** 154 | * 大于多少的数字/字段值 155 | */ 156 | min: { 157 | message: '请输入大于 {0} 的数字', 158 | rule(value, param){ 159 | if(typeof param === 'string') param = this.data[param] 160 | 161 | return value >= param 162 | } 163 | }, 164 | /** 165 | * 小于多少的数字/字段值 166 | */ 167 | max: { 168 | message: '请输入小于 {0} 的数字', 169 | rule(value, param){ 170 | if(typeof param === 'string') param = this.data[param] 171 | 172 | return value <= param 173 | } 174 | }, 175 | /** 176 | * 大于且小于多少的数字 177 | */ 178 | range: { 179 | message: '请输入大于 {0} 且小于 {1} 的数字', 180 | rule(value, param){ 181 | return value >= param[0] && value <= param[1] 182 | } 183 | }, 184 | /** 185 | * 中文字符 186 | */ 187 | chinese: { 188 | message: '只能输入中文字符', 189 | rule: /^[\u4e00-\u9fa5]+$/ 190 | }, 191 | /** 192 | * 最少多少个中文字符 193 | */ 194 | minChinese: { 195 | message: '最少输入 {0} 个中文字符', 196 | rule(value, param){ 197 | return new RegExp(`^[\u4e00-\u9fa5]{${param},}$`).test(value) 198 | } 199 | }, 200 | /** 201 | * 最多多少个中文字符 202 | */ 203 | maxChinese: { 204 | message: '最多输入 {0} 个中文字符', 205 | rule(value, param){ 206 | return new RegExp(`^[\u4e00-\u9fa5]{1,${param}}$`).test(value) 207 | } 208 | }, 209 | /** 210 | * 大于且小于多少个中文字符 211 | */ 212 | rangeChinese: { 213 | message: '只能输入 {0} 到 {1} 个中文字符', 214 | rule(value, param){ 215 | return new RegExp(`^[\u4e00-\u9fa5]{${param[0]},${param[1]}}$`).test(value) 216 | } 217 | }, 218 | /** 219 | * 日期 220 | */ 221 | date: { 222 | message: '请输入有效的日期', 223 | rule(value){ 224 | return !/Invalid|NaN/.test(new Date(value).toString()) 225 | } 226 | }, 227 | /** 228 | * 日期(ISO标准格式)例如:2019-09-19,2019/09/19 229 | */ 230 | dateISO: { 231 | message: '请输入有效的日期(ISO 标准格式)', 232 | rule: /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/ 233 | }, 234 | /** 235 | * ipv4地址 236 | */ 237 | ipv4: { 238 | message: '请输入有效的 IPv4 地址', 239 | rule: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i 240 | }, 241 | /** 242 | * ipv6地址 243 | */ 244 | ipv6: { 245 | message: '请输入有效的 IPv6 地址', 246 | rule: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /example/complex/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 复杂案例 we-validator 8 | 66 | 67 | 68 |
69 |
70 | 要求: 71 |
    72 |
  • 关键字:可选,必须以字母 a 开头
  • 73 |
  • 金额:必填,最大金额不能小于最小金额
  • 74 |
  • 爱好:可选,如果选择最少选择两项
  • 75 |
  • 携带人员:必须选爸,不能同时选哥和弟,也不能同时选姐和妹
  • 76 |
  • 喜欢的姓名:可选,不能输入 张三
  • 77 |
  • 性别:选择男性必须输入你的姓名
  • 78 |
79 |
80 | 81 |
82 | 83 | 84 |
85 |

86 | 87 |
88 | 89 | 90 |
91 |

92 | 93 |
94 | 95 | 96 |
97 |

98 | 99 |
100 | 101 |   102 |   103 |   104 | 105 |
106 |

107 | 108 |
109 | 110 |   111 |   112 |   113 |   114 |   115 | 116 |
117 |

118 | 119 |
120 | 121 | 122 |
123 |

124 | 125 |
126 | 127 |   128 | 129 |
130 |

131 |
132 | 133 | 134 |
135 |

136 | 137 | 138 |
139 | 140 | 141 | 142 | 143 | 144 | 260 | 261 | -------------------------------------------------------------------------------- /dist/we-validator.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * we-validator 3 | * version: 2.1.17 4 | * address: https://github.com/ChanceYu/we-validator#readme 5 | * author: ChanceYu 6 | * license: MIT 7 | */ 8 | !function(root,factory){"object"==typeof exports&&"object"==typeof module?module.exports=factory():"function"==typeof define&&define.amd?define("WeValidator",[],factory):"object"==typeof exports?exports.WeValidator=factory():root.WeValidator=factory()}("undefined"!=typeof self?self:this,function(){return function(modules){function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={i:moduleId,l:!1,exports:{}};return modules[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.l=!0,module.exports}var installedModules={};return __webpack_require__.m=modules,__webpack_require__.c=installedModules,__webpack_require__.d=function(exports,name,getter){__webpack_require__.o(exports,name)||Object.defineProperty(exports,name,{configurable:!1,enumerable:!0,get:getter})},__webpack_require__.n=function(module){var getter=module&&module.__esModule?function(){return module.default}:function(){return module};return __webpack_require__.d(getter,"a",getter),getter},__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)},__webpack_require__.p="",__webpack_require__(__webpack_require__.s=0)}([function(module,exports,__webpack_require__){"use strict";function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function defineProperties(target,props){for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:{};_classCallCheck(this,WeValidator),this.options=options,this.required=requiredFn,this._checkAllRules()}return _createClass(WeValidator,[{key:"_showErrorMessage",value:function(params,onMessage){return isFunction(onMessage)?onMessage(params):isFunction(this.options.onMessage)?this.options.onMessage(params):isFunction(WeValidator.onMessage)?WeValidator.onMessage(params):isWx?wx.showToast({title:params.msg,icon:"none"}):isMy?my.showToast({content:params.msg,type:"none"}):isSwan?swan.showToast({title:params.msg,icon:"none"}):isTt?tt.showToast({title:params.msg,icon:"none"}):void(isBrowser&&alert(params.msg))}},{key:"_getErrorMessage",value:function(ruleName,attr,param){var messages=this.options.messages,defaultMessage=WeValidator.RULES[ruleName].message;if(messages&&messages.hasOwnProperty(attr)&&messages[attr][ruleName]&&(defaultMessage=messages[attr][ruleName]),defaultMessage)return defaultMessage=defaultMessage.replace(/\{(\d)\}/g,function($0,$1){return isArray(param)?param[$1]:param})}},{key:"_isRuleInvalid",value:function(ruleName,attr){if(!WeValidator.RULES.hasOwnProperty(ruleName))return console.warn&&console.warn("没有此验证规则:"+ruleName+",字段:"+attr),!0}},{key:"_checkAllRules",value:function(){var _rules_=this.options.rules;for(var attr in _rules_)for(var ruleName in _rules_[attr])this._isRuleInvalid(ruleName,attr)}},{key:"checkData",value:function(data,onMessage){var showMessage=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],fieldMap=arguments[3],_rules_=this.options.rules,multiCheck=this.options.multiCheck,hasError=!1,errorData={};this.data=data;for(var attr in _rules_)if(!fieldMap||fieldMap.hasOwnProperty(attr))for(var ruleName in _rules_[attr])if(!this._isRuleInvalid(ruleName,attr)){if(fieldMap){var res=fieldMap[attr];if(isArray(res)&&-1===res.indexOf(ruleName))continue}var ruleParam=_rules_[attr][ruleName],value="";data.hasOwnProperty(attr)&&(value=data[attr]),isFunction(ruleParam)&&(ruleParam=ruleParam.call(this,value));var isFieldValid=WeValidator.checkValue.call(this,ruleName,value,ruleParam,!0);if(!isFieldValid){hasError=!0;var msg=this._getErrorMessage(ruleName,attr,ruleParam),errorParam=null;if(showMessage&&msg&&(errorParam={name:attr,value:value,param:ruleParam,rule:ruleName,msg:msg},errorData[attr]=errorParam),!multiCheck)return errorParam&&this._showErrorMessage(errorParam,onMessage),!1}}return!hasError||(multiCheck&&showMessage&&this._showErrorMessage(errorData,onMessage),!1)}},{key:"checkFields",value:function(data,fields,onMessage){var showMessage=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];if(!isArray(fields))throw new Error("第二个参数须为数组");var fieldMap={};return fields.forEach(function(item){var arr=item.split(":"),field=arr[0],rules=arr[1];rules?(rules=rules.split(","),fieldMap[field]=rules):fieldMap[field]=!0}),this.checkData(data,onMessage,showMessage,fieldMap)}},{key:"isValid",value:function(data,fields){return isArray(fields)?this.checkFields(data,fields,null,!1):this.checkData(data,null,!1)}},{key:"addRules",value:function(){var options=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};Object.assign(this.options.rules,options.rules||{}),Object.assign(this.options.messages,options.messages||{}),this._checkAllRules()}},{key:"removeRules",value:function(fields){if(!isArray(fields))throw new Error("参数须为数组");for(var i=0;i0)}},pattern:{message:"不符合此验证规则",rule:function(value,param){return param.test(value)}},email:{message:"请输入有效的电子邮件地址",rule:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/},mobile:{message:"请输入 11 位的手机号码",rule:/^1[3456789]\d{9}$/},tel:{message:"请输入座机号",rule:/^(\d{3,4}-)?\d{7,8}$/},url:{message:"请输入有效的网址",rule:/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i},idcard:{message:"请输入 18 位的有效身份证",rule:/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/},equalTo:{message:"输入值必须和字段 {0} 相同",rule:function(value,param){return value===this.data[param]}},notEqualTo:{message:"输入值不能和字段 {0} 相同",rule:function(value,param){return value!==this.data[param]}},contains:{message:"输入值必须包含 {0}",rule:function(value,param){return value.indexOf(param)>-1}},notContains:{message:"输入值不能包含 {0}",rule:function(value,param){return-1===value.indexOf(param)}},length:{message:"请输入 {0} 个字符",rule:function(value,param){return value.length==param}},minlength:{message:"最少要输入 {0} 个字符",rule:function(value,param){return value.length>=param}},maxlength:{message:"最多可以输入 {0} 个字符",rule:function(value,param){return value.length<=param}},rangelength:{message:"请输入长度在 {0} 到 {1} 之间的字符",rule:function(value,param){return value.length>=param[0]&&value.length<=param[1]}},number:{message:"请输入有效的数字",rule:/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/},digits:{message:"只能输入正整数数字",rule:/^\d+$/},integer:{message:"只能输入整数数字",rule:/^-?\d+$/},min:{message:"请输入大于 {0} 的数字",rule:function(value,param){return"string"==typeof param&&(param=this.data[param]),value>=param}},max:{message:"请输入小于 {0} 的数字",rule:function(value,param){return"string"==typeof param&&(param=this.data[param]),value<=param}},range:{message:"请输入大于 {0} 且小于 {1} 的数字",rule:function(value,param){return value>=param[0]&&value<=param[1]}},chinese:{message:"只能输入中文字符",rule:/^[\u4e00-\u9fa5]+$/},minChinese:{message:"最少输入 {0} 个中文字符",rule:function(value,param){return new RegExp("^[一-龥]{"+param+",}$").test(value)}},maxChinese:{message:"最多输入 {0} 个中文字符",rule:function(value,param){return new RegExp("^[一-龥]{1,"+param+"}$").test(value)}},rangeChinese:{message:"只能输入 {0} 到 {1} 个中文字符",rule:function(value,param){return new RegExp("^[一-龥]{"+param[0]+","+param[1]+"}$").test(value)}},date:{message:"请输入有效的日期",rule:function(value){return!/Invalid|NaN/.test(new Date(value).toString())}},dateISO:{message:"请输入有效的日期(ISO 标准格式)",rule:/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/},ipv4:{message:"请输入有效的 IPv4 地址",rule:/^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i},ipv6:{message:"请输入有效的 IPv6 地址",rule:/^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i}}}])}); -------------------------------------------------------------------------------- /src/we-validator.js: -------------------------------------------------------------------------------- 1 | import RULES from './rules' 2 | 3 | const requiredFn = RULES.required.rule 4 | 5 | /** 6 | * 环境检测 7 | */ 8 | const isWx = typeof wx !== 'undefined' && !!wx.showToast // 微信小程序 9 | const isMy = typeof my !== 'undefined' && !!my.showToast // 支付宝小程序 10 | const isSwan = typeof swan !== 'undefined' && !!swan.showToast // 百度智能小程序 11 | const isTt = typeof tt !== 'undefined' && !!tt.showToast // 字节跳动小程序 12 | const isBrowser = typeof window !== 'undefined' && !!window.alert // 普通浏览器 13 | 14 | const objString = Object.prototype.toString 15 | 16 | const isArray = Array.isArray || ((v) => objString.call(v) === '[object Array]') 17 | const isFunction = (v) => (objString.call(v) === '[object Function]') 18 | const isRegExp = (v) => (objString.call(v) === '[object RegExp]') 19 | 20 | class WeValidator { 21 | 22 | /** 23 | * 默认参数 24 | * @param {object} options 25 | * @param {object} [options.rules] 验证字段的规则 26 | * @param {object} [options.messages] 验证字段错误的提示信息 27 | * @param {function} [options.onMessage] 错误信息显示方式 28 | * @param {boolean} [options.multiCheck] 是否同时校验多个字段 29 | */ 30 | constructor(options = {}) { 31 | this.options = options 32 | 33 | this.required = requiredFn 34 | this._checkAllRules() 35 | } 36 | 37 | /** 38 | * 所有校验规则 39 | */ 40 | static RULES = {} 41 | 42 | /** 43 | * 动态添加验证规则 44 | * @param {string} ruleName 规则名称 45 | * @param {object} ruleOption 规则配置 46 | * @param {string} [ruleOption.message] 默认错误信息文字 47 | * @param {regexp|function} [ruleOption.rule] 验证规则 48 | */ 49 | static addRule = function (ruleName, ruleOption) { 50 | WeValidator.RULES[ruleName] = ruleOption 51 | } 52 | 53 | /** 54 | * 验证单个字段数据 55 | * @param {string} ruleName 规则名称 56 | * @param {string} value 要验证的值 57 | * @param {any} param 传递的验证参数 58 | * @param {boolean} skip 未填跳过校验,仅供内部使用 59 | */ 60 | static checkValue = function (ruleName, value, param, skip){ 61 | let rule = WeValidator.RULES[ruleName].rule 62 | 63 | if(isRegExp(rule)){ 64 | if(skip){ 65 | return !requiredFn(value) || rule.test(value) 66 | }else{ 67 | return rule.test(value) 68 | } 69 | } 70 | 71 | if(isFunction(rule)){ 72 | if(ruleName === 'required'){ 73 | return param && requiredFn(value) 74 | }else{ 75 | if(skip){ 76 | return !requiredFn(value) || rule.call(this, value, param) 77 | }else{ 78 | return rule.call(this, value, param) 79 | } 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * 显示错误信息 86 | * @param {object} params 错误信息 87 | * @param {function} onMessage 自定义提示函数 88 | */ 89 | _showErrorMessage(params, onMessage) { 90 | // validatorInstance.checkData(data, onMessage) 91 | if(isFunction(onMessage)){ 92 | return onMessage(params) 93 | } 94 | 95 | // 参数形式 new WeValidator({ onMessage }) 96 | if(isFunction(this.options.onMessage)){ 97 | return this.options.onMessage(params) 98 | } 99 | 100 | // 全局配置 WeValidator.onMessage 101 | if(isFunction(WeValidator.onMessage)){ 102 | return WeValidator.onMessage(params) 103 | } 104 | 105 | // 微信小程序 106 | if(isWx) { 107 | return wx.showToast({ 108 | title: params.msg, 109 | icon: 'none' 110 | }) 111 | } 112 | 113 | // 支付宝小程序 114 | if(isMy){ 115 | return my.showToast({ 116 | content: params.msg, 117 | type: 'none' 118 | }) 119 | } 120 | 121 | // 百度小程序 122 | if(isSwan){ 123 | return swan.showToast({ 124 | title: params.msg, 125 | icon: 'none' 126 | }) 127 | } 128 | 129 | // 字节跳动小程序 130 | if(isTt){ 131 | return tt.showToast({ 132 | title: params.msg, 133 | icon: 'none' 134 | }) 135 | } 136 | 137 | // 浏览器端 138 | if(isBrowser) alert(params.msg) 139 | } 140 | 141 | /** 142 | * 获取错误信息内容 143 | * @param {string} ruleName 规则名称 144 | * @param {string} attr 字段名称 145 | * @param {any} param 规则参数 146 | */ 147 | _getErrorMessage(ruleName, attr, param){ 148 | let messages = this.options.messages 149 | let defaultMessage = WeValidator.RULES[ruleName].message 150 | 151 | if(messages && messages.hasOwnProperty(attr) && messages[attr][ruleName]){ 152 | defaultMessage = messages[attr][ruleName] 153 | } 154 | 155 | if(defaultMessage){ 156 | defaultMessage = defaultMessage.replace(/\{(\d)\}/g, function($0, $1){ 157 | if(isArray(param)){ 158 | return param[$1] 159 | }else{ 160 | return param 161 | } 162 | }) 163 | 164 | return defaultMessage 165 | } 166 | } 167 | 168 | /** 169 | * 验证配置规则是否无效 170 | * @param {string} ruleName 规则名称 171 | * @param {string} attr 字段名称 172 | */ 173 | _isRuleInvalid(ruleName, attr) { 174 | if (!WeValidator.RULES.hasOwnProperty(ruleName)) { 175 | console.warn && console.warn(`没有此验证规则:${ruleName},字段:${attr}`) 176 | return true 177 | } 178 | } 179 | 180 | /** 181 | * 验证所有配置规则是否正确 182 | */ 183 | _checkAllRules() { 184 | let _rules_ = this.options.rules 185 | 186 | // 遍历字段 187 | for (let attr in _rules_) { 188 | // 遍历验证规则 189 | for (let ruleName in _rules_[attr]) { 190 | if (this._isRuleInvalid(ruleName, attr)) continue 191 | } 192 | } 193 | } 194 | 195 | /** 196 | * 校验数据,会验证所有配置的字段规则 197 | * @param {object} data 验证的数据对象 198 | * @param {function} onMessage 自定义错误信息提示 199 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 200 | * @param {object} fieldMap 校验的字段,默认校验所有字段(内部使用) 201 | */ 202 | checkData(data, onMessage, showMessage = true, fieldMap) { 203 | let _rules_ = this.options.rules 204 | let multiCheck = this.options.multiCheck 205 | let hasError = false 206 | let errorData = {} 207 | 208 | this.data = data 209 | 210 | // 遍历字段 211 | for (let attr in _rules_) { 212 | if(fieldMap && !fieldMap.hasOwnProperty(attr)) continue 213 | 214 | // 遍历验证规则 215 | for (let ruleName in _rules_[attr]) { 216 | if (this._isRuleInvalid(ruleName, attr)) continue 217 | 218 | if(fieldMap){ 219 | let res = fieldMap[attr] 220 | if(isArray(res) && res.indexOf(ruleName) === -1) continue 221 | } 222 | 223 | let ruleParam = _rules_[attr][ruleName] 224 | let value = '' 225 | 226 | if (data.hasOwnProperty(attr)) { 227 | value = data[attr] 228 | } 229 | 230 | if(isFunction(ruleParam)){ 231 | ruleParam = ruleParam.call(this, value) 232 | } 233 | 234 | let isFieldValid = WeValidator.checkValue.call(this, ruleName, value, ruleParam, true) 235 | 236 | // 验证不通过 237 | if (!isFieldValid) { 238 | hasError = true 239 | 240 | let msg = this._getErrorMessage(ruleName, attr, ruleParam) 241 | let errorParam = null 242 | 243 | if (showMessage && msg) { 244 | errorParam = { 245 | name: attr, 246 | value: value, 247 | param: ruleParam, 248 | rule: ruleName, 249 | msg: msg 250 | } 251 | errorData[attr] = errorParam 252 | } 253 | 254 | if(!multiCheck){ 255 | if (errorParam) { 256 | this._showErrorMessage(errorParam, onMessage); 257 | } 258 | return false 259 | } 260 | } 261 | } 262 | } 263 | 264 | if(hasError){ 265 | if(multiCheck && showMessage){ 266 | this._showErrorMessage(errorData, onMessage) 267 | } 268 | return false 269 | } 270 | 271 | return true 272 | } 273 | 274 | /** 275 | * 校验数据,只校验对应的字段规则 276 | * @param {object} data 验证的数据对象 277 | * @param {array} fields 校验的字段 278 | * @param {function} onMessage 自定义错误信息提示 279 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 280 | */ 281 | checkFields(data, fields, onMessage, showMessage = true) { 282 | if(!isArray(fields)) throw new Error('第二个参数须为数组') 283 | 284 | // fields: [ '[field]:[rule]' ] 285 | // fields: [ 'phoneNo' ] => { phoneNo: true } 286 | // fields: [ 'phoneNo:required' ] => { phoneNo: ['required'] } 287 | // fields: [ 'phoneNo:required,mobile' ] => { phoneNo: ['required', 'mobile'] } 288 | let fieldMap = {} 289 | 290 | fields.forEach((item) => { 291 | let arr = item.split(':') 292 | let field = arr[0] 293 | let rules = arr[1] 294 | 295 | if(rules){ 296 | // 只校验特定规则 297 | rules = rules.split(',') 298 | fieldMap[field] = rules 299 | }else{ 300 | // 校验 field 字段的所有规则 301 | fieldMap[field] = true 302 | } 303 | }) 304 | 305 | return this.checkData(data, onMessage, showMessage, fieldMap) 306 | } 307 | 308 | /** 309 | * 校验数据,不会提示错误信息 310 | * @param {object} data 验证的数据对象 311 | * @param {array} fields 校验的字段。如果有,只校验对应的字段规则,默认校验所有配置的字段规则 312 | */ 313 | isValid(data, fields) { 314 | if(isArray(fields)){ 315 | return this.checkFields(data, fields, null, false) 316 | }else{ 317 | return this.checkData(data, null, false) 318 | } 319 | } 320 | 321 | /** 322 | * 动态添加字段校验 323 | * @param {object} options 配置参数 324 | * @param {object} [options.rules] 规则 325 | * @param {object} [options.messages] 提示消息 326 | */ 327 | addRules(options = {}) { 328 | Object.assign(this.options.rules, options.rules || {}) 329 | Object.assign(this.options.messages, options.messages || {}) 330 | 331 | this._checkAllRules() 332 | } 333 | 334 | /** 335 | * 动态移除字段校验 336 | * @param {array} fields 要删除校验的字段 337 | */ 338 | removeRules(fields) { 339 | if(!isArray(fields)) throw new Error('参数须为数组') 340 | 341 | for(let i = 0; i < fields.length; i++){ 342 | let key = fields[i] 343 | 344 | delete this.options.rules[key] 345 | } 346 | } 347 | 348 | } 349 | 350 | WeValidator.RULES = RULES 351 | WeValidator.required = requiredFn 352 | 353 | module.exports = WeValidator 354 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | we-validator 3 |

4 |

5 | 6 | 7 | 8 |

9 | 10 | > 2.x 和 1.x 版本有所差别,如果您继续使用老版本,可以查看 [1.x 版本](https://github.com/ChanceYu/we-validator/tree/v1)。如果您要升级到 2.x 请先阅读[升级指南](./UPGRADE.md),推荐使用 2.x 版本。 11 | 12 | 简单灵活的表单验证插件,支持小程序、浏览器、Nodejs。小程序端支持:微信、支付宝、百度智能、字节跳动,小程序默认提示使用 `showToast`。 13 | 14 | [API 文档](#api) | [示例 Examples](#examples),如果你 :sparkling_heart: 就点击 **★Star** 吧。 15 | 16 | ## 特点 17 | 18 | - 使用简单灵活,不依赖任何框架 19 | - 既支持原生小程序方式,也支持 mpvue、wepy、taro 等小程序框架使用 20 | - 支持浏览器以及 Nodejs 端使用 21 | - [支持自定义规则](#wevalidatoraddrulerulename-ruleoption) 22 | - [支持自定义错误信息提示](#wevalidatoronmessage) 23 | - [支持动态添加或移除字段校验](#addrulesoptions) 24 | - [支持单独校验一个或多个字段规则](#checkfieldsdata-fields-onmessage) 25 | - [支持函数校验](#wevalidatorcheckvaluerulename-value-param) 26 | - [支持多个字段同时校验并显示错误](#多个字段同时校验并显示错误) 27 | - [默认支持常用校验规则](#默认支持的规则) 28 | 29 | 30 | 31 | ## 安装 32 | 使用 npm: 33 | 34 | ```bash 35 | npm install we-validator --save 36 | ``` 37 | 38 | 使用 cdn: 39 | 40 | ```html 41 | 42 | ``` 43 | 44 | 45 | ## 使用 46 | 下面是微信小程序的用法,其它小程序类似 47 | 48 |
49 | 点击查看栗子 :chestnut: 50 | 51 | ```html 52 |
53 | 54 | 55 | 56 | 57 | 58 |
59 | ``` 60 | 61 | ```javascript 62 | const WeValidator = require('we-validator') 63 | 64 | Page({ 65 | onReady(){ 66 | this.initValidator() 67 | }, 68 | onSubmitForm(e){ 69 | let { value } = e.detail 70 | 71 | if(!this.validatorInstance.checkData(value)) return 72 | 73 | // 开始提交表单 74 | // wx.request 75 | }, 76 | initValidator(){ 77 | // 实例化 78 | this.validatorInstance = new WeValidator({ 79 | rules: { 80 | username: { 81 | required: true 82 | }, 83 | phoneno: { 84 | required: true, 85 | mobile: true 86 | }, 87 | str: { 88 | length: 3 89 | }, 90 | }, 91 | messages: { 92 | username: { 93 | required: '请输入用户名' 94 | }, 95 | phoneno: { 96 | required: '请输入手机号', 97 | mobile: '手机号格式不正确' 98 | }, 99 | str: { // 非必填字段 100 | length: '请输入长度为3的字符串' 101 | }, 102 | }, 103 | }) 104 | }, 105 | }) 106 | ``` 107 | 108 |
109 | 110 | ## Examples 111 | 您也可参考当前项目下对应示例 112 | 113 | - [原生微信小程序使用方式](./example/wechat/pages/index/index.js) 114 | - [mpvue 使用方式](./example/mpvue/src/pages/index/index.vue) 115 | - [web 浏览器使用方式](./example/web/index.html) 116 | - [Nodejs 端使用方式](./example/nodejs/server/router/home.js) 117 | - [复杂的校验案例-自定义规则-动态添加字段校验](./example/complex/index.html) 118 | 119 | 120 | ## API 121 | - [new WeValidator(options)](#new-wevalidatoroptions) 122 | - [.checkData(data, onMessage)](#checkdatadata-onmessage) 校验数据,会显示错误信息 123 | - [.checkFields(data, fields, onMessage)](#checkfieldsdata-fields-onmessage) 校验数据,会显示错误信息,只校验对应的字段 124 | - [.isValid(data, fields)](#isvaliddata-fields) 校验数据,不会显示错误信息,可单独校验特定字段 125 | - [.addRules(options)](#addrulesoptions) 动态添加字段校验 126 | - [.removeRules(fields)](#removerulesfields) 动态移除字段校验 127 | 128 | 129 | ## Static API 130 | - [WeValidator](#static-api) 131 | - [.addRule(ruleName, ruleOption)](#wevalidatoraddrulerulename-ruleoption) 添加自定义规则 132 | - [.checkValue(ruleName, value, param)](#wevalidatorcheckvaluerulename-value-param) 函数校验,单独校验某个内容 133 | - [.onMessage](#wevalidatoronmessage) 设置全局错误信息显示 134 | 135 | 136 | ## 默认支持的规则 137 | 138 | > 注意: 非必填字段只有字段有值才会校验配置的规则 139 | 140 | | 规则 | 描述 | 默认提示 | 141 | | --- | --- | --- | 142 | | `required: true` | 必填 | 此字段必填 | 143 | | `pattern: /^\d+$/` | 正则通用 | 不符合此验证规则 | 144 | | `email: true` | 电子邮件格式 | 请输入有效的电子邮件地址 | 145 | | `mobile: true` | 11位手机号 | 请输入11位的手机号码 | 146 | | `tel: true` | 座机号
例如:010-1234567、0551-1234567 | 请输入座机号 | 147 | | `url: true` | URL网址 | 请输入有效的网址 | 148 | | `idcard: true` | 身份证号 | 请输入18位的有效身份证 | 149 | | `equalTo: 'field'` | 字段值相同校验
例如:密码和确认密码,[参考](./example/web/index.html#L82) | 输入值必须和字段 `field` 相同 | 150 | | `notEqualTo: 'field'` | 字段值不能相同校验
与 `equalTo` 相反 | 输入值不能和字段 `field` 相同 | 151 | | `contains: 'str'` | 是否包含某字符 | 输入值必须包含 `str` | 152 | | `notContains: 'str'` | 不能包含某字符 | 输入值不能包含 `str` | 153 | | `length: 5` | 长度为多少的字符串 | 请输入 `5` 个字符 | 154 | | `minlength: 2` | 最少多长的字符串 | 最少要输入 `2` 个字符 | 155 | | `maxlength: 6` | 最多多长的字符串 | 最多可以输入 `6` 个字符 | 156 | | `rangelength: [2, 6]` | 某个范围长度的字符串 | 请输入长度在 `2` 到 `6` 之间的字符 | 157 | | `number: true` | 数字 | 请输入有效的数字 | 158 | | `digits: true` | 正整数数字 | 只能输入正整数数字 | 159 | | `integer: true` | 正整数或负整数数字 | 只能输入整数数字 | 160 | | `min: 3` | 大于多少的数字
(最小只能多少),也可以比较字段的值,[参考](./example/complex/index.html#L180) | 请输入大于 `3` 的数字 | 161 | | `max: 9` | 小于多少的数字
(最大只能多少),也可以比较字段的值 | 请输入小于 `9` 的数字 | 162 | | `range: [3, 9]` | 大于且小于多少的数字 | 请输入大于 `3` 且小于 `9` 的数字 | 163 | | `chinese: true` | 中文字符 | 只能输入中文字符 | 164 | | `minChinese: 3` | 最少多少个中文字符 | 最少输入 `3` 个中文字符 | 165 | | `maxChinese: 9` | 最多多少个中文字符 | 最多输入 `9` 个中文字符 | 166 | | `rangeChinese: [3, 9]` | 大于且小于多少个中文字符 | 只能输入 `3` 到 `9` 个中文字符 | 167 | | `date: true` | 日期(默认使用 `new Date(value)` 校验) | 请输入有效的日期 | 168 | | `dateISO: true` | 日期(ISO标准格式)
例如:2019-09-19,2019/09/19 | 请输入有效的日期(ISO标准格式) | 169 | | `ipv4: true` | ipv4地址 | 请输入有效的IPv4地址 | 170 | | `ipv6: true` | ipv6地址 | 请输入有效的IPv6地址 | 171 | 172 | 173 | ## new WeValidator(options) 174 | > 实例化 175 | 176 | **返回**: object - validatorInstance 177 | 178 | | 参数 | 类型 | 默认值 | 描述 | 179 | | --- | --- | --- | --- | 180 | | options | object | | | 181 | | [options.rules] | object | | 验证字段的规则 | 182 | | [options.messages] | object | | 验证字段错误的提示信息 | 183 | | [options.onMessage] | function | | 错误信息显示方式
默认会自动检测环境。小程序默认使用`showToast`
普通web浏览器默认使用`alert`
Nodejs端不做处理建议自己配置,[详情](#wevalidatoronmessage) | 184 | | [options.multiCheck] | boolean | `false` | 是否校验多个字段
需要一次校验多个字段并显示错误信息时使用,[详情](#多个字段同时校验并显示错误) | 185 | 186 |
187 | 点击查看栗子 :chestnut: 188 | 189 | ```javascript 190 | const WeValidator = require('we-validator') 191 | 192 | new WeValidator({ 193 | rules: { 194 | username: { 195 | required: true 196 | }, 197 | phoneno: { 198 | required: true, 199 | mobile: true 200 | } 201 | }, 202 | messages: { 203 | username: { 204 | required: '请输入用户名' 205 | }, 206 | phoneno: { 207 | required: '请输入手机号', 208 | mobile: '手机号格式不正确' 209 | } 210 | } 211 | }) 212 | ``` 213 | 214 |
215 | 216 | ### .checkData(data, onMessage) 217 | > 校验数据,会显示错误信息,校验所有字段规则 218 | 219 | **返回**: boolean 220 | 221 | | 参数 | 类型 | 默认值 | 描述 | 222 | | --- | --- | --- | --- | 223 | | data | object | | 需要校验的表单数据 | 224 | | onMessage | function | | 自定义错误信息提示,[详情](#wevalidatoronmessage) | 225 | 226 | ### .checkFields(data, fields, onMessage) 227 | > 校验数据,会显示错误信息,只校验对应的字段,[参考](./example/mpvue/src/pages/index/index.vue)。 228 | 229 | 通常用于单独校验一个或多个字段规则 230 | 231 | **返回**: boolean 232 | 233 | | 参数 | 类型 | 默认值 | 描述 | 234 | | --- | --- | --- | --- | 235 | | data | object | | 需要校验的表单数据 | 236 | | fields | array | | 校验的字段规则,必填
例如:
`['phoneNo']` 只校验此字段的所有规则
`['phoneNo:required']` 只校验此字段的 `required` 规则
`['phoneNo:required,mobile']` 只校验此字段的 `required` 和 `mobile` 规则
`['phoneNo', 'code']` 只校验这两个字段的所有规则 | 237 | | onMessage | function | | 自定义错误信息提示,[详情](#wevalidatoronmessage) | 238 | 239 | ### .isValid(data, fields) 240 | > 校验数据是否有效,不会提示错误信息 241 | 242 | 使用场景例如:表单中某些字段校验通过按钮才可点击的场景,[参考](./example/mpvue/src/pages/index/index.vue)。 243 | 244 | **返回**: boolean 245 | 246 | | 参数 | 类型 | 默认值 | 描述 | 247 | | --- | --- | --- | --- | 248 | | data | object | | 需要校验的表单数据 | 249 | | fields | array | | 校验的字段
不传,默认校验所有字段规则
如果有,只校验对应的字段规则
配置方法同 `.checkFields(data, fields)` | 250 | 251 | ### .addRules(options) 252 | > 动态添加字段校验,[参考](./example/complex/index.html#L235) 253 | 254 | | 参数 | 类型 | 默认值 | 描述 | 255 | | --- | --- | --- | --- | 256 | | options | object | | 同 `new WeValidator(options)` ,[详情](#new-wevalidatoroptions) | 257 | 258 | 259 |
260 | 点击查看栗子 :chestnut: 261 | 262 | ```javascript 263 | const WeValidator = require('we-validator') 264 | 265 | const validatorInstance = new WeValidator({ 266 | rules: { 267 | username: { 268 | required: true 269 | } 270 | }, 271 | messages: { 272 | username: { 273 | required: '请输入用户名' 274 | } 275 | } 276 | }) 277 | 278 | // 动态添加校验 279 | validatorInstance.addRules({ 280 | rules: { 281 | phoneno: { 282 | required: true, 283 | mobile: true 284 | } 285 | }, 286 | messages: { 287 | phoneno: { 288 | required: '请输入手机号', 289 | mobile: '手机号格式不正确' 290 | } 291 | } 292 | }) 293 | ``` 294 | 295 |
296 | 297 | ### .removeRules(fields) 298 | > 动态移除字段校验,[参考](./example/complex/index.html#L235) 299 | 300 | | 参数 | 类型 | 默认值 | 描述 | 301 | | --- | --- | --- | --- | 302 | | fields | array | | 需要移除校验的表单字段 | 303 | 304 | ```javascript 305 | validatorInstance.removeRules(['username']) 306 | ``` 307 | 308 | ## WeValidator.addRule(ruleName, ruleOption) 309 | > 静态方法:添加自定义规则,[参考](./example/complex/index.html) 310 | 311 | | 参数 | 类型 | 默认值 | 描述 | 312 | | --- | --- | --- | --- | 313 | | ruleName | string | | 规则名称 | 314 | | ruleOption | object | | 规则配置 | 315 | | [ruleOption.message] | string | | 默认错误信息文字
可以动态插入参数,例如 `请输入长度在 {0} 到 {1} 之间的字符`,[参考](./src/rules.js#L127) | 316 | | [ruleOption.rule] | function\|regexp | | 规则校验函数,需要返回一个 `boolean`。
也可以直接写一个正则表达式(如果只是正则类型的校验)。 | 317 | 318 |
319 | 点击查看栗子 :chestnut: 320 | 321 | ```javascript 322 | const WeValidator = require('we-validator') 323 | 324 | // 添加自定义规则(这两种写法一样) 325 | WeValidator.addRule('theRuleName', { 326 | message: '默认错误信息文字', 327 | rule(value, param){ 328 | return /\d/.test(value) 329 | } 330 | }) 331 | WeValidator.addRule('theRuleName', { 332 | message: '默认错误信息文字', 333 | rule: /\d/ 334 | }) 335 | 336 | // 使用方式一,实例化 337 | new WeValidator({ 338 | rules: { 339 | field1: { 340 | theRuleName: true 341 | } 342 | }, 343 | messages: { 344 | field1: { 345 | theRuleName: '提示信息' 346 | } 347 | } 348 | }) 349 | 350 | // 使用方式二,调用函数 351 | WeValidator.checkValue('theRuleName', 'str') 352 | ``` 353 | 354 |
355 | 356 | 357 | ## WeValidator.checkValue(ruleName, value, param) 358 | > 静态方法:函数校验 359 | 360 | | 参数 | 类型 | 默认值 | 描述 | 361 | | --- | --- | --- | --- | 362 | | ruleName | string | | 规则名称 | 363 | | value | string | | 需要校验的内容 | 364 | | param | any | | 传递给规则参数 | 365 | 366 | 支持所有[默认支持的规则](#默认支持的规则),也支持自定义的规则。 367 | 368 | ```javascript 369 | // 必填 370 | let b1 = WeValidator.checkValue('required', 'str') // true 371 | 372 | // 不能小于6的数字 373 | let b2 = WeValidator.checkValue('min', 'str', 6) // false 374 | 375 | // 大于2小于5的数字 376 | let b3 = WeValidator.checkValue('range', 'str', [2, 5]) // false 377 | ``` 378 | 379 | ## WeValidator.onMessage 380 | > 自定义错误信息提示 381 | 382 | 可以全局配置一个,也可以单独配置,非常灵活。 383 | 384 | 优先级是:`.checkData(data, onMessage)` > `new WeValidator({ onMessage })` > `WeValidator.onMessage` > 默认检测 385 | 386 | 默认的消息提示方式:小程序默认使用`showToast`,浏览器默认使用`alert`,Nodejs端无处理建议自己配置。 387 | 388 |
389 | 点击查看栗子 :chestnut: 390 | 391 | ```javascript 392 | const WeValidator = require('we-validator') 393 | 394 | // 1、全局配置 395 | WeValidator.onMessage = function(data){ 396 | /* 397 | data 参数 398 | { 399 | msg, // 提示文字 400 | name, // 表单控件的 name 401 | value, // 表单控件的值 402 | param // rules 验证字段传递的参数 403 | } 404 | */ 405 | } 406 | 407 | // 2、实例化配置 408 | new WeValidator({ 409 | rules: {}, 410 | message: {}, 411 | onMessage: function(data){ 412 | alert(data.msg) 413 | } 414 | }) 415 | 416 | // 3、验证的时候配置 onMessage(nodejs端校验可以使用此方式) 417 | if(!obj.checkData(formData, onMessage)) return 418 | 419 | function onMessage(data){ 420 | alert(data.msg) 421 | } 422 | ``` 423 | 424 |
425 | 426 | ### 多个字段同时校验并显示错误 427 | 使用场景如下,**注意:当`multiCheck`为`true`时,建议使用自定义`onMessage`**,[参考](./example/web/index.html) 428 | 429 | ![we-validator](./assets/demo_multi.png) 430 | 431 |
432 | 点击查看栗子 :chestnut: 433 | 434 | ```javascript 435 | var validatorInstance = new WeValidator({ 436 | multiCheck: true, 437 | onMessage: function(data){ 438 | console.log(data); 439 | 440 | // 根据自己的项目去处理,控制错误信息的显示 441 | }, 442 | rules: { 443 | username: { 444 | required: true 445 | }, 446 | phoneno: { 447 | required: true, 448 | mobile: true 449 | } 450 | }, 451 | messages: { 452 | username: { 453 | required: '请输入用户名' 454 | }, 455 | phoneno: { 456 | required: '请输入手机号', 457 | mobile: '手机号格式不正确' 458 | } 459 | } 460 | }); 461 | ``` 462 | 463 |
464 | 465 | ## Changelog 466 | [查看更新日志](./CHANGELOG.md) 467 | 468 | ## Issues 469 | 如果您在使用过程中发现 Bug,或者有好的建议,欢迎[报告问题](https://github.com/ChanceYu/we-validator/issues)。 470 | 471 | ## License 472 | 473 | [![license][img-mit]][url-mit] 474 | 475 | Copyright (c) 2019 ChanceYu 476 | 477 | [url-github]: https://github.com/ChanceYu/we-validator 478 | [url-npm]: https://www.npmjs.com/package/we-validator 479 | [url-travis]: https://travis-ci.org/ChanceYu/we-validator 480 | [url-mit]: https://opensource.org/licenses/mit-license.php 481 | 482 | [img-npm]: https://nodei.co/npm/we-validator.png?compact=true 483 | [img-travis]: https://travis-ci.org/ChanceYu/we-validator.svg?branch=master 484 | [img-javascript]: https://img.shields.io/badge/language-JavaScript-brightgreen.svg 485 | [img-mit]: https://img.shields.io/npm/l/we-validator.svg 486 | 487 | -------------------------------------------------------------------------------- /dist/we-validator.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * we-validator 3 | * version: 2.1.17 4 | * address: https://github.com/ChanceYu/we-validator#readme 5 | * author: ChanceYu 6 | * license: MIT 7 | */ 8 | (function webpackUniversalModuleDefinition(root, factory) { 9 | if(typeof exports === 'object' && typeof module === 'object') 10 | module.exports = factory(); 11 | else if(typeof define === 'function' && define.amd) 12 | define("WeValidator", [], factory); 13 | else if(typeof exports === 'object') 14 | exports["WeValidator"] = factory(); 15 | else 16 | root["WeValidator"] = factory(); 17 | })(typeof self !== 'undefined' ? self : this, function() { 18 | return /******/ (function(modules) { // webpackBootstrap 19 | /******/ // The module cache 20 | /******/ var installedModules = {}; 21 | /******/ 22 | /******/ // The require function 23 | /******/ function __webpack_require__(moduleId) { 24 | /******/ 25 | /******/ // Check if module is in cache 26 | /******/ if(installedModules[moduleId]) { 27 | /******/ return installedModules[moduleId].exports; 28 | /******/ } 29 | /******/ // Create a new module (and put it into the cache) 30 | /******/ var module = installedModules[moduleId] = { 31 | /******/ i: moduleId, 32 | /******/ l: false, 33 | /******/ exports: {} 34 | /******/ }; 35 | /******/ 36 | /******/ // Execute the module function 37 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 38 | /******/ 39 | /******/ // Flag the module as loaded 40 | /******/ module.l = true; 41 | /******/ 42 | /******/ // Return the exports of the module 43 | /******/ return module.exports; 44 | /******/ } 45 | /******/ 46 | /******/ 47 | /******/ // expose the modules object (__webpack_modules__) 48 | /******/ __webpack_require__.m = modules; 49 | /******/ 50 | /******/ // expose the module cache 51 | /******/ __webpack_require__.c = installedModules; 52 | /******/ 53 | /******/ // define getter function for harmony exports 54 | /******/ __webpack_require__.d = function(exports, name, getter) { 55 | /******/ if(!__webpack_require__.o(exports, name)) { 56 | /******/ Object.defineProperty(exports, name, { 57 | /******/ configurable: false, 58 | /******/ enumerable: true, 59 | /******/ get: getter 60 | /******/ }); 61 | /******/ } 62 | /******/ }; 63 | /******/ 64 | /******/ // getDefaultExport function for compatibility with non-harmony modules 65 | /******/ __webpack_require__.n = function(module) { 66 | /******/ var getter = module && module.__esModule ? 67 | /******/ function getDefault() { return module['default']; } : 68 | /******/ function getModuleExports() { return module; }; 69 | /******/ __webpack_require__.d(getter, 'a', getter); 70 | /******/ return getter; 71 | /******/ }; 72 | /******/ 73 | /******/ // Object.prototype.hasOwnProperty.call 74 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 75 | /******/ 76 | /******/ // __webpack_public_path__ 77 | /******/ __webpack_require__.p = ""; 78 | /******/ 79 | /******/ // Load entry module and return exports 80 | /******/ return __webpack_require__(__webpack_require__.s = 0); 81 | /******/ }) 82 | /************************************************************************/ 83 | /******/ ([ 84 | /* 0 */ 85 | /***/ (function(module, exports, __webpack_require__) { 86 | 87 | "use strict"; 88 | 89 | 90 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 91 | 92 | var _rules = __webpack_require__(1); 93 | 94 | var _rules2 = _interopRequireDefault(_rules); 95 | 96 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 97 | 98 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 99 | 100 | var requiredFn = _rules2.default.required.rule; 101 | 102 | /** 103 | * 环境检测 104 | */ 105 | var isWx = typeof wx !== 'undefined' && !!wx.showToast; // 微信小程序 106 | var isMy = typeof my !== 'undefined' && !!my.showToast; // 支付宝小程序 107 | var isSwan = typeof swan !== 'undefined' && !!swan.showToast; // 百度智能小程序 108 | var isTt = typeof tt !== 'undefined' && !!tt.showToast; // 字节跳动小程序 109 | var isBrowser = typeof window !== 'undefined' && !!window.alert; // 普通浏览器 110 | 111 | var objString = Object.prototype.toString; 112 | 113 | var isArray = Array.isArray || function (v) { 114 | return objString.call(v) === '[object Array]'; 115 | }; 116 | var isFunction = function isFunction(v) { 117 | return objString.call(v) === '[object Function]'; 118 | }; 119 | var isRegExp = function isRegExp(v) { 120 | return objString.call(v) === '[object RegExp]'; 121 | }; 122 | 123 | var WeValidator = function () { 124 | 125 | /** 126 | * 默认参数 127 | * @param {object} options 128 | * @param {object} [options.rules] 验证字段的规则 129 | * @param {object} [options.messages] 验证字段错误的提示信息 130 | * @param {function} [options.onMessage] 错误信息显示方式 131 | * @param {boolean} [options.multiCheck] 是否同时校验多个字段 132 | */ 133 | function WeValidator() { 134 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 135 | 136 | _classCallCheck(this, WeValidator); 137 | 138 | this.options = options; 139 | 140 | this.required = requiredFn; 141 | this._checkAllRules(); 142 | } 143 | 144 | /** 145 | * 所有校验规则 146 | */ 147 | 148 | 149 | /** 150 | * 动态添加验证规则 151 | * @param {string} ruleName 规则名称 152 | * @param {object} ruleOption 规则配置 153 | * @param {string} [ruleOption.message] 默认错误信息文字 154 | * @param {regexp|function} [ruleOption.rule] 验证规则 155 | */ 156 | 157 | 158 | /** 159 | * 验证单个字段数据 160 | * @param {string} ruleName 规则名称 161 | * @param {string} value 要验证的值 162 | * @param {any} param 传递的验证参数 163 | * @param {boolean} skip 未填跳过校验,仅供内部使用 164 | */ 165 | 166 | 167 | _createClass(WeValidator, [{ 168 | key: '_showErrorMessage', 169 | 170 | 171 | /** 172 | * 显示错误信息 173 | * @param {object} params 错误信息 174 | * @param {function} onMessage 自定义提示函数 175 | */ 176 | value: function _showErrorMessage(params, onMessage) { 177 | // validatorInstance.checkData(data, onMessage) 178 | if (isFunction(onMessage)) { 179 | return onMessage(params); 180 | } 181 | 182 | // 参数形式 new WeValidator({ onMessage }) 183 | if (isFunction(this.options.onMessage)) { 184 | return this.options.onMessage(params); 185 | } 186 | 187 | // 全局配置 WeValidator.onMessage 188 | if (isFunction(WeValidator.onMessage)) { 189 | return WeValidator.onMessage(params); 190 | } 191 | 192 | // 微信小程序 193 | if (isWx) { 194 | return wx.showToast({ 195 | title: params.msg, 196 | icon: 'none' 197 | }); 198 | } 199 | 200 | // 支付宝小程序 201 | if (isMy) { 202 | return my.showToast({ 203 | content: params.msg, 204 | type: 'none' 205 | }); 206 | } 207 | 208 | // 百度小程序 209 | if (isSwan) { 210 | return swan.showToast({ 211 | title: params.msg, 212 | icon: 'none' 213 | }); 214 | } 215 | 216 | // 字节跳动小程序 217 | if (isTt) { 218 | return tt.showToast({ 219 | title: params.msg, 220 | icon: 'none' 221 | }); 222 | } 223 | 224 | // 浏览器端 225 | if (isBrowser) alert(params.msg); 226 | } 227 | 228 | /** 229 | * 获取错误信息内容 230 | * @param {string} ruleName 规则名称 231 | * @param {string} attr 字段名称 232 | * @param {any} param 规则参数 233 | */ 234 | 235 | }, { 236 | key: '_getErrorMessage', 237 | value: function _getErrorMessage(ruleName, attr, param) { 238 | var messages = this.options.messages; 239 | var defaultMessage = WeValidator.RULES[ruleName].message; 240 | 241 | if (messages && messages.hasOwnProperty(attr) && messages[attr][ruleName]) { 242 | defaultMessage = messages[attr][ruleName]; 243 | } 244 | 245 | if (defaultMessage) { 246 | defaultMessage = defaultMessage.replace(/\{(\d)\}/g, function ($0, $1) { 247 | if (isArray(param)) { 248 | return param[$1]; 249 | } else { 250 | return param; 251 | } 252 | }); 253 | 254 | return defaultMessage; 255 | } 256 | } 257 | 258 | /** 259 | * 验证配置规则是否无效 260 | * @param {string} ruleName 规则名称 261 | * @param {string} attr 字段名称 262 | */ 263 | 264 | }, { 265 | key: '_isRuleInvalid', 266 | value: function _isRuleInvalid(ruleName, attr) { 267 | if (!WeValidator.RULES.hasOwnProperty(ruleName)) { 268 | console.warn && console.warn('\u6CA1\u6709\u6B64\u9A8C\u8BC1\u89C4\u5219\uFF1A' + ruleName + '\uFF0C\u5B57\u6BB5\uFF1A' + attr); 269 | return true; 270 | } 271 | } 272 | 273 | /** 274 | * 验证所有配置规则是否正确 275 | */ 276 | 277 | }, { 278 | key: '_checkAllRules', 279 | value: function _checkAllRules() { 280 | var _rules_ = this.options.rules; 281 | 282 | // 遍历字段 283 | for (var attr in _rules_) { 284 | // 遍历验证规则 285 | for (var ruleName in _rules_[attr]) { 286 | if (this._isRuleInvalid(ruleName, attr)) continue; 287 | } 288 | } 289 | } 290 | 291 | /** 292 | * 校验数据,会验证所有配置的字段规则 293 | * @param {object} data 验证的数据对象 294 | * @param {function} onMessage 自定义错误信息提示 295 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 296 | * @param {object} fieldMap 校验的字段,默认校验所有字段(内部使用) 297 | */ 298 | 299 | }, { 300 | key: 'checkData', 301 | value: function checkData(data, onMessage) { 302 | var showMessage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 303 | var fieldMap = arguments[3]; 304 | 305 | var _rules_ = this.options.rules; 306 | var multiCheck = this.options.multiCheck; 307 | var hasError = false; 308 | var errorData = {}; 309 | 310 | this.data = data; 311 | 312 | // 遍历字段 313 | for (var attr in _rules_) { 314 | if (fieldMap && !fieldMap.hasOwnProperty(attr)) continue; 315 | 316 | // 遍历验证规则 317 | for (var ruleName in _rules_[attr]) { 318 | if (this._isRuleInvalid(ruleName, attr)) continue; 319 | 320 | if (fieldMap) { 321 | var res = fieldMap[attr]; 322 | if (isArray(res) && res.indexOf(ruleName) === -1) continue; 323 | } 324 | 325 | var ruleParam = _rules_[attr][ruleName]; 326 | var value = ''; 327 | 328 | if (data.hasOwnProperty(attr)) { 329 | value = data[attr]; 330 | } 331 | 332 | if (isFunction(ruleParam)) { 333 | ruleParam = ruleParam.call(this, value); 334 | } 335 | 336 | var isFieldValid = WeValidator.checkValue.call(this, ruleName, value, ruleParam, true); 337 | 338 | // 验证不通过 339 | if (!isFieldValid) { 340 | hasError = true; 341 | 342 | var msg = this._getErrorMessage(ruleName, attr, ruleParam); 343 | var errorParam = null; 344 | 345 | if (showMessage && msg) { 346 | errorParam = { 347 | name: attr, 348 | value: value, 349 | param: ruleParam, 350 | rule: ruleName, 351 | msg: msg 352 | }; 353 | errorData[attr] = errorParam; 354 | } 355 | 356 | if (!multiCheck) { 357 | if (errorParam) { 358 | this._showErrorMessage(errorParam, onMessage); 359 | } 360 | return false; 361 | } 362 | } 363 | } 364 | } 365 | 366 | if (hasError) { 367 | if (multiCheck && showMessage) { 368 | this._showErrorMessage(errorData, onMessage); 369 | } 370 | return false; 371 | } 372 | 373 | return true; 374 | } 375 | 376 | /** 377 | * 校验数据,只校验对应的字段规则 378 | * @param {object} data 验证的数据对象 379 | * @param {array} fields 校验的字段 380 | * @param {function} onMessage 自定义错误信息提示 381 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 382 | */ 383 | 384 | }, { 385 | key: 'checkFields', 386 | value: function checkFields(data, fields, onMessage) { 387 | var showMessage = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; 388 | 389 | if (!isArray(fields)) throw new Error('第二个参数须为数组'); 390 | 391 | // fields: [ '[field]:[rule]' ] 392 | // fields: [ 'phoneNo' ] => { phoneNo: true } 393 | // fields: [ 'phoneNo:required' ] => { phoneNo: ['required'] } 394 | // fields: [ 'phoneNo:required,mobile' ] => { phoneNo: ['required', 'mobile'] } 395 | var fieldMap = {}; 396 | 397 | fields.forEach(function (item) { 398 | var arr = item.split(':'); 399 | var field = arr[0]; 400 | var rules = arr[1]; 401 | 402 | if (rules) { 403 | // 只校验特定规则 404 | rules = rules.split(','); 405 | fieldMap[field] = rules; 406 | } else { 407 | // 校验 field 字段的所有规则 408 | fieldMap[field] = true; 409 | } 410 | }); 411 | 412 | return this.checkData(data, onMessage, showMessage, fieldMap); 413 | } 414 | 415 | /** 416 | * 校验数据,不会提示错误信息 417 | * @param {object} data 验证的数据对象 418 | * @param {array} fields 校验的字段。如果有,只校验对应的字段规则,默认校验所有配置的字段规则 419 | */ 420 | 421 | }, { 422 | key: 'isValid', 423 | value: function isValid(data, fields) { 424 | if (isArray(fields)) { 425 | return this.checkFields(data, fields, null, false); 426 | } else { 427 | return this.checkData(data, null, false); 428 | } 429 | } 430 | 431 | /** 432 | * 动态添加字段校验 433 | * @param {object} options 配置参数 434 | * @param {object} [options.rules] 规则 435 | * @param {object} [options.messages] 提示消息 436 | */ 437 | 438 | }, { 439 | key: 'addRules', 440 | value: function addRules() { 441 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 442 | 443 | Object.assign(this.options.rules, options.rules || {}); 444 | Object.assign(this.options.messages, options.messages || {}); 445 | 446 | this._checkAllRules(); 447 | } 448 | 449 | /** 450 | * 动态移除字段校验 451 | * @param {array} fields 要删除校验的字段 452 | */ 453 | 454 | }, { 455 | key: 'removeRules', 456 | value: function removeRules(fields) { 457 | if (!isArray(fields)) throw new Error('参数须为数组'); 458 | 459 | for (var i = 0; i < fields.length; i++) { 460 | var key = fields[i]; 461 | 462 | delete this.options.rules[key]; 463 | } 464 | } 465 | }]); 466 | 467 | return WeValidator; 468 | }(); 469 | 470 | WeValidator.RULES = {}; 471 | 472 | WeValidator.addRule = function (ruleName, ruleOption) { 473 | WeValidator.RULES[ruleName] = ruleOption; 474 | }; 475 | 476 | WeValidator.checkValue = function (ruleName, value, param, skip) { 477 | var rule = WeValidator.RULES[ruleName].rule; 478 | 479 | if (isRegExp(rule)) { 480 | if (skip) { 481 | return !requiredFn(value) || rule.test(value); 482 | } else { 483 | return rule.test(value); 484 | } 485 | } 486 | 487 | if (isFunction(rule)) { 488 | if (ruleName === 'required') { 489 | return param && requiredFn(value); 490 | } else { 491 | if (skip) { 492 | return !requiredFn(value) || rule.call(this, value, param); 493 | } else { 494 | return rule.call(this, value, param); 495 | } 496 | } 497 | } 498 | }; 499 | 500 | WeValidator.RULES = _rules2.default; 501 | WeValidator.required = requiredFn; 502 | 503 | module.exports = WeValidator; 504 | 505 | /***/ }), 506 | /* 1 */ 507 | /***/ (function(module, exports, __webpack_require__) { 508 | 509 | "use strict"; 510 | 511 | 512 | module.exports = { 513 | /** 514 | * 必填 515 | */ 516 | required: { 517 | message: '此字段必填', 518 | rule: function rule(value) { 519 | if (typeof value === 'number') { 520 | value = value.toString(); 521 | } else if (typeof value === 'boolean') { 522 | return true; 523 | } 524 | return !!(value && value.length > 0); 525 | } 526 | }, 527 | /** 528 | * 正则通用 529 | */ 530 | pattern: { 531 | message: '不符合此验证规则', 532 | rule: function rule(value, param) { 533 | return param.test(value); 534 | } 535 | }, 536 | /** 537 | * 电子邮件 538 | */ 539 | email: { 540 | message: '请输入有效的电子邮件地址', 541 | rule: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ 542 | }, 543 | /** 544 | * 手机号码 545 | */ 546 | mobile: { 547 | message: '请输入 11 位的手机号码', 548 | rule: /^1[3456789]\d{9}$/ 549 | }, 550 | /** 551 | * 座机号,例如:010-1234567、0551-1234567 552 | */ 553 | tel: { 554 | message: '请输入座机号', 555 | rule: /^(\d{3,4}-)?\d{7,8}$/ 556 | }, 557 | /** 558 | * URL网址 559 | */ 560 | url: { 561 | message: '请输入有效的网址', 562 | rule: /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i 563 | }, 564 | /** 565 | * 身份证号 566 | */ 567 | idcard: { 568 | message: '请输入 18 位的有效身份证', 569 | rule: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/ 570 | }, 571 | /** 572 | * 字段值相同校验(例如:密码和确认密码) 573 | */ 574 | equalTo: { 575 | message: '输入值必须和字段 {0} 相同', 576 | rule: function rule(value, param) { 577 | return value === this.data[param]; 578 | } 579 | }, 580 | /** 581 | * 字段值不相同校验,与 equalTo 相反 582 | */ 583 | notEqualTo: { 584 | message: '输入值不能和字段 {0} 相同', 585 | rule: function rule(value, param) { 586 | return value !== this.data[param]; 587 | } 588 | }, 589 | /** 590 | * 是否包含某字符 591 | */ 592 | contains: { 593 | message: '输入值必须包含 {0}', 594 | rule: function rule(value, param) { 595 | return value.indexOf(param) > -1; 596 | } 597 | }, 598 | /** 599 | * 不能包含某字符 600 | */ 601 | notContains: { 602 | message: '输入值不能包含 {0}', 603 | rule: function rule(value, param) { 604 | return value.indexOf(param) === -1; 605 | } 606 | }, 607 | /** 608 | * 长度为多少的字符串 609 | */ 610 | length: { 611 | message: '请输入 {0} 个字符', 612 | rule: function rule(value, param) { 613 | return value.length == param; 614 | } 615 | }, 616 | /** 617 | * 最少多长的字符串 618 | */ 619 | minlength: { 620 | message: '最少要输入 {0} 个字符', 621 | rule: function rule(value, param) { 622 | return value.length >= param; 623 | } 624 | }, 625 | /** 626 | * 最多多长的字符串 627 | */ 628 | maxlength: { 629 | message: '最多可以输入 {0} 个字符', 630 | rule: function rule(value, param) { 631 | return value.length <= param; 632 | } 633 | }, 634 | /** 635 | * 某个范围长度的字符串 636 | */ 637 | rangelength: { 638 | message: '请输入长度在 {0} 到 {1} 之间的字符', 639 | rule: function rule(value, param) { 640 | return value.length >= param[0] && value.length <= param[1]; 641 | } 642 | }, 643 | /** 644 | * 数字 645 | */ 646 | number: { 647 | message: '请输入有效的数字', 648 | rule: /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/ 649 | }, 650 | /** 651 | * 正整数数字 652 | */ 653 | digits: { 654 | message: '只能输入正整数数字', 655 | rule: /^\d+$/ 656 | }, 657 | /** 658 | * 正整数或负整数数字 659 | */ 660 | integer: { 661 | message: '只能输入整数数字', 662 | rule: /^-?\d+$/ 663 | }, 664 | /** 665 | * 大于多少的数字/字段值 666 | */ 667 | min: { 668 | message: '请输入大于 {0} 的数字', 669 | rule: function rule(value, param) { 670 | if (typeof param === 'string') param = this.data[param]; 671 | 672 | return value >= param; 673 | } 674 | }, 675 | /** 676 | * 小于多少的数字/字段值 677 | */ 678 | max: { 679 | message: '请输入小于 {0} 的数字', 680 | rule: function rule(value, param) { 681 | if (typeof param === 'string') param = this.data[param]; 682 | 683 | return value <= param; 684 | } 685 | }, 686 | /** 687 | * 大于且小于多少的数字 688 | */ 689 | range: { 690 | message: '请输入大于 {0} 且小于 {1} 的数字', 691 | rule: function rule(value, param) { 692 | return value >= param[0] && value <= param[1]; 693 | } 694 | }, 695 | /** 696 | * 中文字符 697 | */ 698 | chinese: { 699 | message: '只能输入中文字符', 700 | rule: /^[\u4e00-\u9fa5]+$/ 701 | }, 702 | /** 703 | * 最少多少个中文字符 704 | */ 705 | minChinese: { 706 | message: '最少输入 {0} 个中文字符', 707 | rule: function rule(value, param) { 708 | return new RegExp('^[\u4E00-\u9FA5]{' + param + ',}$').test(value); 709 | } 710 | }, 711 | /** 712 | * 最多多少个中文字符 713 | */ 714 | maxChinese: { 715 | message: '最多输入 {0} 个中文字符', 716 | rule: function rule(value, param) { 717 | return new RegExp('^[\u4E00-\u9FA5]{1,' + param + '}$').test(value); 718 | } 719 | }, 720 | /** 721 | * 大于且小于多少个中文字符 722 | */ 723 | rangeChinese: { 724 | message: '只能输入 {0} 到 {1} 个中文字符', 725 | rule: function rule(value, param) { 726 | return new RegExp('^[\u4E00-\u9FA5]{' + param[0] + ',' + param[1] + '}$').test(value); 727 | } 728 | }, 729 | /** 730 | * 日期 731 | */ 732 | date: { 733 | message: '请输入有效的日期', 734 | rule: function rule(value) { 735 | return !/Invalid|NaN/.test(new Date(value).toString()); 736 | } 737 | }, 738 | /** 739 | * 日期(ISO标准格式)例如:2019-09-19,2019/09/19 740 | */ 741 | dateISO: { 742 | message: '请输入有效的日期(ISO 标准格式)', 743 | rule: /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/ 744 | }, 745 | /** 746 | * ipv4地址 747 | */ 748 | ipv4: { 749 | message: '请输入有效的 IPv4 地址', 750 | rule: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i 751 | }, 752 | /** 753 | * ipv6地址 754 | */ 755 | ipv6: { 756 | message: '请输入有效的 IPv6 地址', 757 | rule: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i 758 | } 759 | }; 760 | 761 | /***/ }) 762 | /******/ ]); 763 | }); -------------------------------------------------------------------------------- /lib/we-validator.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * we-validator 3 | * version: 2.1.17 4 | * address: https://github.com/ChanceYu/we-validator#readme 5 | * author: ChanceYu 6 | * license: MIT 7 | */ 8 | (function webpackUniversalModuleDefinition(root, factory) { 9 | if(typeof exports === 'object' && typeof module === 'object') 10 | module.exports = factory(); 11 | else if(typeof define === 'function' && define.amd) 12 | define("WeValidator", [], factory); 13 | else if(typeof exports === 'object') 14 | exports["WeValidator"] = factory(); 15 | else 16 | root["WeValidator"] = factory(); 17 | })(typeof self !== 'undefined' ? self : this, function() { 18 | return /******/ (function(modules) { // webpackBootstrap 19 | /******/ // The module cache 20 | /******/ var installedModules = {}; 21 | /******/ 22 | /******/ // The require function 23 | /******/ function __webpack_require__(moduleId) { 24 | /******/ 25 | /******/ // Check if module is in cache 26 | /******/ if(installedModules[moduleId]) { 27 | /******/ return installedModules[moduleId].exports; 28 | /******/ } 29 | /******/ // Create a new module (and put it into the cache) 30 | /******/ var module = installedModules[moduleId] = { 31 | /******/ i: moduleId, 32 | /******/ l: false, 33 | /******/ exports: {} 34 | /******/ }; 35 | /******/ 36 | /******/ // Execute the module function 37 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 38 | /******/ 39 | /******/ // Flag the module as loaded 40 | /******/ module.l = true; 41 | /******/ 42 | /******/ // Return the exports of the module 43 | /******/ return module.exports; 44 | /******/ } 45 | /******/ 46 | /******/ 47 | /******/ // expose the modules object (__webpack_modules__) 48 | /******/ __webpack_require__.m = modules; 49 | /******/ 50 | /******/ // expose the module cache 51 | /******/ __webpack_require__.c = installedModules; 52 | /******/ 53 | /******/ // define getter function for harmony exports 54 | /******/ __webpack_require__.d = function(exports, name, getter) { 55 | /******/ if(!__webpack_require__.o(exports, name)) { 56 | /******/ Object.defineProperty(exports, name, { 57 | /******/ configurable: false, 58 | /******/ enumerable: true, 59 | /******/ get: getter 60 | /******/ }); 61 | /******/ } 62 | /******/ }; 63 | /******/ 64 | /******/ // getDefaultExport function for compatibility with non-harmony modules 65 | /******/ __webpack_require__.n = function(module) { 66 | /******/ var getter = module && module.__esModule ? 67 | /******/ function getDefault() { return module['default']; } : 68 | /******/ function getModuleExports() { return module; }; 69 | /******/ __webpack_require__.d(getter, 'a', getter); 70 | /******/ return getter; 71 | /******/ }; 72 | /******/ 73 | /******/ // Object.prototype.hasOwnProperty.call 74 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 75 | /******/ 76 | /******/ // __webpack_public_path__ 77 | /******/ __webpack_require__.p = ""; 78 | /******/ 79 | /******/ // Load entry module and return exports 80 | /******/ return __webpack_require__(__webpack_require__.s = 0); 81 | /******/ }) 82 | /************************************************************************/ 83 | /******/ ([ 84 | /* 0 */ 85 | /***/ (function(module, exports, __webpack_require__) { 86 | 87 | "use strict"; 88 | 89 | 90 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 91 | 92 | var _rules = __webpack_require__(1); 93 | 94 | var _rules2 = _interopRequireDefault(_rules); 95 | 96 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 97 | 98 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 99 | 100 | var requiredFn = _rules2.default.required.rule; 101 | 102 | /** 103 | * 环境检测 104 | */ 105 | var isWx = typeof wx !== 'undefined' && !!wx.showToast; // 微信小程序 106 | var isMy = typeof my !== 'undefined' && !!my.showToast; // 支付宝小程序 107 | var isSwan = typeof swan !== 'undefined' && !!swan.showToast; // 百度智能小程序 108 | var isTt = typeof tt !== 'undefined' && !!tt.showToast; // 字节跳动小程序 109 | var isBrowser = typeof window !== 'undefined' && !!window.alert; // 普通浏览器 110 | 111 | var objString = Object.prototype.toString; 112 | 113 | var isArray = Array.isArray || function (v) { 114 | return objString.call(v) === '[object Array]'; 115 | }; 116 | var isFunction = function isFunction(v) { 117 | return objString.call(v) === '[object Function]'; 118 | }; 119 | var isRegExp = function isRegExp(v) { 120 | return objString.call(v) === '[object RegExp]'; 121 | }; 122 | 123 | var WeValidator = function () { 124 | 125 | /** 126 | * 默认参数 127 | * @param {object} options 128 | * @param {object} [options.rules] 验证字段的规则 129 | * @param {object} [options.messages] 验证字段错误的提示信息 130 | * @param {function} [options.onMessage] 错误信息显示方式 131 | * @param {boolean} [options.multiCheck] 是否同时校验多个字段 132 | */ 133 | function WeValidator() { 134 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 135 | 136 | _classCallCheck(this, WeValidator); 137 | 138 | this.options = options; 139 | 140 | this.required = requiredFn; 141 | this._checkAllRules(); 142 | } 143 | 144 | /** 145 | * 所有校验规则 146 | */ 147 | 148 | 149 | /** 150 | * 动态添加验证规则 151 | * @param {string} ruleName 规则名称 152 | * @param {object} ruleOption 规则配置 153 | * @param {string} [ruleOption.message] 默认错误信息文字 154 | * @param {regexp|function} [ruleOption.rule] 验证规则 155 | */ 156 | 157 | 158 | /** 159 | * 验证单个字段数据 160 | * @param {string} ruleName 规则名称 161 | * @param {string} value 要验证的值 162 | * @param {any} param 传递的验证参数 163 | * @param {boolean} skip 未填跳过校验,仅供内部使用 164 | */ 165 | 166 | 167 | _createClass(WeValidator, [{ 168 | key: '_showErrorMessage', 169 | 170 | 171 | /** 172 | * 显示错误信息 173 | * @param {object} params 错误信息 174 | * @param {function} onMessage 自定义提示函数 175 | */ 176 | value: function _showErrorMessage(params, onMessage) { 177 | // validatorInstance.checkData(data, onMessage) 178 | if (isFunction(onMessage)) { 179 | return onMessage(params); 180 | } 181 | 182 | // 参数形式 new WeValidator({ onMessage }) 183 | if (isFunction(this.options.onMessage)) { 184 | return this.options.onMessage(params); 185 | } 186 | 187 | // 全局配置 WeValidator.onMessage 188 | if (isFunction(WeValidator.onMessage)) { 189 | return WeValidator.onMessage(params); 190 | } 191 | 192 | // 微信小程序 193 | if (isWx) { 194 | return wx.showToast({ 195 | title: params.msg, 196 | icon: 'none' 197 | }); 198 | } 199 | 200 | // 支付宝小程序 201 | if (isMy) { 202 | return my.showToast({ 203 | content: params.msg, 204 | type: 'none' 205 | }); 206 | } 207 | 208 | // 百度小程序 209 | if (isSwan) { 210 | return swan.showToast({ 211 | title: params.msg, 212 | icon: 'none' 213 | }); 214 | } 215 | 216 | // 字节跳动小程序 217 | if (isTt) { 218 | return tt.showToast({ 219 | title: params.msg, 220 | icon: 'none' 221 | }); 222 | } 223 | 224 | // 浏览器端 225 | if (isBrowser) alert(params.msg); 226 | } 227 | 228 | /** 229 | * 获取错误信息内容 230 | * @param {string} ruleName 规则名称 231 | * @param {string} attr 字段名称 232 | * @param {any} param 规则参数 233 | */ 234 | 235 | }, { 236 | key: '_getErrorMessage', 237 | value: function _getErrorMessage(ruleName, attr, param) { 238 | var messages = this.options.messages; 239 | var defaultMessage = WeValidator.RULES[ruleName].message; 240 | 241 | if (messages && messages.hasOwnProperty(attr) && messages[attr][ruleName]) { 242 | defaultMessage = messages[attr][ruleName]; 243 | } 244 | 245 | if (defaultMessage) { 246 | defaultMessage = defaultMessage.replace(/\{(\d)\}/g, function ($0, $1) { 247 | if (isArray(param)) { 248 | return param[$1]; 249 | } else { 250 | return param; 251 | } 252 | }); 253 | 254 | return defaultMessage; 255 | } 256 | } 257 | 258 | /** 259 | * 验证配置规则是否无效 260 | * @param {string} ruleName 规则名称 261 | * @param {string} attr 字段名称 262 | */ 263 | 264 | }, { 265 | key: '_isRuleInvalid', 266 | value: function _isRuleInvalid(ruleName, attr) { 267 | if (!WeValidator.RULES.hasOwnProperty(ruleName)) { 268 | console.warn && console.warn('\u6CA1\u6709\u6B64\u9A8C\u8BC1\u89C4\u5219\uFF1A' + ruleName + '\uFF0C\u5B57\u6BB5\uFF1A' + attr); 269 | return true; 270 | } 271 | } 272 | 273 | /** 274 | * 验证所有配置规则是否正确 275 | */ 276 | 277 | }, { 278 | key: '_checkAllRules', 279 | value: function _checkAllRules() { 280 | var _rules_ = this.options.rules; 281 | 282 | // 遍历字段 283 | for (var attr in _rules_) { 284 | // 遍历验证规则 285 | for (var ruleName in _rules_[attr]) { 286 | if (this._isRuleInvalid(ruleName, attr)) continue; 287 | } 288 | } 289 | } 290 | 291 | /** 292 | * 校验数据,会验证所有配置的字段规则 293 | * @param {object} data 验证的数据对象 294 | * @param {function} onMessage 自定义错误信息提示 295 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 296 | * @param {object} fieldMap 校验的字段,默认校验所有字段(内部使用) 297 | */ 298 | 299 | }, { 300 | key: 'checkData', 301 | value: function checkData(data, onMessage) { 302 | var showMessage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 303 | var fieldMap = arguments[3]; 304 | 305 | var _rules_ = this.options.rules; 306 | var multiCheck = this.options.multiCheck; 307 | var hasError = false; 308 | var errorData = {}; 309 | 310 | this.data = data; 311 | 312 | // 遍历字段 313 | for (var attr in _rules_) { 314 | if (fieldMap && !fieldMap.hasOwnProperty(attr)) continue; 315 | 316 | // 遍历验证规则 317 | for (var ruleName in _rules_[attr]) { 318 | if (this._isRuleInvalid(ruleName, attr)) continue; 319 | 320 | if (fieldMap) { 321 | var res = fieldMap[attr]; 322 | if (isArray(res) && res.indexOf(ruleName) === -1) continue; 323 | } 324 | 325 | var ruleParam = _rules_[attr][ruleName]; 326 | var value = ''; 327 | 328 | if (data.hasOwnProperty(attr)) { 329 | value = data[attr]; 330 | } 331 | 332 | if (isFunction(ruleParam)) { 333 | ruleParam = ruleParam.call(this, value); 334 | } 335 | 336 | var isFieldValid = WeValidator.checkValue.call(this, ruleName, value, ruleParam, true); 337 | 338 | // 验证不通过 339 | if (!isFieldValid) { 340 | hasError = true; 341 | 342 | var msg = this._getErrorMessage(ruleName, attr, ruleParam); 343 | var errorParam = null; 344 | 345 | if (showMessage && msg) { 346 | errorParam = { 347 | name: attr, 348 | value: value, 349 | param: ruleParam, 350 | rule: ruleName, 351 | msg: msg 352 | }; 353 | errorData[attr] = errorParam; 354 | } 355 | 356 | if (!multiCheck) { 357 | if (errorParam) { 358 | this._showErrorMessage(errorParam, onMessage); 359 | } 360 | return false; 361 | } 362 | } 363 | } 364 | } 365 | 366 | if (hasError) { 367 | if (multiCheck && showMessage) { 368 | this._showErrorMessage(errorData, onMessage); 369 | } 370 | return false; 371 | } 372 | 373 | return true; 374 | } 375 | 376 | /** 377 | * 校验数据,只校验对应的字段规则 378 | * @param {object} data 验证的数据对象 379 | * @param {array} fields 校验的字段 380 | * @param {function} onMessage 自定义错误信息提示 381 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 382 | */ 383 | 384 | }, { 385 | key: 'checkFields', 386 | value: function checkFields(data, fields, onMessage) { 387 | var showMessage = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; 388 | 389 | if (!isArray(fields)) throw new Error('第二个参数须为数组'); 390 | 391 | // fields: [ '[field]:[rule]' ] 392 | // fields: [ 'phoneNo' ] => { phoneNo: true } 393 | // fields: [ 'phoneNo:required' ] => { phoneNo: ['required'] } 394 | // fields: [ 'phoneNo:required,mobile' ] => { phoneNo: ['required', 'mobile'] } 395 | var fieldMap = {}; 396 | 397 | fields.forEach(function (item) { 398 | var arr = item.split(':'); 399 | var field = arr[0]; 400 | var rules = arr[1]; 401 | 402 | if (rules) { 403 | // 只校验特定规则 404 | rules = rules.split(','); 405 | fieldMap[field] = rules; 406 | } else { 407 | // 校验 field 字段的所有规则 408 | fieldMap[field] = true; 409 | } 410 | }); 411 | 412 | return this.checkData(data, onMessage, showMessage, fieldMap); 413 | } 414 | 415 | /** 416 | * 校验数据,不会提示错误信息 417 | * @param {object} data 验证的数据对象 418 | * @param {array} fields 校验的字段。如果有,只校验对应的字段规则,默认校验所有配置的字段规则 419 | */ 420 | 421 | }, { 422 | key: 'isValid', 423 | value: function isValid(data, fields) { 424 | if (isArray(fields)) { 425 | return this.checkFields(data, fields, null, false); 426 | } else { 427 | return this.checkData(data, null, false); 428 | } 429 | } 430 | 431 | /** 432 | * 动态添加字段校验 433 | * @param {object} options 配置参数 434 | * @param {object} [options.rules] 规则 435 | * @param {object} [options.messages] 提示消息 436 | */ 437 | 438 | }, { 439 | key: 'addRules', 440 | value: function addRules() { 441 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 442 | 443 | Object.assign(this.options.rules, options.rules || {}); 444 | Object.assign(this.options.messages, options.messages || {}); 445 | 446 | this._checkAllRules(); 447 | } 448 | 449 | /** 450 | * 动态移除字段校验 451 | * @param {array} fields 要删除校验的字段 452 | */ 453 | 454 | }, { 455 | key: 'removeRules', 456 | value: function removeRules(fields) { 457 | if (!isArray(fields)) throw new Error('参数须为数组'); 458 | 459 | for (var i = 0; i < fields.length; i++) { 460 | var key = fields[i]; 461 | 462 | delete this.options.rules[key]; 463 | } 464 | } 465 | }]); 466 | 467 | return WeValidator; 468 | }(); 469 | 470 | WeValidator.RULES = {}; 471 | 472 | WeValidator.addRule = function (ruleName, ruleOption) { 473 | WeValidator.RULES[ruleName] = ruleOption; 474 | }; 475 | 476 | WeValidator.checkValue = function (ruleName, value, param, skip) { 477 | var rule = WeValidator.RULES[ruleName].rule; 478 | 479 | if (isRegExp(rule)) { 480 | if (skip) { 481 | return !requiredFn(value) || rule.test(value); 482 | } else { 483 | return rule.test(value); 484 | } 485 | } 486 | 487 | if (isFunction(rule)) { 488 | if (ruleName === 'required') { 489 | return param && requiredFn(value); 490 | } else { 491 | if (skip) { 492 | return !requiredFn(value) || rule.call(this, value, param); 493 | } else { 494 | return rule.call(this, value, param); 495 | } 496 | } 497 | } 498 | }; 499 | 500 | WeValidator.RULES = _rules2.default; 501 | WeValidator.required = requiredFn; 502 | 503 | module.exports = WeValidator; 504 | 505 | /***/ }), 506 | /* 1 */ 507 | /***/ (function(module, exports, __webpack_require__) { 508 | 509 | "use strict"; 510 | 511 | 512 | module.exports = { 513 | /** 514 | * 必填 515 | */ 516 | required: { 517 | message: '此字段必填', 518 | rule: function rule(value) { 519 | if (typeof value === 'number') { 520 | value = value.toString(); 521 | } else if (typeof value === 'boolean') { 522 | return true; 523 | } 524 | return !!(value && value.length > 0); 525 | } 526 | }, 527 | /** 528 | * 正则通用 529 | */ 530 | pattern: { 531 | message: '不符合此验证规则', 532 | rule: function rule(value, param) { 533 | return param.test(value); 534 | } 535 | }, 536 | /** 537 | * 电子邮件 538 | */ 539 | email: { 540 | message: '请输入有效的电子邮件地址', 541 | rule: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ 542 | }, 543 | /** 544 | * 手机号码 545 | */ 546 | mobile: { 547 | message: '请输入 11 位的手机号码', 548 | rule: /^1[3456789]\d{9}$/ 549 | }, 550 | /** 551 | * 座机号,例如:010-1234567、0551-1234567 552 | */ 553 | tel: { 554 | message: '请输入座机号', 555 | rule: /^(\d{3,4}-)?\d{7,8}$/ 556 | }, 557 | /** 558 | * URL网址 559 | */ 560 | url: { 561 | message: '请输入有效的网址', 562 | rule: /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i 563 | }, 564 | /** 565 | * 身份证号 566 | */ 567 | idcard: { 568 | message: '请输入 18 位的有效身份证', 569 | rule: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/ 570 | }, 571 | /** 572 | * 字段值相同校验(例如:密码和确认密码) 573 | */ 574 | equalTo: { 575 | message: '输入值必须和字段 {0} 相同', 576 | rule: function rule(value, param) { 577 | return value === this.data[param]; 578 | } 579 | }, 580 | /** 581 | * 字段值不相同校验,与 equalTo 相反 582 | */ 583 | notEqualTo: { 584 | message: '输入值不能和字段 {0} 相同', 585 | rule: function rule(value, param) { 586 | return value !== this.data[param]; 587 | } 588 | }, 589 | /** 590 | * 是否包含某字符 591 | */ 592 | contains: { 593 | message: '输入值必须包含 {0}', 594 | rule: function rule(value, param) { 595 | return value.indexOf(param) > -1; 596 | } 597 | }, 598 | /** 599 | * 不能包含某字符 600 | */ 601 | notContains: { 602 | message: '输入值不能包含 {0}', 603 | rule: function rule(value, param) { 604 | return value.indexOf(param) === -1; 605 | } 606 | }, 607 | /** 608 | * 长度为多少的字符串 609 | */ 610 | length: { 611 | message: '请输入 {0} 个字符', 612 | rule: function rule(value, param) { 613 | return value.length == param; 614 | } 615 | }, 616 | /** 617 | * 最少多长的字符串 618 | */ 619 | minlength: { 620 | message: '最少要输入 {0} 个字符', 621 | rule: function rule(value, param) { 622 | return value.length >= param; 623 | } 624 | }, 625 | /** 626 | * 最多多长的字符串 627 | */ 628 | maxlength: { 629 | message: '最多可以输入 {0} 个字符', 630 | rule: function rule(value, param) { 631 | return value.length <= param; 632 | } 633 | }, 634 | /** 635 | * 某个范围长度的字符串 636 | */ 637 | rangelength: { 638 | message: '请输入长度在 {0} 到 {1} 之间的字符', 639 | rule: function rule(value, param) { 640 | return value.length >= param[0] && value.length <= param[1]; 641 | } 642 | }, 643 | /** 644 | * 数字 645 | */ 646 | number: { 647 | message: '请输入有效的数字', 648 | rule: /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/ 649 | }, 650 | /** 651 | * 正整数数字 652 | */ 653 | digits: { 654 | message: '只能输入正整数数字', 655 | rule: /^\d+$/ 656 | }, 657 | /** 658 | * 正整数或负整数数字 659 | */ 660 | integer: { 661 | message: '只能输入整数数字', 662 | rule: /^-?\d+$/ 663 | }, 664 | /** 665 | * 大于多少的数字/字段值 666 | */ 667 | min: { 668 | message: '请输入大于 {0} 的数字', 669 | rule: function rule(value, param) { 670 | if (typeof param === 'string') param = this.data[param]; 671 | 672 | return value >= param; 673 | } 674 | }, 675 | /** 676 | * 小于多少的数字/字段值 677 | */ 678 | max: { 679 | message: '请输入小于 {0} 的数字', 680 | rule: function rule(value, param) { 681 | if (typeof param === 'string') param = this.data[param]; 682 | 683 | return value <= param; 684 | } 685 | }, 686 | /** 687 | * 大于且小于多少的数字 688 | */ 689 | range: { 690 | message: '请输入大于 {0} 且小于 {1} 的数字', 691 | rule: function rule(value, param) { 692 | return value >= param[0] && value <= param[1]; 693 | } 694 | }, 695 | /** 696 | * 中文字符 697 | */ 698 | chinese: { 699 | message: '只能输入中文字符', 700 | rule: /^[\u4e00-\u9fa5]+$/ 701 | }, 702 | /** 703 | * 最少多少个中文字符 704 | */ 705 | minChinese: { 706 | message: '最少输入 {0} 个中文字符', 707 | rule: function rule(value, param) { 708 | return new RegExp('^[\u4E00-\u9FA5]{' + param + ',}$').test(value); 709 | } 710 | }, 711 | /** 712 | * 最多多少个中文字符 713 | */ 714 | maxChinese: { 715 | message: '最多输入 {0} 个中文字符', 716 | rule: function rule(value, param) { 717 | return new RegExp('^[\u4E00-\u9FA5]{1,' + param + '}$').test(value); 718 | } 719 | }, 720 | /** 721 | * 大于且小于多少个中文字符 722 | */ 723 | rangeChinese: { 724 | message: '只能输入 {0} 到 {1} 个中文字符', 725 | rule: function rule(value, param) { 726 | return new RegExp('^[\u4E00-\u9FA5]{' + param[0] + ',' + param[1] + '}$').test(value); 727 | } 728 | }, 729 | /** 730 | * 日期 731 | */ 732 | date: { 733 | message: '请输入有效的日期', 734 | rule: function rule(value) { 735 | return !/Invalid|NaN/.test(new Date(value).toString()); 736 | } 737 | }, 738 | /** 739 | * 日期(ISO标准格式)例如:2019-09-19,2019/09/19 740 | */ 741 | dateISO: { 742 | message: '请输入有效的日期(ISO 标准格式)', 743 | rule: /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/ 744 | }, 745 | /** 746 | * ipv4地址 747 | */ 748 | ipv4: { 749 | message: '请输入有效的 IPv4 地址', 750 | rule: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i 751 | }, 752 | /** 753 | * ipv6地址 754 | */ 755 | ipv6: { 756 | message: '请输入有效的 IPv6 地址', 757 | rule: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i 758 | } 759 | }; 760 | 761 | /***/ }) 762 | /******/ ]); 763 | }); -------------------------------------------------------------------------------- /example/wechat/js/we-validator.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * we-validator 3 | * version: 2.1.17 4 | * address: https://github.com/ChanceYu/we-validator#readme 5 | * author: ChanceYu 6 | * license: MIT 7 | */ 8 | (function webpackUniversalModuleDefinition(root, factory) { 9 | if(typeof exports === 'object' && typeof module === 'object') 10 | module.exports = factory(); 11 | else if(typeof define === 'function' && define.amd) 12 | define("WeValidator", [], factory); 13 | else if(typeof exports === 'object') 14 | exports["WeValidator"] = factory(); 15 | else 16 | root["WeValidator"] = factory(); 17 | })(typeof self !== 'undefined' ? self : this, function() { 18 | return /******/ (function(modules) { // webpackBootstrap 19 | /******/ // The module cache 20 | /******/ var installedModules = {}; 21 | /******/ 22 | /******/ // The require function 23 | /******/ function __webpack_require__(moduleId) { 24 | /******/ 25 | /******/ // Check if module is in cache 26 | /******/ if(installedModules[moduleId]) { 27 | /******/ return installedModules[moduleId].exports; 28 | /******/ } 29 | /******/ // Create a new module (and put it into the cache) 30 | /******/ var module = installedModules[moduleId] = { 31 | /******/ i: moduleId, 32 | /******/ l: false, 33 | /******/ exports: {} 34 | /******/ }; 35 | /******/ 36 | /******/ // Execute the module function 37 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 38 | /******/ 39 | /******/ // Flag the module as loaded 40 | /******/ module.l = true; 41 | /******/ 42 | /******/ // Return the exports of the module 43 | /******/ return module.exports; 44 | /******/ } 45 | /******/ 46 | /******/ 47 | /******/ // expose the modules object (__webpack_modules__) 48 | /******/ __webpack_require__.m = modules; 49 | /******/ 50 | /******/ // expose the module cache 51 | /******/ __webpack_require__.c = installedModules; 52 | /******/ 53 | /******/ // define getter function for harmony exports 54 | /******/ __webpack_require__.d = function(exports, name, getter) { 55 | /******/ if(!__webpack_require__.o(exports, name)) { 56 | /******/ Object.defineProperty(exports, name, { 57 | /******/ configurable: false, 58 | /******/ enumerable: true, 59 | /******/ get: getter 60 | /******/ }); 61 | /******/ } 62 | /******/ }; 63 | /******/ 64 | /******/ // getDefaultExport function for compatibility with non-harmony modules 65 | /******/ __webpack_require__.n = function(module) { 66 | /******/ var getter = module && module.__esModule ? 67 | /******/ function getDefault() { return module['default']; } : 68 | /******/ function getModuleExports() { return module; }; 69 | /******/ __webpack_require__.d(getter, 'a', getter); 70 | /******/ return getter; 71 | /******/ }; 72 | /******/ 73 | /******/ // Object.prototype.hasOwnProperty.call 74 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 75 | /******/ 76 | /******/ // __webpack_public_path__ 77 | /******/ __webpack_require__.p = ""; 78 | /******/ 79 | /******/ // Load entry module and return exports 80 | /******/ return __webpack_require__(__webpack_require__.s = 0); 81 | /******/ }) 82 | /************************************************************************/ 83 | /******/ ([ 84 | /* 0 */ 85 | /***/ (function(module, exports, __webpack_require__) { 86 | 87 | "use strict"; 88 | 89 | 90 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 91 | 92 | var _rules = __webpack_require__(1); 93 | 94 | var _rules2 = _interopRequireDefault(_rules); 95 | 96 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 97 | 98 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 99 | 100 | var requiredFn = _rules2.default.required.rule; 101 | 102 | /** 103 | * 环境检测 104 | */ 105 | var isWx = typeof wx !== 'undefined' && !!wx.showToast; // 微信小程序 106 | var isMy = typeof my !== 'undefined' && !!my.showToast; // 支付宝小程序 107 | var isSwan = typeof swan !== 'undefined' && !!swan.showToast; // 百度智能小程序 108 | var isTt = typeof tt !== 'undefined' && !!tt.showToast; // 字节跳动小程序 109 | var isBrowser = typeof window !== 'undefined' && !!window.alert; // 普通浏览器 110 | 111 | var objString = Object.prototype.toString; 112 | 113 | var isArray = Array.isArray || function (v) { 114 | return objString.call(v) === '[object Array]'; 115 | }; 116 | var isFunction = function isFunction(v) { 117 | return objString.call(v) === '[object Function]'; 118 | }; 119 | var isRegExp = function isRegExp(v) { 120 | return objString.call(v) === '[object RegExp]'; 121 | }; 122 | 123 | var WeValidator = function () { 124 | 125 | /** 126 | * 默认参数 127 | * @param {object} options 128 | * @param {object} [options.rules] 验证字段的规则 129 | * @param {object} [options.messages] 验证字段错误的提示信息 130 | * @param {function} [options.onMessage] 错误信息显示方式 131 | * @param {boolean} [options.multiCheck] 是否同时校验多个字段 132 | */ 133 | function WeValidator() { 134 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 135 | 136 | _classCallCheck(this, WeValidator); 137 | 138 | this.options = options; 139 | 140 | this.required = requiredFn; 141 | this._checkAllRules(); 142 | } 143 | 144 | /** 145 | * 所有校验规则 146 | */ 147 | 148 | 149 | /** 150 | * 动态添加验证规则 151 | * @param {string} ruleName 规则名称 152 | * @param {object} ruleOption 规则配置 153 | * @param {string} [ruleOption.message] 默认错误信息文字 154 | * @param {regexp|function} [ruleOption.rule] 验证规则 155 | */ 156 | 157 | 158 | /** 159 | * 验证单个字段数据 160 | * @param {string} ruleName 规则名称 161 | * @param {string} value 要验证的值 162 | * @param {any} param 传递的验证参数 163 | * @param {boolean} skip 未填跳过校验,仅供内部使用 164 | */ 165 | 166 | 167 | _createClass(WeValidator, [{ 168 | key: '_showErrorMessage', 169 | 170 | 171 | /** 172 | * 显示错误信息 173 | * @param {object} params 错误信息 174 | * @param {function} onMessage 自定义提示函数 175 | */ 176 | value: function _showErrorMessage(params, onMessage) { 177 | // validatorInstance.checkData(data, onMessage) 178 | if (isFunction(onMessage)) { 179 | return onMessage(params); 180 | } 181 | 182 | // 参数形式 new WeValidator({ onMessage }) 183 | if (isFunction(this.options.onMessage)) { 184 | return this.options.onMessage(params); 185 | } 186 | 187 | // 全局配置 WeValidator.onMessage 188 | if (isFunction(WeValidator.onMessage)) { 189 | return WeValidator.onMessage(params); 190 | } 191 | 192 | // 微信小程序 193 | if (isWx) { 194 | return wx.showToast({ 195 | title: params.msg, 196 | icon: 'none' 197 | }); 198 | } 199 | 200 | // 支付宝小程序 201 | if (isMy) { 202 | return my.showToast({ 203 | content: params.msg, 204 | type: 'none' 205 | }); 206 | } 207 | 208 | // 百度小程序 209 | if (isSwan) { 210 | return swan.showToast({ 211 | title: params.msg, 212 | icon: 'none' 213 | }); 214 | } 215 | 216 | // 字节跳动小程序 217 | if (isTt) { 218 | return tt.showToast({ 219 | title: params.msg, 220 | icon: 'none' 221 | }); 222 | } 223 | 224 | // 浏览器端 225 | if (isBrowser) alert(params.msg); 226 | } 227 | 228 | /** 229 | * 获取错误信息内容 230 | * @param {string} ruleName 规则名称 231 | * @param {string} attr 字段名称 232 | * @param {any} param 规则参数 233 | */ 234 | 235 | }, { 236 | key: '_getErrorMessage', 237 | value: function _getErrorMessage(ruleName, attr, param) { 238 | var messages = this.options.messages; 239 | var defaultMessage = WeValidator.RULES[ruleName].message; 240 | 241 | if (messages && messages.hasOwnProperty(attr) && messages[attr][ruleName]) { 242 | defaultMessage = messages[attr][ruleName]; 243 | } 244 | 245 | if (defaultMessage) { 246 | defaultMessage = defaultMessage.replace(/\{(\d)\}/g, function ($0, $1) { 247 | if (isArray(param)) { 248 | return param[$1]; 249 | } else { 250 | return param; 251 | } 252 | }); 253 | 254 | return defaultMessage; 255 | } 256 | } 257 | 258 | /** 259 | * 验证配置规则是否无效 260 | * @param {string} ruleName 规则名称 261 | * @param {string} attr 字段名称 262 | */ 263 | 264 | }, { 265 | key: '_isRuleInvalid', 266 | value: function _isRuleInvalid(ruleName, attr) { 267 | if (!WeValidator.RULES.hasOwnProperty(ruleName)) { 268 | console.warn && console.warn('\u6CA1\u6709\u6B64\u9A8C\u8BC1\u89C4\u5219\uFF1A' + ruleName + '\uFF0C\u5B57\u6BB5\uFF1A' + attr); 269 | return true; 270 | } 271 | } 272 | 273 | /** 274 | * 验证所有配置规则是否正确 275 | */ 276 | 277 | }, { 278 | key: '_checkAllRules', 279 | value: function _checkAllRules() { 280 | var _rules_ = this.options.rules; 281 | 282 | // 遍历字段 283 | for (var attr in _rules_) { 284 | // 遍历验证规则 285 | for (var ruleName in _rules_[attr]) { 286 | if (this._isRuleInvalid(ruleName, attr)) continue; 287 | } 288 | } 289 | } 290 | 291 | /** 292 | * 校验数据,会验证所有配置的字段规则 293 | * @param {object} data 验证的数据对象 294 | * @param {function} onMessage 自定义错误信息提示 295 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 296 | * @param {object} fieldMap 校验的字段,默认校验所有字段(内部使用) 297 | */ 298 | 299 | }, { 300 | key: 'checkData', 301 | value: function checkData(data, onMessage) { 302 | var showMessage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 303 | var fieldMap = arguments[3]; 304 | 305 | var _rules_ = this.options.rules; 306 | var multiCheck = this.options.multiCheck; 307 | var hasError = false; 308 | var errorData = {}; 309 | 310 | this.data = data; 311 | 312 | // 遍历字段 313 | for (var attr in _rules_) { 314 | if (fieldMap && !fieldMap.hasOwnProperty(attr)) continue; 315 | 316 | // 遍历验证规则 317 | for (var ruleName in _rules_[attr]) { 318 | if (this._isRuleInvalid(ruleName, attr)) continue; 319 | 320 | if (fieldMap) { 321 | var res = fieldMap[attr]; 322 | if (isArray(res) && res.indexOf(ruleName) === -1) continue; 323 | } 324 | 325 | var ruleParam = _rules_[attr][ruleName]; 326 | var value = ''; 327 | 328 | if (data.hasOwnProperty(attr)) { 329 | value = data[attr]; 330 | } 331 | 332 | if (isFunction(ruleParam)) { 333 | ruleParam = ruleParam.call(this, value); 334 | } 335 | 336 | var isFieldValid = WeValidator.checkValue.call(this, ruleName, value, ruleParam, true); 337 | 338 | // 验证不通过 339 | if (!isFieldValid) { 340 | hasError = true; 341 | 342 | var msg = this._getErrorMessage(ruleName, attr, ruleParam); 343 | var errorParam = null; 344 | 345 | if (showMessage && msg) { 346 | errorParam = { 347 | name: attr, 348 | value: value, 349 | param: ruleParam, 350 | rule: ruleName, 351 | msg: msg 352 | }; 353 | errorData[attr] = errorParam; 354 | } 355 | 356 | if (!multiCheck) { 357 | if (errorParam) { 358 | this._showErrorMessage(errorParam, onMessage); 359 | } 360 | return false; 361 | } 362 | } 363 | } 364 | } 365 | 366 | if (hasError) { 367 | if (multiCheck && showMessage) { 368 | this._showErrorMessage(errorData, onMessage); 369 | } 370 | return false; 371 | } 372 | 373 | return true; 374 | } 375 | 376 | /** 377 | * 校验数据,只校验对应的字段规则 378 | * @param {object} data 验证的数据对象 379 | * @param {array} fields 校验的字段 380 | * @param {function} onMessage 自定义错误信息提示 381 | * @param {boolean} showMessage 是否显示提示信息,默认显示(内部使用) 382 | */ 383 | 384 | }, { 385 | key: 'checkFields', 386 | value: function checkFields(data, fields, onMessage) { 387 | var showMessage = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; 388 | 389 | if (!isArray(fields)) throw new Error('第二个参数须为数组'); 390 | 391 | // fields: [ '[field]:[rule]' ] 392 | // fields: [ 'phoneNo' ] => { phoneNo: true } 393 | // fields: [ 'phoneNo:required' ] => { phoneNo: ['required'] } 394 | // fields: [ 'phoneNo:required,mobile' ] => { phoneNo: ['required', 'mobile'] } 395 | var fieldMap = {}; 396 | 397 | fields.forEach(function (item) { 398 | var arr = item.split(':'); 399 | var field = arr[0]; 400 | var rules = arr[1]; 401 | 402 | if (rules) { 403 | // 只校验特定规则 404 | rules = rules.split(','); 405 | fieldMap[field] = rules; 406 | } else { 407 | // 校验 field 字段的所有规则 408 | fieldMap[field] = true; 409 | } 410 | }); 411 | 412 | return this.checkData(data, onMessage, showMessage, fieldMap); 413 | } 414 | 415 | /** 416 | * 校验数据,不会提示错误信息 417 | * @param {object} data 验证的数据对象 418 | * @param {array} fields 校验的字段。如果有,只校验对应的字段规则,默认校验所有配置的字段规则 419 | */ 420 | 421 | }, { 422 | key: 'isValid', 423 | value: function isValid(data, fields) { 424 | if (isArray(fields)) { 425 | return this.checkFields(data, fields, null, false); 426 | } else { 427 | return this.checkData(data, null, false); 428 | } 429 | } 430 | 431 | /** 432 | * 动态添加字段校验 433 | * @param {object} options 配置参数 434 | * @param {object} [options.rules] 规则 435 | * @param {object} [options.messages] 提示消息 436 | */ 437 | 438 | }, { 439 | key: 'addRules', 440 | value: function addRules() { 441 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 442 | 443 | Object.assign(this.options.rules, options.rules || {}); 444 | Object.assign(this.options.messages, options.messages || {}); 445 | 446 | this._checkAllRules(); 447 | } 448 | 449 | /** 450 | * 动态移除字段校验 451 | * @param {array} fields 要删除校验的字段 452 | */ 453 | 454 | }, { 455 | key: 'removeRules', 456 | value: function removeRules(fields) { 457 | if (!isArray(fields)) throw new Error('参数须为数组'); 458 | 459 | for (var i = 0; i < fields.length; i++) { 460 | var key = fields[i]; 461 | 462 | delete this.options.rules[key]; 463 | } 464 | } 465 | }]); 466 | 467 | return WeValidator; 468 | }(); 469 | 470 | WeValidator.RULES = {}; 471 | 472 | WeValidator.addRule = function (ruleName, ruleOption) { 473 | WeValidator.RULES[ruleName] = ruleOption; 474 | }; 475 | 476 | WeValidator.checkValue = function (ruleName, value, param, skip) { 477 | var rule = WeValidator.RULES[ruleName].rule; 478 | 479 | if (isRegExp(rule)) { 480 | if (skip) { 481 | return !requiredFn(value) || rule.test(value); 482 | } else { 483 | return rule.test(value); 484 | } 485 | } 486 | 487 | if (isFunction(rule)) { 488 | if (ruleName === 'required') { 489 | return param && requiredFn(value); 490 | } else { 491 | if (skip) { 492 | return !requiredFn(value) || rule.call(this, value, param); 493 | } else { 494 | return rule.call(this, value, param); 495 | } 496 | } 497 | } 498 | }; 499 | 500 | WeValidator.RULES = _rules2.default; 501 | WeValidator.required = requiredFn; 502 | 503 | module.exports = WeValidator; 504 | 505 | /***/ }), 506 | /* 1 */ 507 | /***/ (function(module, exports, __webpack_require__) { 508 | 509 | "use strict"; 510 | 511 | 512 | module.exports = { 513 | /** 514 | * 必填 515 | */ 516 | required: { 517 | message: '此字段必填', 518 | rule: function rule(value) { 519 | if (typeof value === 'number') { 520 | value = value.toString(); 521 | } else if (typeof value === 'boolean') { 522 | return true; 523 | } 524 | return !!(value && value.length > 0); 525 | } 526 | }, 527 | /** 528 | * 正则通用 529 | */ 530 | pattern: { 531 | message: '不符合此验证规则', 532 | rule: function rule(value, param) { 533 | return param.test(value); 534 | } 535 | }, 536 | /** 537 | * 电子邮件 538 | */ 539 | email: { 540 | message: '请输入有效的电子邮件地址', 541 | rule: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ 542 | }, 543 | /** 544 | * 手机号码 545 | */ 546 | mobile: { 547 | message: '请输入 11 位的手机号码', 548 | rule: /^1[3456789]\d{9}$/ 549 | }, 550 | /** 551 | * 座机号,例如:010-1234567、0551-1234567 552 | */ 553 | tel: { 554 | message: '请输入座机号', 555 | rule: /^(\d{3,4}-)?\d{7,8}$/ 556 | }, 557 | /** 558 | * URL网址 559 | */ 560 | url: { 561 | message: '请输入有效的网址', 562 | rule: /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i 563 | }, 564 | /** 565 | * 身份证号 566 | */ 567 | idcard: { 568 | message: '请输入 18 位的有效身份证', 569 | rule: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/ 570 | }, 571 | /** 572 | * 字段值相同校验(例如:密码和确认密码) 573 | */ 574 | equalTo: { 575 | message: '输入值必须和字段 {0} 相同', 576 | rule: function rule(value, param) { 577 | return value === this.data[param]; 578 | } 579 | }, 580 | /** 581 | * 字段值不相同校验,与 equalTo 相反 582 | */ 583 | notEqualTo: { 584 | message: '输入值不能和字段 {0} 相同', 585 | rule: function rule(value, param) { 586 | return value !== this.data[param]; 587 | } 588 | }, 589 | /** 590 | * 是否包含某字符 591 | */ 592 | contains: { 593 | message: '输入值必须包含 {0}', 594 | rule: function rule(value, param) { 595 | return value.indexOf(param) > -1; 596 | } 597 | }, 598 | /** 599 | * 不能包含某字符 600 | */ 601 | notContains: { 602 | message: '输入值不能包含 {0}', 603 | rule: function rule(value, param) { 604 | return value.indexOf(param) === -1; 605 | } 606 | }, 607 | /** 608 | * 长度为多少的字符串 609 | */ 610 | length: { 611 | message: '请输入 {0} 个字符', 612 | rule: function rule(value, param) { 613 | return value.length == param; 614 | } 615 | }, 616 | /** 617 | * 最少多长的字符串 618 | */ 619 | minlength: { 620 | message: '最少要输入 {0} 个字符', 621 | rule: function rule(value, param) { 622 | return value.length >= param; 623 | } 624 | }, 625 | /** 626 | * 最多多长的字符串 627 | */ 628 | maxlength: { 629 | message: '最多可以输入 {0} 个字符', 630 | rule: function rule(value, param) { 631 | return value.length <= param; 632 | } 633 | }, 634 | /** 635 | * 某个范围长度的字符串 636 | */ 637 | rangelength: { 638 | message: '请输入长度在 {0} 到 {1} 之间的字符', 639 | rule: function rule(value, param) { 640 | return value.length >= param[0] && value.length <= param[1]; 641 | } 642 | }, 643 | /** 644 | * 数字 645 | */ 646 | number: { 647 | message: '请输入有效的数字', 648 | rule: /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/ 649 | }, 650 | /** 651 | * 正整数数字 652 | */ 653 | digits: { 654 | message: '只能输入正整数数字', 655 | rule: /^\d+$/ 656 | }, 657 | /** 658 | * 正整数或负整数数字 659 | */ 660 | integer: { 661 | message: '只能输入整数数字', 662 | rule: /^-?\d+$/ 663 | }, 664 | /** 665 | * 大于多少的数字/字段值 666 | */ 667 | min: { 668 | message: '请输入大于 {0} 的数字', 669 | rule: function rule(value, param) { 670 | if (typeof param === 'string') param = this.data[param]; 671 | 672 | return value >= param; 673 | } 674 | }, 675 | /** 676 | * 小于多少的数字/字段值 677 | */ 678 | max: { 679 | message: '请输入小于 {0} 的数字', 680 | rule: function rule(value, param) { 681 | if (typeof param === 'string') param = this.data[param]; 682 | 683 | return value <= param; 684 | } 685 | }, 686 | /** 687 | * 大于且小于多少的数字 688 | */ 689 | range: { 690 | message: '请输入大于 {0} 且小于 {1} 的数字', 691 | rule: function rule(value, param) { 692 | return value >= param[0] && value <= param[1]; 693 | } 694 | }, 695 | /** 696 | * 中文字符 697 | */ 698 | chinese: { 699 | message: '只能输入中文字符', 700 | rule: /^[\u4e00-\u9fa5]+$/ 701 | }, 702 | /** 703 | * 最少多少个中文字符 704 | */ 705 | minChinese: { 706 | message: '最少输入 {0} 个中文字符', 707 | rule: function rule(value, param) { 708 | return new RegExp('^[\u4E00-\u9FA5]{' + param + ',}$').test(value); 709 | } 710 | }, 711 | /** 712 | * 最多多少个中文字符 713 | */ 714 | maxChinese: { 715 | message: '最多输入 {0} 个中文字符', 716 | rule: function rule(value, param) { 717 | return new RegExp('^[\u4E00-\u9FA5]{1,' + param + '}$').test(value); 718 | } 719 | }, 720 | /** 721 | * 大于且小于多少个中文字符 722 | */ 723 | rangeChinese: { 724 | message: '只能输入 {0} 到 {1} 个中文字符', 725 | rule: function rule(value, param) { 726 | return new RegExp('^[\u4E00-\u9FA5]{' + param[0] + ',' + param[1] + '}$').test(value); 727 | } 728 | }, 729 | /** 730 | * 日期 731 | */ 732 | date: { 733 | message: '请输入有效的日期', 734 | rule: function rule(value) { 735 | return !/Invalid|NaN/.test(new Date(value).toString()); 736 | } 737 | }, 738 | /** 739 | * 日期(ISO标准格式)例如:2019-09-19,2019/09/19 740 | */ 741 | dateISO: { 742 | message: '请输入有效的日期(ISO 标准格式)', 743 | rule: /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/ 744 | }, 745 | /** 746 | * ipv4地址 747 | */ 748 | ipv4: { 749 | message: '请输入有效的 IPv4 地址', 750 | rule: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i 751 | }, 752 | /** 753 | * ipv6地址 754 | */ 755 | ipv6: { 756 | message: '请输入有效的 IPv6 地址', 757 | rule: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i 758 | } 759 | }; 760 | 761 | /***/ }) 762 | /******/ ]); 763 | }); --------------------------------------------------------------------------------