This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0

增加next配置;重构表单验证模块,去除UI

old
宇天 2018-03-25 15:45:11 +08:00
parent 112e3c2316
commit adc8d73365
8 changed files with 516 additions and 321 deletions

View File

@ -15,5 +15,8 @@
npm start
# 生产环境
npm run build
npm run prod
# 不编译,只压缩
npm run next
```

View File

@ -40,7 +40,8 @@ const compileJs = (entry, output) => {
fs.cp(entry, output)
} else {
try {
const { code } = babel.transformFileSync(entry, jsOpt)
let { code } = babel.transformFileSync(entry, jsOpt)
code = code.replace(/\.scss/g, '.css')
fs.echo(code, output)
} catch (err) {
return log(err)

115
build.next.js Normal file
View File

@ -0,0 +1,115 @@
#! /usr/bin/env node
const log = console.log
const fs = require('iofs')
const path = require('path')
const scss = require('node-sass')
const postcss = require('postcss')
const autoprefixer = require('autoprefixer')
const chalk = require('chalk')
const uglify = require('uglify-es')
const sourceDir = path.resolve(__dirname, 'src')
const buildDir = path.resolve(__dirname, 'dist')
const prefixer = postcss().use(
autoprefixer({
browsers: ['ie > 9', 'iOS > 8', 'Android >= 4.4', 'ff > 38', 'Chrome > 38']
})
)
const cssOpt = {
includePaths: ['src/css/'],
outputStyle: 'compressed'
}
const compileJs = (entry, output) => {
if (/touch\.patch/.test(entry)) {
return
}
let t1 = Date.now()
let buf = fs.cat(entry).toString()
let { code } = uglify.minify(buf)
code = code.replace(/\.scss/g, '.css')
log(
'编译JS: %s, 耗时 %s ms',
chalk.green(entry),
chalk.yellow(Date.now() - t1)
)
fs.echo(code, output)
}
const compileCss = (entry, output) => {
let t1 = Date.now()
const { css } = scss.renderSync({ ...cssOpt, file: entry })
prefixer.process(css, { from: '', to: '' }).then(result => {
log(
'编译scss: %s, 耗时 %s ms',
chalk.green(entry),
chalk.yellow(Date.now() - t1)
)
fs.echo(result.css, output)
})
}
const compileHtm = (entry, output) => {
let t1 = Date.now()
let htm = fs.cat(entry).toString('utf8')
htm = htm.replace(/[\r\n\t]+/g, ' ').replace(/\s{2,}/g, ' ')
log(
'压缩HTML: %s, 耗时 %s ms',
chalk.green(entry),
chalk.yellow(Date.now() - t1)
)
fs.echo(htm, output)
}
/*=======================================================*/
/*===== ===*/
/*=======================================================*/
const fontFiles = fs.ls('./src/font/', true)
const jsFiles = fs.ls('./src/js/', true)
const cssFiles = fs.ls('./src/css/', true)
if (fs.isdir(buildDir)) {
fs.rm(buildDir, true)
log(chalk.cyan('清除旧目录 dist/'))
}
// 字体文件直接复制
fontFiles.forEach(file => {
fs.cp('./src/font/' + file, './dist/font/' + file)
})
// css目录
cssFiles.forEach(file => {
if (/\.scss$/.test(file)) {
let entry = path.resolve(sourceDir, 'css/', file)
let output = path.resolve(buildDir, 'css/', file.replace(/scss$/, 'css'))
compileCss(entry, output)
}
})
// js目录的处理要复杂一点
jsFiles.forEach(file => {
let entry = path.resolve(sourceDir, 'js', file)
let output = path.resolve(buildDir, 'js', file)
let ext = file.slice(file.lastIndexOf('.') + 1)
switch (ext) {
case 'js':
compileJs(entry, output)
break
case 'scss':
output = output.replace(/scss$/, 'css')
compileCss(entry, output)
break
case 'htm':
compileHtm(entry, output)
break
default:
if (!fs.isdir(entry)) {
fs.cp(entry, output)
}
}
})

View File

@ -8,7 +8,7 @@ const scss = require('node-sass')
const postcss = require('postcss')
const autoprefixer = require('autoprefixer')
const chalk = require('chalk')
const uglify = require('uglify-js')
const uglify = require('uglify-es')
const sourceDir = path.resolve(__dirname, 'src')
const buildDir = path.resolve(__dirname, 'dist')
@ -41,7 +41,7 @@ const compileJs = (entry, output) => {
tmpOpt = Object.assign({}, jsOpt, { plugins: [] })
}
let { code } = babel.transformFileSync(entry, tmpOpt)
code = uglify.minify(code).code
code = uglify.minify(code).code.replace(/\.scss/g, '.css')
log(
'编译JS: %s, 耗时 %s ms',
chalk.green(entry),
@ -84,7 +84,7 @@ const jsFiles = fs.ls('./src/js/', true)
const cssFiles = fs.ls('./src/css/', true)
if (fs.isdir(buildDir)) {
// fs.rm(buildDir, true)
fs.rm(buildDir, true)
log(chalk.cyan('清除旧目录 dist/'))
}

16
package-lock.json generated
View File

@ -3672,16 +3672,22 @@
"dev": true,
"optional": true
},
"uglify-js": {
"version": "3.3.15",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.15.tgz",
"integrity": "sha512-bqtBCAINYXX/OkdnqMGpbXr+OPWc00hsozRpk+dAtfnbdk2jjKiLmyOkQ7zamg648lVMnzATL8JrSN6LmaVpYA==",
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
"integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
"dev": true,
"requires": {
"commander": "2.15.0",
"commander": "2.13.0",
"source-map": "0.6.1"
},
"dependencies": {
"commander": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",

View File

@ -5,16 +5,14 @@
"main": "index.js",
"scripts": {
"start": "node ./build.dev.js",
"build": "node ./build.prod.js"
"prod": "node ./build.prod.js",
"next": "node ./build.next.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/yutent/doui.git"
},
"keywords": [
"doui",
"Anot"
],
"keywords": ["doui", "Anot"],
"author": "yutent",
"license": "MIT",
"devDependencies": {
@ -29,7 +27,7 @@
"iofs": "^1.0.3",
"node-sass": "^4.8.2",
"postcss": "^6.0.19",
"uglify-js": "^3.3.15"
"uglify-es": "^3.3.9"
},
"dependencies": {}
}

View File

@ -5,22 +5,7 @@
* support IE10+ and other browsers
*
==================================================*/
;(function(global, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = global.document
? factory(global, true)
: function(w) {
if (!w.document) {
throw new Error('Anot.js只能运行在浏览器环境')
}
return factory(w)
}
} else {
factory(global)
}
// Pass this if window is not defined yet
})(typeof window !== 'undefined' ? window : this, function(window, noGlobal) {
const _Anot = (function() {
/*********************************************************************
* 全局变量及方法 *
**********************************************************************/
@ -35,7 +20,7 @@
var head = DOC.head //HEAD元素
head.insertAdjacentHTML(
'afterBegin',
'<anot :skip class="anot-hide"><style id="anot-style">.anot-hide{ display: none!important } .do-rule-tips {position:absolute;z-index:65535;min-width:75px;height:30px;padding:7px 8px;line-height:16px;color:#333;background:#f9ca05;white-space:pre;} .do-rule-tips::before {position:absolute;left:5px;bottom:-8px;width:0;height:0;border:8px solid transparent;border-left:8px solid #f9ca05;content: " "}</style></anot>'
'<anot skip class="anot-hide"><style id="anot-style">.anot-hide{ display: none!important }</style></anot>'
)
var ifGroup = head.firstChild
@ -141,7 +126,7 @@
}
if (tickObserver) {
var node = document.createTextNode('any')
var node = document.createTextNode('anot')
new tickObserver(callback).observe(node, { characterData: true }) // jshint ignore:line
var bool = false
return function(fn) {
@ -181,7 +166,11 @@
return ''
},
check: function(val) {
return Anot.type(val) === this.checkType
this.result = Anot.type(val)
return this.result === this.checkType
},
call: function() {
return this.toString()
}
}
@ -235,13 +224,13 @@
if ($elem === DOC.body) {
scanTag($elem, [])
} else {
var $parent = null
while (($parent = $elem.parentNode)) {
var $parent = $elem
while (($parent = $parent.parentNode)) {
if ($parent.anotctrl) {
scanTag($elem.parentNode, [VMODELS[$parent.anotctrl]])
break
}
}
scanTag($elem.parentNode, $parent ? [VMODELS[$parent.anotctrl]] : [])
}
}
return vm
@ -460,7 +449,7 @@
value: function() {
var thisYear = this.getFullYear(),
that = new Date(thisYear, 0, 1),
firstDay = that.getDay(),
firstDay = that.getDay() || 1,
numsOfToday = (this - that) / 86400000
return Math.ceil((numsOfToday + firstDay) / 7)
},
@ -1373,6 +1362,7 @@
var methods = source.methods
var props = source.props
var watches = source.watch
var mounted = source.mounted
delete source.state
delete source.computed
@ -1488,6 +1478,8 @@
hideProperty($vmodel, '$active', false)
hideProperty($vmodel, '$pathname', old ? old.$pathname : '')
hideProperty($vmodel, '$accessors', accessors)
hideProperty($vmodel, '$refs', {})
hideProperty($vmodel, '$children', [])
hideProperty($vmodel, 'hasOwnProperty', trackBy)
if (options.watch) {
hideProperty($vmodel, '$watch', function() {
@ -1500,6 +1492,12 @@
var v = Anot.vmodels[i]
v.$fire && v.$fire.apply(v, [ee, a])
}
} else if (path.indexOf('child!') === 0) {
var ee = 'props.' + path.slice(6)
for (var i in $vmodel.$children) {
var v = $vmodel.$children[i]
v.$fire && v.$fire.apply(v, [ee, a])
}
} else {
$emit.call($vmodel, path, [a])
}
@ -1527,6 +1525,11 @@
}
$vmodel.$active = true
$vmodel.mounted = mounted
if (old && old.$up) {
old.$up.$children.push($vmodel)
}
return $vmodel
}
@ -2912,7 +2915,7 @@
binding.observers.forEach(function(it) {
if (it.type === 'function') {
// log(it, expr)
let reg = new RegExp(it.p + '\\(([^)]*)\\)', 'g')
var reg = new RegExp(it.p + '\\(([^)]*)\\)', 'g')
expr = expr.replace(reg, function(s, m) {
m = m.trim()
return (
@ -2933,7 +2936,7 @@
"'use strict';\ntry{\nvar " +
assigns.join(',\n') +
expr +
'\n}catch(e){log(e)}'
'\n}catch(e){console.log(e)}'
)
)
/* jshint ignore:end */
@ -3082,17 +3085,19 @@
}
var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/
var ronattr = /^on\-[\w-]+$/
var ronattr = '__fn__'
function getOptionsFromTag(elem, vmodels) {
var attributes = elem.attributes
var ret = {}
for (var i = 0, attr; (attr = attributes[i++]); ) {
var name = attr.name
if (attr.specified && !rnoCollect.test(name)) {
var camelizeName = camelize(attr.name)
if (/^on\-[\w-]+$/.test(name)) {
ret[camelizeName] = getBindingCallback(elem, name, vmodels)
if (name.indexOf(ronattr) === 0) {
name = attr.value.slice(6)
ret[name] = elem[attr.value]
delete elem[attr.value]
} else {
var camelizeName = camelize(name)
ret[camelizeName] = parseData(attr.value)
}
}
@ -3224,6 +3229,12 @@
//确保所有:attr-name扫描完再处理
_delay_component(widget)
}
} else {
// 非组件才检查 ref属性
var ref = isRef(elem)
if (ref) {
vmodels[0].$refs[ref] = elem
}
}
}
@ -3267,34 +3278,19 @@
createSignalTower(elem, newVmodel)
hideProperty(newVmodel, '$elem', elem)
if (vmodels.length) {
attrs.forEach(function(attr, i) {
var props = {}
attrs.forEach(function(attr) {
if (/^:/.test(attr.name)) {
var name = attr.name.match(rmsAttr)[1]
var value = null
if (!name || Anot.directives[name]) {
if (!name || Anot.directives[name] || events[name]) {
return
}
try {
value = parseExpr(attr.value, vmodels, {}).apply(0, vmodels)
value = toJson(value)
elem.removeAttribute(attr.name)
if (!value) {
return
}
if (
newVmodel.props[name] &&
newVmodel.props[name].type === 'PropsTypes'
) {
if (newVmodel.props[name].check(value)) {
newVmodel.props[name] = value
} else {
Anot.error(
'props「' + name + '」类型错误!' + value,
TypeError
)
}
} else {
newVmodel.props[name] = value
}
props[name] = value
} catch (error) {
log(
'Props parse faild on (%s[class=%s]),',
@ -3306,13 +3302,38 @@
}
}
})
// 一旦设定了 props的类型, 就必须传入正确的值
for (var k in newVmodel.props) {
if (newVmodel.props[k] && newVmodel.props[k].type === 'PropsTypes') {
if (newVmodel.props[k].check(props[k])) {
newVmodel.props[k] = props[k]
delete props[k]
} else {
Anot.error(
'props.' +
k +
' needs [' +
newVmodel.props[k].checkType +
'], but [' +
newVmodel.props[k].result +
'] given.',
TypeError
)
}
}
}
Object.assign(newVmodel.props, props)
props = undefined
}
}
scanAttr(elem, vm) //扫描特性节点
if (newVmodel) {
setTimeout(function() {
newVmodel.$fire(':scan-end', elem)
if (typeof newVmodel.mounted === 'function') {
newVmodel.mounted()
}
delete newVmodel.mounted
})
}
}
@ -3436,15 +3457,13 @@
var componentQueue = []
var widgetList = []
var componentHooks = {
construct: function(props, next) {
next(props)
},
construct: noop,
componentWillMount: noop,
componentDidMount: noop,
childComponentDidMount: noop,
componentWillUnmount: noop,
render: function(str) {
return str
render: function() {
return null
}
}
@ -3474,21 +3493,19 @@
return
}
var props = getOptionsFromTag(elem, host.vmodels)
var vmOpts = getOptionsFromVM(host.vmodels, props.config)
var $id = props.uuid || generateID(widget)
var componentDefinition = {}
props = Object.assign({}, vmOpts, props)
vmOpts = void 0
delete props.config
delete props.uuid
hooks.construct.call(elem, props, function next(val) {
Object.assign(hooks.props, val)
Object.assign(componentDefinition, hooks)
})
delete props.name
componentDefinition.$refs = {}
componentDefinition.$id = $id
hooks.props = hooks.props || {}
hooks.state = hooks.state || {}
Object.assign(hooks.props, props)
hooks.construct.call(elem, hooks.props, hooks.state)
hooks.$id = $id
//==========构建VM=========
var {
@ -3497,15 +3514,17 @@
childComponentDidMount,
componentWillUnmount,
render
} = componentDefinition
} = hooks
delete componentDefinition.construct
delete componentDefinition.componentWillMount
delete componentDefinition.componentDidMount
delete componentDefinition.childComponentDidMount
delete componentDefinition.componentWillUnmount
delete hooks.construct
delete hooks.componentWillMount
delete hooks.componentDidMount
delete hooks.childComponentDidMount
delete hooks.componentWillUnmount
var vmodel = Anot(componentDefinition)
var vmodel = Anot(hooks)
delete vmodel.mounted
host.vmodels[0].$children.push(vmodel)
elem.msResolved = 1 //防止二进扫描此元素
@ -3514,18 +3533,30 @@
if (!elem.content.firstElementChild) {
Anot.clearHTML(elem)
elem.innerHTML = render()
var html = render.call(vmodel) || ''
html = html.replace(/<\w+[^>]*>/g, function(m, s) {
return m.replace(/[\n\t\s]{1,}/g, ' ')
})
elem.innerHTML = html
}
// 组件所使用的标签是temlate,所以必须要要用子元素替换掉
var child = elem.content.firstElementChild
elem.parentNode.replaceChild(child, elem)
var nullComponent = DOC.createComment('empty component')
elem.parentNode.replaceChild(child || nullComponent, elem)
// 空组件直接跳出
if (!child) {
return
}
child.msResolved = 1
var cssText = elem.style.cssText
var className = elem.className
elem = host.element = child
elem.style.cssText += ';' + cssText
elem.style && (elem.style.cssText += ';' + cssText)
if (className) {
Anot(elem).addClass(className)
@ -3542,10 +3573,11 @@
if (ev.childReady) {
dependencies += ev.childReady
if (vmodel !== ev.vm) {
vmodel.$refs[ev.vm.$id] = ev.vm
vmodel.$children.push(ev.vm)
ev.vm.$up = vmodel
if (ev.childReady === -1) {
children++
childComponentDidMount.call(vmodel, elem, ev)
childComponentDidMount.call(vmodel, ev.vm)
}
ev.stopPropagation()
}
@ -3590,24 +3622,11 @@
})
}, 17)
}
})(obj, Anot.components[name], obj.element, obj.name) // jshint ignore:line
})(obj, toJson(Anot.components[name]), obj.element, obj.name) // jshint ignore:line
}
}
}
function getOptionsFromVM(vmodels, pre) {
if (pre) {
for (var i = 0, v; (v = vmodels[i++]); ) {
if (v.hasOwnProperty(pre) && typeof v[pre] === 'object') {
var vmOptions = v[pre]
return vmOptions.$model || vmOptions
break
}
}
}
return {}
}
function isWidget(el) {
//如果是组件,则返回组件的名字
var name = el.nodeName.toLowerCase()
@ -3617,6 +3636,10 @@
return null
}
function isRef(el) {
return el.hasAttribute('ref') ? el.getAttribute('ref') : null
}
var bools = [
'autofocus,autoplay,async,allowTransparency,checked,controls',
'declare,disabled,defer,defaultChecked,defaultSelected',
@ -3687,11 +3710,16 @@
update: function(val) {
var elem = this.element
var obj = val
var vm = this.vmodels[0]
if (typeof obj === 'object' && obj !== null) {
if (!Anot.isPlainObject(obj)) obj = obj.$model
if (!Anot.isPlainObject(obj)) {
obj = obj.$model
}
} else {
if (!this.param) return
if (!this.param) {
return
}
obj = {}
obj[this.param] = val
@ -3711,24 +3739,32 @@
//chrome v37- 下embed标签动态设置的src无法发起请求
if (window.chrome && elem.tagName === 'EMBED') {
var parent = elem.parentNode
var com = document.createComment(':src')
var com = DOC.createComment(':src')
parent.replaceChild(com, elem)
parent.replaceChild(elem, com)
}
} else {
var k = i
//古董IE下部分属性名字要进行映射
if (!W3C && propMap[k]) k = propMap[k]
if (!W3C && propMap[k]) {
k = propMap[k]
}
if (obj[i] === false || obj[i] === null || obj[i] === undefined) {
obj[i] = ''
}
if (typeof elem[boolMap[k]] === 'boolean') {
//布尔属性必须使用el.xxx = true|false方式设值
elem[boolMap[k]] = !!obj[i]
//如果为false, IE全系列下相当于setAttribute(xxx, ''),会影响到样式,需要进一步处理
if (!obj[i]) obj[i] = !!obj[i]
if (!obj[i]) {
obj[i] = !!obj[i]
}
if (obj[i] === false) {
return elem.removeAttribute(k)
}
}
if (obj[i] === false || obj[i] === null || obj[i] === undefined)
return elem.removeAttribute(k)
//SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy
var isInnate = rsvg.test(elem)
@ -3737,6 +3773,13 @@
if (isInnate) {
elem[k] = obj[i]
} else {
if (typeof obj[i] === 'object') {
obj[i] = JSON.stringify(obj[i])
} else if (typeof obj[i] === 'function') {
k = '__fn__' + camelize(k)
elem[k] = obj[i].bind(vm)
obj[i] = k
}
elem.setAttribute(k, obj[i])
}
}
@ -3881,115 +3924,121 @@
/*------ 表单验证 -------*/
var __rules = {}
Anot.validate = function(key) {
return (
!__rules[key] ||
__rules[key].every(function(it) {
return it.checked
})
)
Anot.validate = function(key, cb) {
if (!__rules[key]) {
throw new Error('validate [' + key + '] not exists.')
}
if (typeof cb === 'function') {
__rules[key].event = cb
}
var result = __rules[key].result
for (var k in result) {
if (!result[k].passed) {
return result[k]
}
}
return true
}
Anot.directive('rule', {
priority: 2010,
init: function(binding) {
if (binding.param && !__rules[binding.param]) {
__rules[binding.param] = []
__rules[binding.param] = {
event: noop,
result: {}
}
}
binding.target = __rules[binding.param]
},
update: function(obj) {
var _this = this,
elem = this.element,
ruleID = -1
if (!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) return
update: function(opt) {
var _this = this
var elem = this.element
if (!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) {
return
}
if (this.target) {
ruleID = this.target.length
this.target.push({ checked: true })
this.target.result[elem.expr] = { key: elem.expr }
}
var target = this.target
//如果父级元素没有定位属性,则加上相对定位
if (getComputedStyle(elem.parentNode).position === 'static') {
elem.parentNode.style.position = 'relative'
}
var $elem = Anot(elem),
ol = elem.offsetLeft + elem.offsetWidth - 50,
ot = elem.offsetTop + elem.offsetHeight + 8,
tips = document.createElement('div')
tips.className = 'do-rule-tips'
tips.style.left = ol + 'px'
tips.style.bottom = ot + 'px'
// 0: 验证通过
// 10001: 不能为空
// 10002: 必须为合法数字
// 10003: Email格式错误
// 10004: 手机格式错误
// 10005: 必须为纯中文
// 10006: 格式匹配错误(正则)
// 10011: 输入值超过指定最大长度
// 10012: 输入值短于指定最小长度
// 10021: 输入值大于指定最大数值
// 10022: 输入值小于指定最小数值
// 10031: 与指定的表单的值不一致
function checked(ev) {
var txt = '',
val = elem.value
var val = elem.value
var code = 0
if (obj.require && (val === '' || val === null)) txt = '必填项'
if (!txt && obj.isNumeric) txt = !isFinite(val) ? '必须为合法数字' : ''
if (!txt && obj.isEmail)
txt = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val)
? 'Email格式错误'
: ''
if (!txt && obj.isPhone)
txt = !/^1[34578]\d{9}$/.test(val) ? '手机格式错误' : ''
if (!txt && obj.isCN)
txt = !/^[\u4e00-\u9fa5]+$/.test(val) ? '必须为纯中文' : ''
if (!txt && obj.exp)
txt = !obj.exp.test(val) ? obj.msg || '格式错误' : ''
if (!txt && obj.maxLen)
txt =
val.length > obj.maxLen ? '长度不得超过' + obj.maxLen + '位' : ''
if (!txt && obj.minLen)
txt =
val.length < obj.minLen ? '长度不得小于' + obj.minLen + '位' : ''
if (!txt && obj.hasOwnProperty('max'))
txt = val > obj.max ? '输入值不能大于' + obj.max : ''
if (!txt && obj.hasOwnProperty('min'))
txt = val < obj.min ? '输入值不能小于' + obj.min : ''
if (!txt && obj.eq) {
var eqEl = document.querySelector('#' + obj.eq)
txt = val !== eqEl.value ? obj.msg || '2次值不一致' : ''
if (opt.require && (val === '' || val === null)) {
code = 10001
}
if (txt) {
if (ev) {
tips.textContent = txt
elem.parentNode.appendChild(tips)
if (code === 0 && opt.isNumeric) {
code = !isFinite(val) ? 10002 : 0
}
if (code === 0 && opt.isEmail)
code = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val) ? 10003 : 0
if (code === 0 && opt.isPhone) {
code = !/^1[34578]\d{9}$/.test(val) ? 10004 : 0
}
if (code === 0 && opt.isCN) {
code = !/^[\u4e00-\u9fa5]+$/.test(val) ? 10005 : 0
}
if (code === 0 && opt.exp) {
code = !opt.exp.test(val) ? 10006 : 0
}
if (code === 0 && opt.maxLen) {
code = val.length > opt.maxLen ? 10011 : 0
}
if (code === 0 && opt.minLen) {
code = val.length < opt.minLen ? 10012 : 0
}
if (code === 0 && opt.hasOwnProperty('max')) {
code = val > opt.max ? 10021 : 0
}
if (code === 0 && opt.hasOwnProperty('min')) {
code = val < opt.min ? 10022 : 0
}
if (code === 0 && opt.eq) {
var eqEl = document.querySelector('#' + opt.eq)
txt = val !== eqEl.value ? 10031 : 0
}
target.result[elem.expr].code = code
target.result[elem.expr].passed = opt.require ? code === 0 : true
var done
for (var k in target.result) {
if (!target.result[k].passed) {
done = true
target.event(target.result[k])
break
}
//必须是"必填项"才会更新验证状态
if (_this.target && obj.require) {
_this.target[ruleID].checked = false
}
} else {
if (_this.target) {
_this.target[ruleID].checked = true
}
try {
elem.parentNode.removeChild(tips)
} catch (err) {}
}
if (!done) {
target.event(true)
}
}
$elem.bind('change,blur', checked)
$elem.bind('focus', function(ev) {
try {
elem.parentNode.removeChild(tips)
} catch (err) {}
})
Anot(elem).bind('blur', checked)
checked()
}
})
@ -4039,12 +4088,13 @@
? 'change'
: 'input'
}
elem.expr = binding.expr
//===================绑定事件======================
var bound = (binding.bound = function(type, callback) {
elem.addEventListener(type, callback, false)
var old = binding.rollback
binding.rollback = function() {
elem.anotStter = null
elem.anotSetter = null
Anot.unbind(elem, type, callback)
old && old()
}
@ -4148,7 +4198,7 @@
elem.msFocus = false
})
}
elem.anotStter = updateVModel //#765
elem.anotSetter = updateVModel //#765
watchValueInTimer(function() {
if (root.contains(elem)) {
if (!elem.msFocus) {
@ -4167,7 +4217,7 @@
if (!this.init) {
for (var i in Anot.vmodels) {
var v = Anot.vmodels[i]
v.$fire('any-duplex-init', binding)
v.$fire('anot-duplex-init', binding)
}
var cpipe = binding.pipe || (binding.pipe = pipe)
cpipe(null, binding, 'init')
@ -4250,17 +4300,7 @@
if (-val === -number) {
return number
}
var arr = /strong|medium|weak/.exec(
binding.element.getAttribute('data-duplex-number')
) || ['medium']
switch (arr[0]) {
case 'strong':
return 0
case 'medium':
return val === '' ? '' : 0
case 'weak':
return val
}
return 0
},
set: fixNull
}
@ -4308,8 +4348,8 @@
function newSetter(value) {
// jshint ignore:line
setters[this.tagName].call(this, value)
if (!this.msFocus && this.anotStter) {
this.anotStter()
if (!this.msFocus && this.anotSetter) {
this.anotSetter()
}
}
var inputProto = HTMLInputElement.prototype
@ -5676,7 +5716,9 @@
time: function(str) {
str = str >> 0
var s = str % 60
;(m = Math.floor(str / 60)), (h = Math.floor(m / 60)), (m = m % 60)
var m = Math.floor(str / 60)
var h = Math.floor(m / 60)
m = m % 60
m = m < 10 ? '0' + m : m
s = s < 10 ? '0' + s : s
@ -5763,14 +5805,38 @@
}
})
// Map over Anot in case of overwrite
var _Anot = window.Anot
Anot.noConflict = function(deep) {
if (deep && window.Anot === Anot) {
window.Anot = _Anot
/*********************************************************************
* DOMReady *
**********************************************************************/
var readyList = [],
isReady
var fireReady = function(fn) {
isReady = true
var require = Anot.require
if (require && require.checkDeps) {
modules['domReady!'].state = 4
require.checkDeps()
}
while ((fn = readyList.shift())) {
fn(Anot)
}
return Anot
}
window.Anot = Anot
})
if (DOC.readyState === 'complete') {
setTimeout(fireReady) //如果在domReady之外加载
} else {
DOC.addEventListener('DOMContentLoaded', fireReady)
}
window.addEventListener('load', fireReady)
Anot.ready = function(fn) {
if (!isReady) {
readyList.push(fn)
} else {
fn(Anot)
}
}
return Anot
})()
export default _Anot

View File

@ -35,7 +35,7 @@
var head = DOC.head //HEAD元素
head.insertAdjacentHTML(
'afterBegin',
'<anot :skip class="anot-hide"><style id="anot-style">.anot-hide{ display: none!important } .do-rule-tips {position:absolute;z-index:65535;min-width:75px;height:30px;padding:7px 8px;line-height:16px;color:#333;background:#f9ca05;white-space:pre;} .do-rule-tips::before {position:absolute;left:5px;bottom:-8px;width:0;height:0;border:8px solid transparent;border-left:8px solid #f9ca05;content: " "}</style></anot>'
'<anot skip class="anot-hide"><style id="anot-style">.anot-hide{ display: none!important }</style></anot>'
)
var ifGroup = head.firstChild
@ -3939,115 +3939,120 @@
/*------ 表单验证 -------*/
var __rules = {}
Anot.validate = function(key) {
return (
!__rules[key] ||
__rules[key].every(function(it) {
return it.checked
})
)
Anot.validate = function(key, cb) {
if (!__rules[key]) {
throw new Error('validate [' + key + '] not exists.')
}
if (typeof cb === 'function') {
__rules[key].event = cb
}
var result = __rules[key].result
for (var k in result) {
if (!result[k].passed) {
return result[k]
}
}
return true
}
Anot.directive('rule', {
priority: 2010,
init: function(binding) {
if (binding.param && !__rules[binding.param]) {
__rules[binding.param] = []
__rules[binding.param] = {
event: noop,
result: {}
}
}
binding.target = __rules[binding.param]
},
update: function(obj) {
var _this = this,
elem = this.element,
ruleID = -1
if (!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) return
update: function(opt) {
var _this = this
var elem = this.element
if (!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) {
return
}
if (this.target) {
ruleID = this.target.length
this.target.push({ checked: true })
this.target.result[elem.expr] = { key: elem.expr }
}
var target = this.target
//如果父级元素没有定位属性,则加上相对定位
if (getComputedStyle(elem.parentNode).position === 'static') {
elem.parentNode.style.position = 'relative'
}
var $elem = Anot(elem),
ol = elem.offsetLeft + elem.offsetWidth - 50,
ot = elem.offsetTop + elem.offsetHeight + 8,
tips = document.createElement('div')
tips.className = 'do-rule-tips'
tips.style.left = ol + 'px'
tips.style.bottom = ot + 'px'
// 0: 验证通过
// 10001: 不能为空
// 10002: 必须为合法数字
// 10003: Email格式错误
// 10004: 手机格式错误
// 10005: 必须为纯中文
// 10006: 格式匹配错误(正则)
// 10011: 输入值超过指定最大长度
// 10012: 输入值短于指定最小长度
// 10021: 输入值大于指定最大数值
// 10022: 输入值小于指定最小数值
// 10031: 与指定的表单的值不一致
function checked(ev) {
var txt = '',
val = elem.value
var val = elem.value
var code = 0
if (obj.require && (val === '' || val === null)) txt = '必填项'
if (!txt && obj.isNumeric) txt = !isFinite(val) ? '必须为合法数字' : ''
if (!txt && obj.isEmail)
txt = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val)
? 'Email格式错误'
: ''
if (!txt && obj.isPhone)
txt = !/^1[34578]\d{9}$/.test(val) ? '手机格式错误' : ''
if (!txt && obj.isCN)
txt = !/^[\u4e00-\u9fa5]+$/.test(val) ? '必须为纯中文' : ''
if (!txt && obj.exp)
txt = !obj.exp.test(val) ? obj.msg || '格式错误' : ''
if (!txt && obj.maxLen)
txt =
val.length > obj.maxLen ? '长度不得超过' + obj.maxLen + '位' : ''
if (!txt && obj.minLen)
txt =
val.length < obj.minLen ? '长度不得小于' + obj.minLen + '位' : ''
if (!txt && obj.hasOwnProperty('max'))
txt = val > obj.max ? '输入值不能大于' + obj.max : ''
if (!txt && obj.hasOwnProperty('min'))
txt = val < obj.min ? '输入值不能小于' + obj.min : ''
if (!txt && obj.eq) {
var eqEl = document.querySelector('#' + obj.eq)
txt = val !== eqEl.value ? obj.msg || '2次值不一致' : ''
if (opt.require && (val === '' || val === null)) {
code = 10001
}
if (txt) {
if (ev) {
tips.textContent = txt
elem.parentNode.appendChild(tips)
if (code === 0 && opt.isNumeric) {
code = !isFinite(val) ? 10002 : 0
}
if (code === 0 && opt.isEmail)
code = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val) ? 10003 : 0
if (code === 0 && opt.isPhone) {
code = !/^1[34578]\d{9}$/.test(val) ? 10004 : 0
}
if (code === 0 && opt.isCN) {
code = !/^[\u4e00-\u9fa5]+$/.test(val) ? 10005 : 0
}
if (code === 0 && opt.exp) {
code = !opt.exp.test(val) ? 10006 : 0
}
if (code === 0 && opt.maxLen) {
code = val.length > opt.maxLen ? 10011 : 0
}
if (code === 0 && opt.minLen) {
code = val.length < opt.minLen ? 10012 : 0
}
if (code === 0 && opt.hasOwnProperty('max')) {
code = val > opt.max ? 10021 : 0
}
if (code === 0 && opt.hasOwnProperty('min')) {
code = val < opt.min ? 10022 : 0
}
if (code === 0 && opt.eq) {
var eqEl = document.querySelector('#' + opt.eq)
txt = val !== eqEl.value ? 10031 : 0
}
target.result[elem.expr].code = code
target.result[elem.expr].passed = opt.require ? code === 0 : true
var done
for (var k in target.result) {
if (!target.result[k].passed) {
done = true
target.event(target.result[k])
break
}
//必须是"必填项"才会更新验证状态
if (_this.target && obj.require) {
_this.target[ruleID].checked = false
}
} else {
if (_this.target) {
_this.target[ruleID].checked = true
}
try {
elem.parentNode.removeChild(tips)
} catch (err) {}
}
if (!done) {
target.event(true)
}
}
$elem.bind('change,blur', checked)
$elem.bind('focus', function(ev) {
try {
elem.parentNode.removeChild(tips)
} catch (err) {}
})
Anot(elem).bind('blur', checked)
checked()
}
})
@ -4097,6 +4102,7 @@
? 'change'
: 'input'
}
elem.expr = binding.expr
//===================绑定事件======================
var bound = (binding.bound = function(type, callback) {
elem.addEventListener(type, callback, false)