jQuery操作DOM工具类
Utils
.js代码
if (!window.Utils || typeof Utils !== 'function') {
/**
* 工具类
* @returns {Utils}
* @constructor
*/
var Utils = function () {
return this;
};
(function () {
const REG_PKG_B_TO_E = /^\d*to\d*$/i,
REG_PKG_I_NUM_X = /^(-?\d+(\.\d+)?)*num(-?\d+(\.\d+)?)*$/i;
const REG_EMPTY_STR = /\s+/, //无效字符
REG_NUM = /^-?\d+(\.\d+)?$/, //数字
REG_ZIP = /^[1-9]\d{5}$/, //邮编
REG_EMAIL = /^[a-zA-Z\d($\+\-\._#&)\u4e00-\u9fff]{1,20}@[a-zA-Z\d\-$_]{1,20}(\.[a-zA-Z\d]{2,3}){1,3}$/, //邮箱
REG_PHONE = /^(\+?86)?1(3|[5-9])\d{9}$/, //手机号
REG_IDENTITY = /^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|71|8[1-2])\d{4}((19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[0-1]))\d{3}(\d|x|X)$/, //身份证号
REG_THOU = /^-?(\d+,{1})+\d+(\.\d+)?$/; //数字千分位分隔
Utils.prototype.getRegEmptyStr = function () {
return REG_EMPTY_STR;
};
Utils.prototype.getRegNum = function () {
return REG_NUM;
};
Utils.prototype.getRegZip = function () {
return REG_ZIP;
};
Utils.prototype.getRegEmail = function () {
return REG_EMAIL;
};
Utils.prototype.getRegPhone = function () {
return REG_PHONE;
};
Utils.prototype.getRegIdentity = function () {
return REG_IDENTITY;
};
Utils.prototype.getRegThou = function () {
return REG_THOU;
};
/**
* 添加前缀。例:preAdd('0', 6, '*'); //结果:'*****0'
* @param n {@link Object}:被操作的本体;
* @param len {@link Number}:总长度;
* @param preStr {@link String}:(选参)被添加的前缀字符,默认“0”;
* @returns {@link String}:处理后的字符。
*/
Utils.prototype.preAdd = function (n, len, preStr) {
if (!(n = String(n)) || (len = Number(len) - n.length) < 1)
return n;
preStr = preStr || '0';
var pres = Array(++len).join(preStr);
return pres + n;
};
/**
* 数字千分位分隔
* @param num {@link Number}:被处理的数值;
* @param bit {@link Number}:分隔位数,默认为3;
* @returns {@link String}:数字千分位字符。
*/
Utils.prototype.numToThou = function (num) {
if (num === 0)
return '0';
var bit = arguments[1] || 3;
var numStr = $.trim(String(num || ''));
if (numStr && !isNaN(numStr)) {
num = Number(numStr); //防止"0001.00"
var numSplit = numStr.split('.');
var numInt = numSplit[0];
numSplit[0] = String(Math.abs(numInt));
var numArray = [];
for (var i = numSplit[0].length; i > 0; i -= bit) {
if (i >= bit) {
var idx = i - bit;
var sz = bit;
} else {
var idx = 0;
var sz = i;
}
numArray.unshift(numSplit[0].substr(idx, sz));
}
return (num < 0 ? '-' : '') + numArray.join() + (!numSplit[1] ? '' : ('.' + numSplit[1]));
}
//return '0';
return numStr;
};
/**
* 千分位转数字
* @param num {@link String}:被处理的千分位数值;
* @returns {@link String}:数字字符。
*/
Utils.prototype.thouToNum = function thouToNum(num) {
if (num === 0)
return '0';
var numStr = $.trim(String(num || ''));
if (REG_THOU.test(numStr)) //将“千分位”分隔字符处理为数字字符
return numStr.replace(/,/g, '');
return numStr;
};
/**
* 数字超出位数截断
* @param dom {@link Object}:被操作的DOM对象;
* @param ureLen {@link Number}:截取后,要保留的位数;
* @param minNum {@link Number}:输入的最小数值;
*/
Utils.prototype.numCut = function (dom, ureLen, minNum) {
var kc = event.keyCode;
if ((kc > 36 && kc < 41) || (kc > 110 && kc < 124)) //无效键码
return;
var ts = $(dom);
try {
var tsVal = ts.val();
if (tsVal) {
var reg = new RegExp('[^\\d\\.-]', 'g');
if (reg.test(tsVal)) {
tsVal = tsVal.replace(reg, '');
ts.val(tsVal);
}
if (!isNaN(tsVal)) {
var numval = Number(tsVal);
minNum = Number(minNum) || 0;
if (numval < minNum) {
alert('输入的数值,请不要小于' + minNum);
ts.val(minNum).next().val(minNum);
return;
}
var maxNum = Math.pow(10, 19);
if (Math.abs(numval) > maxNum) {
alert('输入的数值 ' + tsVal + ' 过大!\n\r请不要超过 ' + maxNum + ',确认后再重新输入!');
ts.val(maxNum).next().val(maxNum);
return;
}
if (numval % 1 > 0 || tsVal.indexOf('.') != -1) {
ureLen = parseInt(ureLen) || 2;
var vsp = tsVal.split('.');
if (vsp[1] && vsp[1].length > ureLen) {
// ts.val(numval.toFixed(ureLen));
ts.val(Number(vsp[0] + '.' + vsp[1].substr(0, ureLen)));
}
}
} else {
var fltVal = parseFloat(tsVal + '0'); //末尾添加"0"后转化,防止首先输入"-"、"."等非数字字符。
if (isNaN(fltVal))
ts.val('');
else if (fltVal != 0)
ts.val(fltVal);
}
}
} catch (e) {
//
}
};
/**
* 清空区域内容
* @param me {@link Object}:区域DOM对象;
* @param sel {@link String}:被清空元素的jQuery选择器;
* @returns {@link Number}:被清空元素数。
*/
Utils.prototype.cleanup = function (me, sel) {
var num = 0;
var sv = (me = $(me)).attr('cleanup') || me;
var doms = $(sv).find(sel ? sel : '[name], input, select, textarea');
doms.each(function (i) {
var dom = $(this);
if (dom.is('input')) { //<input />
var domType = dom.attr('type');
if (domType == 'checkbox' || domType == 'radio')
dom.prop('checked', false);
else
dom.val('');
} else if (dom.is('select')) { //<select></select>
dom.find('option:selected').attr('selected', false);
} else {
dom.val('');
}
num++;
});
return num;
};
/**
* 提交验证
* @param obj {@link Object}:
* @param obj.sel {@link Object}:jQuery选择器,被验证的DOM范围;
* @param obj.hintPosi {@link Object}:jQuery选择器,提示位置;
* @param obj.hintDom {@link Object}:jQuery选择器,提示DOM体;
* @param obj.hintText {@link Object}:jQuery选择器,提示文本位置;
* @returns {@link Boolean}:是否验证通过:true - 通过。
*/
Utils.prototype.inputValidate = function (obj) {
var result = true;
if (Object.prototype.toString.call(obj) != '[object Object]' || !obj.sel)
obj = {
sel: obj
};
var valis = $(!obj.sel ? 'body' : obj.sel).find('[validate]');
try {
var run = function (valis, index, obj) {
var cont = [];
var me = valis.eq(index);
var meVal = me.val();
var vds = me.attr('validate').split(';');
for (var i = 0; i < vds.length && $.trim(vds[i]); i++) {
var vd = vds[i].toLowerCase();
if (vd == 'notnull') {
if (!$.trim(meVal))
cont.push('不能为空');
} else if (REG_PKG_B_TO_E.test(vd)) {
if (!meVal)
continue;
var b2e = vd.split(/to/i);
var b = Number(isNaN(b2e[0]) ? 0 : b2e[0]);
var e = Number(isNaN(b2e[1]) ? 0 : b2e[1]);
if ((meVal.length - b) * (meVal.length - e) > 0)
cont.push(['字符数在', b, '-', e, '之间'].join(' '));
} else if (vd == 'void') {
if (REG_EMPTY_STR.test(meVal))
cont.push('不能含空格等无效字符');
} else if (REG_PKG_I_NUM_X.test(vd)) {
if (!meVal)
continue;
if (!REG_NUM.test(meVal)) {
cont.push('只能是数字');
continue;
}
var i2x = vd.split(/num/i);
if (i2x[0]) {
var min = Number(isNaN(i2x[0]) ? 0 : i2x[0]);
if (meVal < min)
cont.push('最小值(' + min + ')');
}
if (i2x[1]) {
var max = Number(isNaN(i2x[1]) ? 0 : i2x[1]);
if (meVal > max)
cont.push('最大值(' + max + ')');
}
} else if (vd == 'email') {
if (!meVal)
continue;
if (!REG_EMAIL.test(meVal))
cont.push('邮箱格式错误');
} else if (vd == 'phone') {
if (!meVal)
continue;
if (!REG_PHONE.test(meVal))
cont.push('电话号格式错误');
} else if (vd == 'zip') {
if (!meVal)
continue;
if (!REG_ZIP.test(meVal))
cont.push('邮编格式错误');
} else {
var isReg = false;
try {
isReg = new RegExp(vds[i]).test(meVal);
} catch (e) {
isReg = false;
}
if (!isReg)
cont.push('不符合规则(' + vds[i] + ')');
}
}
var hp = ((!obj.hintPosi) ? me.constructor : obj.hintPosi)(me);
if (!cont.length) {
hp.nextAll('[vhi="' + index + '"]').remove();
} else {
result = false;
var labSpan = hp.nextAll('[vhi="' + index + '"]');
if (!labSpan.length) {
labSpan = $(obj.hintDom || '<span>');
labSpan.addClass('hint').attr('vhi', index);
labSpan.css(obj.hintCss || {});
hp.after(labSpan);
}
(!obj.hintText ? labSpan : labSpan.find(obj.hintText)).text(cont.join(';'));
}
};
for (var i = 0; i < valis.length; i++)
run(valis, i, obj);
} catch (e) {
result = false;
(!console ? window.console : console).error(e);
}
return result;
};
/**
* 设置DOM区域name值
* @param dom {@link Object}:jQuery选择器:DOM区域对象;
* @param obj {@link Object}:name属性对应的实体;
* @returns {@link Number}:已设置的元素数。
*/
Utils.prototype.setVal = function(dom, obj) {
if (!obj || Object.prototype.toString.call(obj) != '[object Object]') //强制"obj"为Object类型
return -1;
var num = 0;
for (var k in obj) { //效验obj是否含有效值
if (obj[k] != null) {
num++; //num = 1;
break;
}
}
if (!num--) //obj内部属性全部无效(num--:先赋值后运算,还原初始值为0)
return -1;
var ns = $(dom || 'body').find('[name]');
var set = function (ns, i, obj) {
var dom = ns.eq(i);
var name = dom.attr('name');
var v = obj[name];
if (v == null) //不过滤:Number: 0, Boolean: false, Array等
return false;
num++;
if (dom.is('input')) { //<input />
var domType = dom.attr('type');
if (domType == 'radio') { //单选
dom.prop('checked', dom.val() == String(v));
return true;
} else if (domType == 'checkbox') { //多选
var dv = dom.val();
if (dv == String(v)) { //防止Boolean类型判断错误
dom.prop('checked', true);
} else if (v instanceof Object) { //是可遍历对象:Array或Object
for (var k in v) {
if (dv == String(v[k])) {
dom.prop('checked', true);
break;
}
}
} else {
dom.prop('checked', false);
}
return true;
} else if (domType == 'file') { //input file不可修改值
num--;
return false;
}
}
dom.val(v);
return true;
};
for (var i = 0, len = ns.length; i < len; i++)
set(ns, i, obj);
return num;
};
/**
* 序列化DOM区域name对象
* @param dom {@link Object}:jQuery选择器:DOM区域对象;
* @param obj {@link Object}:
* @param obj.trim {@link Boolean}:是否过滤前后导空白,默认:true;
* @param obj.blank {@link Boolean}:是否允许无效字符,默认:false;
* @param obj.empty {@link Boolean}:是否允许空字符,默认:false;
*/
Utils.prototype.serial = function (dom, obj) {
var kv = {};
var ns = $(dom || 'body').find('[name]');
var seri = function (ns, i, obj) {
var dom = ns.eq(i);
if (dom.is('input')) { //<input />
var domType = dom.attr('type');
if ((domType == 'checkbox' || domType == 'radio') && !dom.is(':checked')) //跳过未选中
return false;
}
var v = dom.val();
v = !obj.trim ? $.trim(v) : v; //是否过滤前后导空白
if (
(!obj.blank && (!v || !$.trim(v))) //是否允许无效字符
|| (!obj.empty && !v) //是否允许空字符
)
return false;
var k = dom.attr('name');
if (domType == 'checkbox') //checkbox单独处理(domType无作用域)
(!kv[k] ? (kv[k] = []) : kv[k]).push(v);
else
kv[k] = v;
return true;
};
if (!obj)
obj = {};
for (var i = 0, len = ns.length; i < len; i++)
seri(ns, i, obj);
return kv;
};
})();
}
DOM操作的部分常用功能,其它未涉及到的将逐渐补充、更新。
有其它更好功能的童鞋们,欢迎在此评论区分享成果。
测试示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Utils test</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" type="application/javascript"></script>
<script src="./Utils.js" type="application/javascript"></script>
</head>
<body>
<div k="cont">
<div id="cont1">
<label>ID:</label>
<input name="id" validate="notNull;0num" /><!-- [validate]验证:非空、数字(最小值为0) -->
<br/>
<label>课程:</label>
<input id="rd1" name="lesson" type="radio" value="app" />
<label for="rd1">前端</label>
<input id="rd2" name="lesson" type="radio" value="service" />
<label for="rd2">后端</label>
<br/>
<label>书籍:</label>
<input id="bok1" name="books" type="checkbox" value="JS" />
<label for="bok1">JS</label>
<input id="bok2" name="books" type="checkbox" value="JAVA" />
<label for="bok2">JAVA</label>
<br/>
<label>价格:</label>
<input name="money" validate="notNull;0num9.9"></input>
<br/>
<label>备注:</label>
<textarea name="remark" validate="2to10"></textarea><!-- [validate]验证:字符数在2 - 10之间 -->
<br/>
<button class="cleanup" cleanup="[k='cont'] #cont1">清空</button>
<button class="validate">验证</button>
<br/>
<button class="setv">赋值</button>
<i id="setv"></i>
<br/>
<button class="serial">序列化DOM</button>
<span id="serial"></span>
</div>
<hr/>
<div id="cont2">
<label>小功能:</label>
<input name="text" value="1234567.8901" validate="notNull;^-?\d+$" />
<button class="pre-add">添加前缀</button>
<button class="num-thou">数字 > 千分位</button>
<button class="thou-num">千分位 > 数字</button>
<button class="num-cut">截断2位</button>
<button class="validate">验证</button>
<button class="cleanup" cleanup="#cont2">清空</button>
</div>
</div>
</body>
</html>
<script type="text/javascript">
var utils = new Utils();
$(function () {
/* 清空 */
$('.cleanup').click(function (e) {
utils.cleanup(this);
});
/* 验证(暂不支持"radio"和"checkbox") */
$('#cont1 .validate').click(function (e) {
utils.inputValidate('#cont1') && alert('验证通过');
});
$('#cont2 .validate').click(function (e) {
var r = utils.inputValidate({
sel: '#cont2',
hintDom: '<p style="color: red"><b>', //使用<p>标签提示
hintText: 'b', //提示内容显示到:"hintDom"创建的<p>标签下的<b>标签内,
hintPosi: function (me) {
return me.parent();
}
});
r && alert('验证通过');
});
/* 赋值 */
var setv = {
id: -1,
lesson: 'service',
books: [ 'JS', 'JAVA' ],
money: 90.1,
remark: '使用 utils.SetVal 区域赋值'
};
$('#setv').text(JSON.stringify(setv));
$('.setv').click(function (e) {
utils.setVal('[k="cont"]', setv);
});
/* 序列化DOM */
$('.serial').click(function (e) {
var r = utils.serial('#cont1', {
trim: false //不过滤前后导空白
});
$('#serial').text(JSON.stringify(r));
});
/* 添加前缀 */
$('.pre-add').click(function (e) {
var ipt = $('[name="text"]');
var r = utils.preAdd(ipt.val(), 15);
ipt.val(r);
});
/* 数字 > 千分位 */
$('.num-thou').click(function (e) {
var ipt = $('[name="text"]');
var r = utils.numToThou(ipt.val());
ipt.val(r);
});
/* 千分位 > 数字 */
$('.thou-num').click(function (e) {
var ipt = $('[name="text"]');
var r = utils.thouToNum(ipt.val());
ipt.val(r);
});
/* 截断2位 */
$('.num-cut').click(function (e) {
var ipt = $('[name="text"]');
utils.numCut(ipt, 2);
});
});
</script>
<style type="text/css">
/* 错误提示 */
.hint {
color: red;
font-size: 12px;
}
</style>
使用过程中,如出现bug,或有其它优化建议,欢迎在此文章“评论区”留言讨论,并留下您的邮箱,以便改正后及时通知您。