pull/2/head
wang ziting 3 months ago
parent ecaa541e38
commit bf9f1391f5

@ -4,36 +4,48 @@
Date: 2019/12/18
Time: 14:05
To change this template use File | Settings | File Templates.
这部分是HTML页面头部的注释说明了该文件创建时的相关信息如创建者、创建日期、时间以及提示如何修改模板等内容方便后续对代码来源及修改情况进行追溯。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>欢迎页面</title>
<!-- 引入layui框架的CSS样式文件路径通过表达式语言获取当前页面上下文请求路径拼接而成layui是一个用于构建页面交互界面的前端框架这里引入的CSS文件用于设置页面基于layui框架的样式风格。 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/lib/layui/css/layui.css" />
<!-- 引入jQuery库的JavaScript文件这是一个常用的JavaScript库用于简化DOM操作、事件处理等功能方便后续编写页面的交互逻辑。 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
</head>
<body>
<!-- 创建一个字段集fieldset元素应用layui的相关样式类layui-elem-field和layui-field-title用于对页面中的相关内容进行分组展示设置顶部外边距为30px使其与上方元素有一定间隔内部包含一个用于显示标题的<legend>元素,这里标题为“系统时间”,用于提示该部分内容的主题。 -->
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend>系统时间</legend>
</fieldset>
<!-- 创建一个引用块blockquote元素应用layui的相关样式类layui-elem-quote并设置id为“mytime”这个元素用于后续通过JavaScript代码动态显示系统时间初始时为空等待脚本填充内容。 -->
<blockquote class="layui-elem-quote" id="mytime"></blockquote>
<!-- 再次创建一个字段集元素同样应用layui的样式类设置顶部外边距为20px用于对下一部分内容进行分组内部标题为“控制面板”提示接下来展示的内容与系统控制面板相关。 -->
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
<legend>控制面板</legend>
</fieldset>
<!-- 创建一个具有内边距和背景颜色设置的<div>元素,用于作为控制面板相关内容的容器,营造出一个视觉上区分开的区域,背景颜色设置为#F2F2F2浅灰色使其更突出显示。 -->
<div style="padding: 20px; background-color: #F2F2F2;">
<!-- 创建一个layui的行元素并设置列间距为15px基于layui的网格布局系统用于在水平方向上合理排列内部的各个模块使其分布更规整。 -->
<div class="layui-row layui-col-space15">
<!-- 创建一个占6列宽度基于layui的网格系统中md尺寸中等屏幕尺寸下的布局规则的列元素用于放置一个卡片式的模块。 -->
<div class="layui-col-md6">
<div class="layui-card">
<!-- 创建卡片的头部区域应用layui的卡片头部样式类显示文本“CPU利用率”用于提示该卡片内展示的内容主题。 -->
<div class="layui-card-header">CPU利用率</div>
<div class="layui-card-body">
<!-- 在卡片的主体区域内简单显示文本“CPU利用率”这里可能后续需要进一步完善比如通过JavaScript等方式动态获取并展示实际的CPU利用率数据等内容。 -->
CPU<br/>利用率
</div>
</div>
</div>
<!-- 再次创建一个占6列宽度的列元素同样放置一个卡片式模块结构与上面类似用于展示“系统出入流量”相关信息不过目前主体区域也只是简单显示文本有待进一步完善功能来展示真实数据。 -->
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">系统出入流量</div>
@ -43,6 +55,7 @@
</div>
</div>
<!-- 又创建一个占6列宽度的列元素及对应的卡片模块用于展示某个“模块”相关信息目前显示“模块待更新”文本推测后续可能会根据业务需求完善此处比如显示模块的版本、更新提示等具体内容。 -->
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">模块</div>
@ -52,6 +65,7 @@
</div>
</div>
<!-- 最后再创建一个占6列宽度的列元素及卡片模块同样显示“模块待更新”文本结构和功能与上一个模块类似可能是多个需要展示和更新管理的模块在页面上的布局体现。 -->
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">模块</div>
@ -65,16 +79,25 @@
</div>
<script>
function showTime(){
var nowtime =new Date();
var year=nowtime.getFullYear();
var month=nowtime.getMonth()+1;
var date=nowtime.getDate();
// 创建一个Date对象用于获取当前的系统时间信息它会包含年、月、日、时、分、秒等详细时间数据。
var nowtime = new Date();
// 通过Date对象的getFullYear()方法获取当前的年份例如2024年等。
var year = nowtime.getFullYear();
// 通过Date对象的getMonth()方法获取当前的月份注意返回值是0 - 11所以需要加1才是我们日常使用的1 - 12月的表示方式。
var month = nowtime.getMonth() + 1;
// 通过Date对象的getDate()方法获取当前的日期即一个月中的第几天范围是1 - 31。
var date = nowtime.getDate();
// 通过Date对象的getHours()方法获取当前的小时数范围是0 - 23。
var h = nowtime.getHours();
// 通过Date对象的getMinutes()方法获取当前的分钟数范围是0 - 59。
var m = nowtime.getMinutes();
// 通过Date对象的getSeconds()方法获取当前的秒数范围是0 - 59。
var s = nowtime.getSeconds();
document.getElementById("mytime").innerText=year+"年"+month+"月"+date+"日"+" "+h+"时"+m+"分"+s+"秒";
// 将获取到的年、月、日、时、分、秒等时间信息组合成一个格式化后的字符串并通过DOM操作使用document.getElementById获取id为“mytime”的元素然后设置其innerText属性将这个时间字符串显示在页面上对应的引用块元素中实现动态显示系统当前时间的功能。
document.getElementById("mytime").innerText = year + "年" + month + "月" + date + "日" + " " + h + "时" + m + "分" + s + "秒";
}
setInterval("showTime()",1000);
// 使用JavaScript的setInterval函数每隔1000毫秒即1秒调用一次showTime函数从而实现每隔1秒更新一次页面上显示的系统时间达到实时显示当前时间的效果。
setInterval("showTime()", 1000);
</script>
</body>
</html>

@ -1,63 +1,97 @@
/*
* minimobile.js v0.0.1 by chenyaowen
* 在保留作者签名的情况下允许使用与商业用途
* 该文件是一个用于移动端页面布局相关功能的JavaScript代码库包含了一些处理页面缩放适配以及常见UI组件功能的代码例如处理viewport设置侧栏显示隐藏返回顶部功能进度条展示等
*/
if(!window.Zepto && !window.jQuery){
// 检查页面是否引入了Zepto.js或者jQuery.js如果都没引入则在控制台输出提示信息因为后续代码依赖这两个库之一。
if (!window.Zepto &&!window.jQuery) {
console.log("minimobile 是基于Zepto.js 或者 jQuery.js 的请检查页面是否已在miniMobile之前引入")
}
;(function(win, lib) {
//摘自淘宝移动端
}
// 立即执行函数用于创建一个局部作用域避免全局变量污染同时接收window对象和一个名为lib的对象如果不存在则创建一个空对象作为参数在函数内部进行相关页面适配等功能的实现。
;(function (win, lib) {
// 获取当前页面的document对象后续会用于操作页面元素、获取页面相关属性等操作。
var doc = win.document;
// 获取页面根元素(<html>元素),很多页面样式和布局相关的设置会基于这个元素来操作,例如设置页面字体大小等属性。
var docEl = doc.documentElement;
// 通过选择器查找页面中name属性为"viewport"的meta标签viewport元标签常用于控制页面在移动端的缩放、布局等显示相关设置。
var metaEl = doc.querySelector('meta[name="viewport"]');
// 通过选择器查找页面中name属性为"flexible"的meta标签从代码逻辑看用于获取一些和页面缩放比例相关的自定义配置信息。
var flexibleEl = doc.querySelector('meta[name="flexible"]');
// 用于存储设备像素比devicePixelRatio相关的缩放因子初始化为0后续会根据不同情况计算并赋值。
var dpr = 0;
// 用于存储页面的缩放比例初始化为0会根据meta标签内容或者设备类型等情况来确定具体值。
var scale = 0;
// 用于存储定时器的标识在处理页面resize和pageshow等事件时通过定时器来延迟执行一些操作避免频繁触发导致性能问题初始化为null或未定义取决于JavaScript环境
var tid;
// 创建一个名为flexible的对象用于存储页面适配相关的一些属性和方法如果外部传入的lib对象中已经存在flexible属性则使用传入的否则创建一个新的空对象赋值给lib.flexible。
var flexible = lib.flexible || (lib.flexible = {});
var designPixel = 750;//设计稿件尺寸
// 定义设计稿件的尺寸单位可能是像素这里设定为750用于后续根据页面实际宽度计算缩放比例等相关操作使页面在不同设备上能按比例适配显示。
var designPixel = 750;
// 如果页面中存在name为"viewport"的meta标签则根据其content属性内容来获取初始缩放比例并计算出对应的设备像素比dpr
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
// 通过正则表达式匹配获取content属性中initial-scale的值该值表示页面初始缩放比例。
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
// 将匹配到的初始缩放比例字符串转换为浮点数赋值给scale变量。
scale = parseFloat(match[1]);
// 根据缩放比例计算设备像素比设备像素比是物理像素与逻辑像素的比例关系例如scale为0.5则dpr为2表示物理像素是逻辑像素的2倍。
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
// 获取name为"flexible"的meta标签的content属性内容用于进一步解析获取相关缩放比例配置信息。
var content = flexibleEl.getAttribute('content');
if (content) {
// 通过正则表达式匹配尝试获取content属性中initial-dpr的值用于设置设备像素比dpr
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
// 通过正则表达式匹配尝试获取content属性中maximum-dpr的值同样用于设置设备像素比dpr可能会覆盖前面initialDpr的设置取决于具体匹配情况。
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
// 将匹配到的initial-dpr的值转换为浮点数赋值给dpr变量用于设置设备像素比。
dpr = parseFloat(initialDpr[1]);
// 根据设备像素比计算缩放比例并保留两位小数赋值给scale变量。
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
// 同理如果匹配到了maximum-dpr的值更新设备像素比dpr和缩放比例scale
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
// 如果经过前面的步骤都没有确定dpr和scale的值即都为0则根据设备类型是iPhone还是其他安卓设备等来设置默认的设备像素比dpr和缩放比例scale
if (!dpr &&!scale) {
// 通过正则表达式判断当前设备是否为安卓系统。
var isAndroid = win.navigator.appVersion.match(/android/gi);
// 通过正则表达式判断当前设备是否为iPhone。
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
// 获取当前设备的设备像素比,即物理像素与逻辑像素的实际比例关系。
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// 如果是iPhone设备根据设备像素比来设置合适的设备像素比dpr例如设备像素比大于等于3且之前未设置或设置的dpr大于等于3则设置dpr为3以此类推。
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2;
} else {
dpr = 1;
}
} else {
// 如果不是iPhone设备一般为安卓等其他设备默认设置设备像素比dpr为1。
dpr = 1;
}
// 根据设备像素比dpr计算缩放比例scale两者互为倒数关系。
scale = 1 / dpr;
}
// 将计算得到的设备像素比dpr设置为页面根元素<html>元素的data-dpr属性值方便在CSS等地方通过属性选择器等方式根据不同的设备像素比来应用不同的样式规则。
docEl.setAttribute('data-dpr', dpr);
// 如果页面中不存在name为"viewport"的meta标签则动态创建一个这样的meta标签并设置其content属性用于控制页面的缩放、用户缩放是否可用等显示相关设置然后将其添加到页面中合适的位置一般是<head>标签内)。
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
@ -71,46 +105,65 @@
}
}
function refreshRem(){
// 定义一个用于刷新页面根元素字体大小rem单位的函数根据页面宽度、设计稿件尺寸以及设备像素比等信息来动态计算并设置根元素的字体大小实现页面的自适应布局效果。
function refreshRem() {
// 获取页面根元素(<html>元素的可视宽度不包含滚动条等占据的宽度单位为像素后续会基于这个宽度来计算rem值。
var width = docEl.getBoundingClientRect().width;
if (width / dpr > designPixel) { //如果分辨率不是1那么获取的物理宽度应该乘以分辨率才是最终可用的width
// 如果设备像素比dpr不为1说明物理像素和逻辑像素不一致那么需要将获取到的物理宽度乘以设备像素比得到真正用于计算rem的可用宽度这样能保证在不同分辨率设备上布局的准确性。
if (width / dpr > designPixel) {
width = width * dpr;
}
var rem = width / (designPixel/100); //计算最终还原到设计图上的比例,从而设置到文档上
// 根据设计稿件尺寸designPixel和当前页面可用宽度width计算rem值这里是将页面宽度按照设计稿件尺寸等比例缩放例如设计稿件宽度是750px页面当前宽度是375px则rem值会相应变小实现页面元素按比例缩放显示。
var rem = width / (designPixel / 100);
// 将计算得到的rem值设置为页面根元素<html>元素的字体大小单位为px通过设置根元素字体大小为rem单位页面中使用rem单位的元素尺寸等会根据根元素字体大小动态变化从而实现自适应布局。
docEl.style.fontSize = rem + 'px';
// 将计算得到的rem值存储到flexible对象和全局的win对象即window对象方便其他地方可以访问和使用这个rem值例如用于将px单位转换为rem单位等操作。
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
// 监听页面的resize事件当页面大小发生改变时触发当触发该事件时先清除之前可能存在的定时器避免重复执行或频繁执行刷新rem的操作然后设置一个新的定时器延迟300毫秒后调用refreshRem函数来重新计算并更新页面根元素的字体大小实现页面在大小改变后的自适应布局调整。
win.addEventListener('resize', function () {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
// 监听页面的pageshow事件当页面显示时触发比如浏览器前进、后退等操作导致页面重新显示时如果页面是从缓存中加载显示通过e.persisted判断同样先清除之前的定时器再设置新定时器延迟300毫秒调用refreshRem函数来更新页面布局确保页面在各种显示场景下都能正确自适应。
win.addEventListener('pageshow', function (e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
// 如果页面已经加载完成document.readyState为'complete'则直接设置页面body元素的字体大小为16乘以设备像素比dpr的像素值这是一种基础的字体大小设置通常配合rem单位的自适应布局使用确保文字显示大小合适。
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 16 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
// 如果页面还未加载完成则监听DOMContentLoaded事件当页面DOM结构加载完成但可能资源如图片等还未完全加载时触发在该事件触发时设置页面body元素的字体大小同样为16乘以设备像素比dpr的像素值。
doc.addEventListener('DOMContentLoaded', function (e) {
doc.body.style.fontSize = 16 * dpr + 'px';
}, false);
}
// 首次加载页面时调用refreshRem函数初始化页面根元素的字体大小确保页面一开始就能以正确的自适应布局显示。
refreshRem();
// 将计算得到的设备像素比dpr存储到flexible对象和全局的win对象即window对象方便其他地方获取和使用设备像素比信息例如在处理高清图片显示等场景下可能会用到。
flexible.dpr = win.dpr = dpr;
// 将refreshRem函数存储到flexible对象上方便外部可以手动调用该函数来刷新页面的rem值实现手动触发页面自适应布局调整例如在某些动态改变页面布局结构的情况下可以使用。
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
// 定义一个方法用于将rem单位的数值转换为px单位的数值接收一个参数d可以是数字或者以rem结尾的字符串先将其转换为浮点数然后乘以当前的rem值通过this.rem获取this指向flexible对象如果传入的参数是字符串且以rem结尾则在返回结果后面加上'px'单位,方便在样式设置等场景下直接使用。
flexible.rem2px = function (d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
// 定义一个方法用于将px单位的数值转换为rem单位的数值接收一个参数d可以是数字或者以px结尾的字符串先将其转换为浮点数然后除以当前的rem值通过this.rem获取this指向flexible对象如果传入的参数是字符串且以px结尾则在返回结果后面加上'rem'单位方便在样式设置等场景下直接使用例如在根据设计稿尺寸计算元素的rem单位尺寸时会用到。
flexible.px2rem = function (d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
@ -119,114 +172,40 @@
}
})(window, window['lib'] || (window['lib'] = {}));
/*
* asideUi 侧栏
* 以下代码定义了一个名为asideUi的jQuery或Zepto插件取决于页面引入的是哪个库用于创建一个具有特定交互效果的侧边栏组件例如可以通过点击切换侧边栏的显示隐藏状态并且可以配置一些属性如大小是否显示遮罩位置以及动画过渡时间等
*/
;
(function($) {
$.fn.asideUi = function(options) {
var defaults = {
size: '100%',
hasmask: true,
position: 'left',
sidertime: 300
};
var val = $.extend(defaults, options);
var obj = function() {},
_self = this,
thisMask = $("<div class='ui-aside-mask'></div>"),
thisCss = {},
thisCss2 = {};
thisCss[val.position] = '-' + val.size;
this.css({
'top': (val.position == "bottom") ? "auto" : 0,
'bottom': 0
});
thisCss2[val.position] = 0;
_self.css(thisCss);
obj.toggle = function() {
if(_self.hasClass('ui-aside-open')) {
_self.removeClass('ui-aside-open');
_self.animate(thisCss, val.sidertime);
$('.ui-aside-mask').animate({
'opacity': 0
}, 100, function() {
$(this).remove();
});
} else {
_self.addClass('ui-aside-open');
_self.animate(thisCss2, val.sidertime);
if(val.hasmask) {
$('body').append(thisMask);
$(".ui-aside-mask").animate({
'opacity': 1
}, 100);
}
}
}
thisMask.tap(function() {
obj.toggle();
})
return obj;
};
})(window.Zepto || window.jQuery)
/*
* 返回顶部
*/
function goTop(acceleration, time) {
acceleration = acceleration || 0.1;
time = time || 16;
var x1 = 0;
var y1 = 0;
var x2 = 0;
var y2 = 0;
var x3 = 0;
var y3 = 0;
if(document.documentElement) {
x1 = document.documentElement.scrollLeft || 0;
y1 = document.documentElement.scrollTop || 0;
}
if(document.body) {
x2 = document.body.scrollLeft || 0;
y2 = document.body.scrollTop || 0;
}
var x3 = window.scrollX || 0;
var y3 = window.scrollY || 0;
// 滚动条到页面顶部的水平距离
var x = Math.max(x1, Math.max(x2, x3));
// 滚动条到页面顶部的垂直距离
var y = Math.max(y1, Math.max(y2, y3));
// 滚动距离 = 目前距离 / 速度, 因为距离原来越小, 速度是大于 1 的数, 所以滚动距离会越来越小
var speed = 1 + acceleration;
window.scrollTo(Math.floor(x / speed), Math.floor(y / speed));
// 如果距离不为零, 继续调用迭代本函数
if(x > 0 || y > 0) {
var invokeFunction = "goTop(" + acceleration + ", " + time + ")";
window.setTimeout(invokeFunction, time);
}
}
(function ($) {
// 通过$.fn向jQuery或Zepto的原型对象上添加一个名为asideUi的方法这样就可以在选择器选中的元素上调用该方法来创建侧边栏组件实例接收一个options参数用于传入配置选项。
$.fn.asideUi = function (options) {
// 定义默认的配置选项对象,包含侧边栏的大小(默认为'100%'可以是具体的宽度值或者百分比等、是否显示遮罩默认为true、显示位置默认为'left',还可以是'right'、'bottom'等以及侧边栏展开收起的动画过渡时间默认为300毫秒
var defaults = {
size: '100%',
hasmask: true,
position: 'left',
sidertime: 300
};
// 使用$.extend方法将传入的options参数与默认的配置选项defaults进行合并返回合并后的配置对象这样既可以使用默认配置又可以通过传入的参数覆盖部分默认配置。
var val = $.extend(defaults, options);
// 创建一个空的函数对象,后续会在这个对象上添加一些方法用于操作侧边栏的显示隐藏等功能,目前只是一个占位,方便代码组织和扩展。
var obj = function () { };
// 将当前调用asideUi方法的jQuery或Zepto对象即选中的元素集合赋值给_self变量方便在后续代码中引用例如设置选中元素的样式、添加移除类名等操作。
var _self = this;
// 创建一个用于作为侧边栏遮罩层的<div>元素,添加一个名为'ui-aside-mask'的类名后续可以通过CSS样式来设置其外观如透明度、背景色等以及交互效果如点击隐藏侧边栏等
var thisMask = $("<div class='ui-aside-mask'></div>");
// 创建一个空对象thisCss用于存储侧边栏的初始样式设置主要是控制侧边栏的显示位置和隐藏状态相关样式后续会根据配置的侧边栏位置等信息来设置具体的样式属性。
var thisCss = {};
// 创建另一个空对象thisCss2用于存储侧边栏展开后的样式设置同样是控制侧边栏的位置相关样式与thisCss相对应用于在侧边栏切换显示隐藏时应用不同的样式实现动画过渡效果。
var thisCss2 = {};
/*
* ui-progress进度条
*/
;
(function($) {
$.fn.progressUi = function(options) {
var defaults = {
skin: ''
};
var val = $.extend(defaults, options);
var attrs = {
max: this.attr('max') || 0,
value: this.attr("value") || 0
},
doms = $('<div class="ui-progressBox"></div>');
domsContent = $('<div class="progress-content ' + val.skin + '"></div>');
this.wrap(doms);
domsContent.animate({
'width': attrs.value / attrs.max * 100 + '%',
});
doms.prepend(domsContent);
};
})(window.Zepto || window.jQuery)
// 根据配置的侧边栏位置val.position设置侧边栏的初始位置样式例如如果位置是'left'则将其left属性设置为负的侧边栏大小val.size实现将侧边栏隐藏在屏幕左侧的效果通过CSS的left属性负值来隐藏元素其他位置同理。
thisCss[val.position] = '-' + val.size;
// 设置侧边栏的top和bottom属性根据侧边栏的显示位置val.position来决定top属性是否自动如果是'bottom'位置则top为'auto'其他位置top为0同时设置bottom属性为0用于控制侧边栏在垂直方向上的定位。
this.css({
'top': (val.position == "bottom")? "auto" : 0,
'bottom': 0
});}})
// 根据

@ -1,19 +1,33 @@
(function() {
// 立即执行函数,用于创建一个局部作用域,避免全局变量污染,在这个函数内部定义了一个基础的类继承机制以及一些与表单验证相关的功能代码。
(function () {
/**
* 所有类的基类提供继承机制
* 这里通过一些巧妙的代码逻辑实现了一个简单的类继承模式允许创建类并能方便地继承其他类的属性和方法同时处理了在子类中调用父类同名方法的情况通过 _super 机制
*/
var initializing = false, fnTest = /xyz/.test(function() {xyz;}) ? /\b_super\b/ : /.*/;
this.Class = function() {};
Class.extend = function(prop) {
// 用于检测当前JavaScript环境是否支持在函数内部通过名字访问函数自身的代码用于判断是否是严格模式等情况根据检测结果确定后续用于检测函数中是否包含 _super 关键字的正则表达式。
var initializing = false, fnTest = /xyz/.test(function () { xyz; })? /\b_super\b/ : /.*/;
// 创建一个名为 Class 的全局函数在严格模式下这里的this指向全局对象非严格模式下指向调用者的上下文对象一般在浏览器环境下是 window 对象),这个函数后续作为创建类的构造函数,初始时它只是一个空函数,后续会通过扩展功能来完善类的创建逻辑。
this.Class = function () { };
// 为 Class 函数添加一个 extend 方法用于实现类的继承功能通过传入一个包含属性和方法的对象prop来定义子类要扩展或重写的内容。
Class.extend = function (prop) {
// 获取当前类(调用 extend 方法的类)的原型对象,也就是父类的原型,后续用于在子类中访问父类的方法等操作,实现继承关系中的方法复用和重写逻辑。
var _super = this.prototype;
// 设置 initializing 为 true表示正在初始化一个新的类在继承过程中创建子类的原型对象阶段用于后续在构造函数中判断是否是初始化阶段避免一些不必要的操作比如重复调用初始化方法等
initializing = true;
// 通过使用 new 操作符调用当前类this 指向调用 extend 的类,也就是父类)的构造函数来创建一个新的对象,这个对象将作为子类的原型对象,它会继承父类原型上的属性和方法。
var prototype = new this();
// 完成子类原型对象的创建后,将 initializing 重新设置为 false表示初始化阶段结束。
initializing = false;
for ( var name in prop) {
// 遍历传入的属性对象prop中的每个属性一般是方法或新定义的属性进行相应的处理判断是普通属性赋值还是函数属性的特殊处理涉及到父类同名函数的调用情况
for (var name in prop) {
// 判断当前属性prop[name]是否是函数类型并且父类原型上是否存在同名的函数属性_super[name]),同时还要检测该函数的代码中是否包含 _super 关键字(通过 fnTest 正则表达式判断),如果满足这些条件,则进行特殊的函数包装处理,用于实现子类中调用父类同名函数的功能。
prototype[name] = typeof prop[name] == "function"
&& typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn) {
return function() {
&& typeof _super[name] == "function" && fnTest.test(prop[name])?
// 如果满足上述条件,返回一个新的函数,这个函数内部实现了先临时保存当前对象的 _super 属性(可能是之前保存的父类同名函数引用),然后将 _super 属性指向父类的同名函数,接着调用传入的函数(也就是子类重写的函数),在调用完成后恢复 _super 属性的原始值,最后返回函数执行的结果,这样就巧妙地实现了在子类函数中通过 this._super 调用父类同名函数的功能。
(function (name, fn) {
return function () {
var tmp = this._super;
this._super = _super[name];
@ -25,119 +39,141 @@
};
})(name, prop[name]) : prop[name];
}
// 创建一个新的函数(作为子类的构造函数),在这个构造函数中,如果当前不是处于初始化阶段(即不是在创建子类原型对象过程中),并且子类定义了 init 方法(一般用于初始化操作),则调用子类的 init 方法,并传入相应的参数,实现子类实例化时的初始化逻辑。
function Class() {
if (!initializing && this.init)
this.init.apply(this, arguments);
}
// 将前面创建并处理好的原型对象prototype赋值给新创建的子类构造函数Class的原型属性这样通过这个构造函数创建的实例就能继承原型对象上的属性和方法了。
Class.prototype = prototype;
// 修复子类构造函数的 constructor 属性,将其指向正确的子类构造函数本身,确保在使用 instanceof 等操作时能正确识别对象的构造函数类型。
Class.prototype.constructor = Class;
// 将 extend 方法也添加到子类的构造函数上,使得子类也能继续通过调用 extend 方法来实现进一步的继承,形成继承链,这里通过 arguments.callee 引用当前的 extend 函数本身来实现这个功能不过在严格模式下arguments.callee 是不允许使用的,代码可能需要调整)。
Class.extend = arguments.callee;
// 返回创建好的子类构造函数,外部可以通过调用这个构造函数来创建子类的实例对象,完成类的继承和实例化操作。
return Class;
};
})();
var validate = Class
.extend({
defaultCfg:{
rules:{},
submitFun:function(){},
errorLabel:'<label style="color:red"></label>',
errorFun:function(){}
},
init:function(cfg){
this.cfg = $.extend({},this.defaultCfg,cfg);
this.flag=0;
this.toAction(this);
if(this.flag==0){
for(var i in this.cfg.rules){
$("#"+i).unbind("keyup");
}
this.cfg.submitFun();
}
},
toAction:function(that){
for(var i in that.cfg.rules){
this.toVal("#"+i,that.cfg.rules[i]);
}
},
toVal:function(ele,constant){
validateConstant[constant].test($(ele).val())?
this.toRemoveError(ele):this.toShowError(ele,errorMsg[constant]);
},
toRemoveError:function(ele){
var that = this;
if($(ele).closest(".form-group").attr("not-allow")){
$(ele).removeAttr("style").closest(".form-group").removeAttr("style")
.removeAttr("not-allow");
$(ele).next().remove();
$(ele).keyup(function(){
ele = ele.replace("#","");
that.toVal("#"+ele,that.cfg.rules[ele]);
});
}
},
toShowError:function(ele,message){
var error = $(this.cfg.errorLabel).text(message);
if(!$(ele).closest(".form-group").attr("not-allow")){
$(ele).after(error);
$(ele).css("border","1px solid red").closest(".form-group")
.css("color","red").attr("not-allow","true");
$(ele).keyup(function(){
ele = ele.replace("#","");
that.toVal("#"+ele,that.cfg.rules[ele]);
});
// 使用前面定义的 Class 类及继承机制创建一个名为 validate 的类,它继承自 Class主要用于实现表单验证相关的功能比如验证表单字段是否符合特定的规则、显示错误提示等。
var validate = Class
.extend({
// 默认配置对象包含了验证相关的各种默认设置如验证规则rules、提交表单时执行的函数submitFun、用于显示错误信息的HTML标签模板errorLabel以及出现错误时执行的函数errorFun等属性。
defaultCfg: {
rules: {},
submitFun: function () { },
errorLabel: '<label style="color:red"></label>',
errorFun: function () { }
},
// 初始化方法,在创建 validate 类的实例时会被调用(如果不是处于类继承的初始化阶段,也就是 new 操作实例化时会执行),用于初始化验证相关的配置信息以及绑定一些事件处理等操作。
init: function (cfg) {
// 使用 jQuery 的 extend 方法将传入的配置对象cfg与默认配置对象defaultCfg进行合并得到最终的配置对象并赋值给 this.cfg这样既可以使用默认配置又能通过传入的参数覆盖部分默认配置。
this.cfg = $.extend({}, this.defaultCfg, cfg);
// 初始化一个标志变量flag为0用于记录表单验证过程中是否出现错误等情况后续根据这个标志来决定是否执行提交表单等操作。
this.flag = 0;
// 调用 toAction 方法并传入当前实例对象this开始进行表单验证相关的操作比如遍历验证规则并对相应的表单字段进行验证。
this.toAction(this);
// 如果验证过程中没有出现错误flag 仍然为0则解除表单字段的 keyup 事件绑定可能是之前绑定的用于实时验证的事件这里在全部验证通过后解除避免重复验证等不必要的操作然后执行提交表单的函数submitFun提交表单数据等操作具体由这个函数的实现决定
if (this.flag == 0) {
for (var i in this.cfg.rules) {
$("#" + i).unbind("keyup");
}
this.flag++;
var that = this;
this.cfg.submitFun();
}
},
// 用于执行表单验证的主要方法接收一个表示当前验证实例的对象that在这个方法内部会遍历配置的验证规则并针对每个规则调用 toVal 方法对相应的表单字段进行验证操作。
toAction: function (that) {
for (var i in that.cfg.rules) {
this.toVal("#" + i, that.cfg.rules[i]);
}
},
// 具体验证单个表单字段的方法接收一个表单字段的选择器ele一般是类似 "#inputId" 的形式表示通过ID选择元素以及对应的验证规则常量constant用于确定使用哪种验证规则来验证该字段根据验证结果调用相应的方法来显示或移除错误提示信息。
toVal: function (ele, constant) {
// 调用 validateConstant 对象中对应的验证规则函数(通过 constant 作为键来查找),传入表单字段的值(通过 jQuery 获取元素的值)进行验证,如果验证通过(返回 true则调用 toRemoveError 方法移除该字段的错误提示信息,否则调用 toShowError 方法显示相应的错误提示信息(传入错误提示消息,通过 errorMsg 对象根据验证规则常量获取)。
validateConstant[constant].test($(ele).val())?
this.toRemoveError(ele) : this.toShowError(ele, errorMsg[constant]);
},
// 用于移除表单字段错误提示信息的方法接收一个表单字段的选择器ele首先获取当前验证实例对象通过 this 赋值给 that 变量),然后判断该字段所在的表单组元素(通过 closest 方法查找父级的.form-group 元素)是否有 "not-allow" 属性,如果有则表示之前添加过错误提示等限制属性,现在需要移除这些属性,恢复表单字段和表单组的原始样式(通过 removeAttr 方法移除相关样式属性),同时移除该字段后面的错误提示标签(通过 next 方法找到并 remove 方法移除),最后重新绑定 keyup 事件,当用户再次输入内容时重新进行验证(调用 toVal 方法)。
toRemoveError: function (ele) {
var that = this;
if ($(ele).closest(".form-group").attr("not-allow")) {
$(ele).removeAttr("style").closest(".form-group").removeAttr("style")
.removeAttr("not-allow");
$(ele).next().remove();
$(ele).keyup(function () {
ele = ele.replace("#", "");
that.toVal("#" + ele, that.cfg.rules[ele]);
});
}
},
// 用于显示表单字段错误提示信息的方法接收一个表单字段的选择器ele以及对应的错误提示消息message首先根据配置的错误标签模板cfg.errorLabel创建一个包含错误消息的 <label> 标签元素(通过 jQuery 的 text 方法设置文本内容),然后判断该字段所在的表单组元素是否已经有 "not-allow" 属性(如果没有则表示之前没有添加过错误提示,需要添加),如果没有则将错误提示标签添加到表单字段后面(通过 after 方法),同时设置表单字段和表单组的样式为红色边框、红色文字等错误提示样式(通过 css 方法设置样式属性,并通过 attr 方法添加 "not-allow" 属性表示已经添加了错误提示),最后重新绑定 keyup 事件当用户再次输入内容时重新进行验证并且每次显示错误提示时会将标志变量flag加1表示出现了错误情况后续可以根据这个标志来判断是否能提交表单等操作。
toShowError: function (ele, message) {
var error = $(this.cfg.errorLabel).text(message);
if (!$(ele).closest(".form-group").attr("not-allow")) {
$(ele).after(error);
$(ele).css("border", "1px solid red").closest(".form-group")
.css("color", "red").attr("not-allow", "true");
$(ele).keyup(function () {
ele = ele.replace("#", "");
that.toVal("#" + ele, that.cfg.rules[ele]);
});
}
})
this.flag++;
var that = this;
}
})
// 定义一个名为 validateConstant 的对象,用于存储各种表单字段验证的正则表达式或验证函数,通过不同的键(验证规则常量,如 "notEmpty"、"password" 等)来对应不同的验证逻辑,用于验证表单输入是否符合相应的格式要求。
var validateConstant = {
"notEmpty" : /^.+$/,// 合法字符
"password" : /^[0-9A-Za-z]{1,18}$/,// 密码
"rightfulString" : /^[A-Za-z0-9_-]+$/,// 合法字符
"number" : /^\d+$/,// 数字
"endlish" : /^[A-Za-z]+$/,// 纯英文
"numberEnglish" : /^[A-Za-z0-9]+$/,// 英文和数字
"float" : /^[+]?\d+(\.\d+)?$/,// 浮点型
"money" : /(^[1-9]\d{0,9}(\.\d{1,2})?$)/,
"chinese" : "/^[\u4e00-\u9fa5]+$/",// 纯中文
"mobile" : /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})|(14[0-9]{1}))+\d{8})$/,// 手机号
"tel" : /^(\d{3,4}-?)?\d{7,9}$/g,// 电话
"qq" : /^[1-9]\d{4,12}$/,// qq
"zipCode" : /^[0-9]{6}$/,// 邮政编码
"email" : /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,// 邮箱
"positive":/^[1-9][0-9]+$/,//大于0的数字
"checkIdCard" : function(idcard) {// 校验身份证
var area={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",
37:"山东",41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",
63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"}
var idcard,Y,JYM;
var S,M;
"notEmpty": /^.+$/,// 合法字符,该正则表达式表示只要输入有内容(至少包含一个字符)就算符合要求,用于验证字段不能为空。
"password": /^[0-9A-Za-z]{1,18}$/,// 密码验证密码格式要求由数字、大小写字母组成长度在1到18位之间。
"rightfulString": /^[A-Za-z0-9_-]+$/,// 合法字符,验证输入是否是由大小写字母、数字、下划线和短横线组成的合法字符串。
"number": /^\d+$/,// 数字,验证输入是否只包含数字。
"endlish": /^[A-Za-z]+$/,// 纯英文,验证输入是否只包含英文字母。
"numberEnglish": /^[A-Za-z0-9]+$/,// 英文和数字,验证输入是否只包含英文字母和数字。
"float": /^[+]?\d+(\.\d+)?$/,// 浮点型,验证输入是否是合法的浮点数格式,可以包含正负号、整数部分和可选的小数部分。
"money": /(^[1-9]\d{0,9}(\.\d{1,2})?$)/,
"chinese": "/^[\u4e00-\u9fa5]+$/",// 纯中文验证输入是否只包含中文字符通过Unicode编码范围来判断不过这里的正则表达式写法有点问题外面的双引号应该去掉正确的是 /^[\u4e00-\u9fa5]+$/.
"mobile": /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})|(14[0-9]{1}))+\d{8})$/,// 手机号,验证输入是否是符合常见手机号码格式的字符串。
"tel": /^(\d{3,4}-?)?\d{7,9}$/g,// 电话,验证输入是否是符合常见电话号码格式(可以包含区号,用 - 连接,也可以没有区号)的字符串,注意这里的 /g 表示全局匹配标志,在验证时会匹配所有符合的内容(不过在这个场景下一般只验证一个电话号码,是否需要全局匹配可根据实际情况调整)。
"qq": /^[1-9]\d{4,12}$/,// qq验证输入是否是符合QQ号码格式数字开头长度在5到13位之间的数字字符串。
"zipCode": /^[0-9]{6}$/,// 邮政编码验证输入是否是6位数字的邮政编码格式。
"email": /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,// 邮箱,验证输入是否是符合常见邮箱格式(包含用户名、@符号、域名等部分,这里只是简单的格式验证,不是非常严格)的字符串。
"positive": /^[1-9][0-9]+$/,//大于0的数字验证输入是否是大于0的整数数字开头且不是0后面可以跟其他数字
"checkIdCard": function (idcard) {// 校验身份证定义一个函数用于验证身份证号码的合法性根据身份证号码的位数15位或18位以及对应的出生日期、地区编码、校验位等规则来进行详细的验证返回 true 表示验证通过false 表示验证不通过。
var area = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西",
37: "山东", 41: "河南", 42: "湖北", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏", 61: "陕西", 62: "甘肃",
63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外" }
var idcard, Y, JYM;
var S, M;
var idcard_array = new Array();
idcard_array = idcard.split("");
//地区检验
if(area[parseInt(idcard.substr(0,2))]==null){
//地区检验,通过截取身份证号码的前两位,在 area 对象中查找对应的地区名称,如果查找不到则表示地区编码不合法,返回 false。
if (area[parseInt(idcard.substr(0, 2))] == null) {
return false;
}
//身份号码位数及格式检验
switch(idcard.length){
case 15:
if ( (parseInt(idcard.substr(6,2))+1900) % 4 == 0 || ((parseInt(idcard.substr(6,2))+1900) % 100 == 0 && (parseInt(idcard.substr(6,2))+1900) % 4 == 0 )){
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/;
//测试出生日期的合法性
} else {
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/;
//测试出生日期的合法性
}
if(ereg.test(idcard)){
return true;
}else{
return false;
}
break;
//身份号码位数及格式检验根据身份证号码的长度15位或18位分别进行不同的格式和合法性验证主要涉及出生日期的合法性检查以及18位身份证的校验位计算等操作。
switch (idcard.length) {case 15:
if ( (parseInt(idcard.substr(6,2))+1900) % 4 == 0 || ((parseInt(idcard.substr(6,2))+1900) % 100 == 0 && (parseInt(idcard.substr(6,2))+1900) % 4 == 0 )){
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/;
//测试出生日期的合法性
} else {
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/;
//测试出生日期的合法性
}
if(ereg.test(idcard)){
return true;
}else{
return false;
}
break;
case 18:
//18位身份号码检测
//出生日期的合法性检查
@ -153,10 +189,10 @@ var validateConstant = {
if(ereg.test(idcard)){//测试出生日期的合法性
//计算校验位
S = (parseInt(idcard_array[0]) + parseInt(idcard_array[10])) * 7 + (parseInt(idcard_array[1]) + parseInt(idcard_array[11])) * 9
+ (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 + (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5
+ (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 + (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4
+ (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 + parseInt(idcard_array[7]) * 1 + parseInt(idcard_array[8]) * 6
+ parseInt(idcard_array[9]) * 3 ;
+ (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 + (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5
+ (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 + (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4
+ (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 + parseInt(idcard_array[7]) * 1 + parseInt(idcard_array[8]) * 6
+ parseInt(idcard_array[9]) * 3 ;
Y = S % 11;
M = "F";
JYM = "10X98765432";

Loading…
Cancel
Save