From bf9f1391f588c2b6a07b928b8ac8b17f98b6763e Mon Sep 17 00:00:00 2001 From: wang ziting <3165305859@qq.com> Date: Sat, 14 Dec 2024 00:02:26 +0800 Subject: [PATCH] wang --- src/main/webapp/WEB-INF/jsp/welcome.jsp | 37 ++- src/main/webapp/js/miniMobile.js | 237 +++++++++---------- src/main/webapp/js/validate.js | 302 +++++++++++++----------- 3 files changed, 307 insertions(+), 269 deletions(-) diff --git a/src/main/webapp/WEB-INF/jsp/welcome.jsp b/src/main/webapp/WEB-INF/jsp/welcome.jsp index fcd4f78..082883d 100644 --- a/src/main/webapp/WEB-INF/jsp/welcome.jsp +++ b/src/main/webapp/WEB-INF/jsp/welcome.jsp @@ -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" %> 欢迎页面 + + +
系统时间
+
+
控制面板
+
+
+
+
CPU利用率
+ CPU
利用率
+
系统出入流量
@@ -43,6 +55,7 @@
+
模块
@@ -52,6 +65,7 @@
+
模块
@@ -65,16 +79,25 @@
- + \ No newline at end of file diff --git a/src/main/webapp/js/miniMobile.js b/src/main/webapp/js/miniMobile.js index e7ed45e..92a7c6a 100644 --- a/src/main/webapp/js/miniMobile.js +++ b/src/main/webapp/js/miniMobile.js @@ -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; + // 获取页面根元素(元素),很多页面样式和布局相关的设置会基于这个元素来操作,例如设置页面字体大小等属性。 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;//设计稿件尺寸 - - if (metaEl) { - console.warn('将根据已有的meta标签来设置缩放比例'); + // 定义设计稿件的尺寸(单位可能是像素),这里设定为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 = parseFloat((1 / dpr).toFixed(2)); + // 根据设备像素比计算缩放比例,并保留两位小数,赋值给scale变量。 + scale = parseFloat((1 / dpr).toFixed(2)); } if (maximumDpr) { + // 同理,如果匹配到了maximum-dpr的值,更新设备像素比(dpr)和缩放比例(scale)。 dpr = parseFloat(maximumDpr[1]); - scale = parseFloat((1 / dpr).toFixed(2)); + 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) { - if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { + 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 { + } else { + // 如果不是iPhone设备(一般为安卓等其他设备),默认设置设备像素比(dpr)为1。 dpr = 1; } + // 根据设备像素比(dpr)计算缩放比例(scale),两者互为倒数关系。 scale = 1 / dpr; } + // 将计算得到的设备像素比(dpr)设置为页面根元素(元素)的data-dpr属性值,方便在CSS等地方通过属性选择器等方式根据不同的设备像素比来应用不同的样式规则。 docEl.setAttribute('data-dpr', dpr); + + // 如果页面中不存在name为"viewport"的meta标签,则动态创建一个这样的meta标签,并设置其content属性,用于控制页面的缩放、用户缩放是否可用等显示相关设置,然后将其添加到页面中合适的位置(一般是标签内)。 if (!metaEl) { metaEl = doc.createElement('meta'); metaEl.setAttribute('name', 'viewport'); @@ -71,46 +105,65 @@ } } - function refreshRem(){ + // 定义一个用于刷新页面根元素字体大小(rem单位)的函数,根据页面宽度、设计稿件尺寸以及设备像素比等信息来动态计算并设置根元素的字体大小,实现页面的自适应布局效果。 + function refreshRem() { + // 获取页面根元素(元素)的可视宽度(不包含滚动条等占据的宽度),单位为像素,后续会基于这个宽度来计算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值设置为页面根元素(元素)的字体大小(单位为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 = $("
"), - 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; + // 创建一个用于作为侧边栏遮罩层的
元素,添加一个名为'ui-aside-mask'的类名,后续可以通过CSS样式来设置其外观(如透明度、背景色等)以及交互效果(如点击隐藏侧边栏等)。 + var thisMask = $("
"); + // 创建一个空对象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 = $('
'); - domsContent = $('
'); - this.wrap(doms); - domsContent.animate({ - 'width': attrs.value / attrs.max * 100 + '%', - }); - doms.prepend(domsContent); - }; -})(window.Zepto || window.jQuery) \ No newline at end of file + // 根据配置的侧边栏位置(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 + });}}) +// 根据 \ No newline at end of file diff --git a/src/main/webapp/js/validate.js b/src/main/webapp/js/validate.js index 5c5f836..5b791bb 100644 --- a/src/main/webapp/js/validate.js +++ b/src/main/webapp/js/validate.js @@ -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) { - prototype[name] = typeof prop[name] == "function" - && typeof _super[name] == "function" && fnTest.test(prop[name]) ? - (function(name, fn) { - return function() { + + // 遍历传入的属性对象(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])? + // 如果满足上述条件,返回一个新的函数,这个函数内部实现了先临时保存当前对象的 _super 属性(可能是之前保存的父类同名函数引用),然后将 _super 属性指向父类的同名函数,接着调用传入的函数(也就是子类重写的函数),在调用完成后恢复 _super 属性的原始值,最后返回函数执行的结果,这样就巧妙地实现了在子类函数中通过 this._super 调用父类同名函数的功能。 + (function (name, fn) { + return function () { var tmp = this._super; this._super = _super[name]; @@ -25,155 +39,177 @@ }; })(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; }; })(); + +// 使用前面定义的 Class 类及继承机制创建一个名为 validate 的类,它继承自 Class,主要用于实现表单验证相关的功能,比如验证表单字段是否符合特定的规则、显示错误提示等。 var validate = Class - .extend({ - defaultCfg:{ - rules:{}, - submitFun:function(){}, - errorLabel:'', - 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(); + .extend({ + // 默认配置对象,包含了验证相关的各种默认设置,如验证规则(rules)、提交表单时执行的函数(submitFun)、用于显示错误信息的HTML标签模板(errorLabel)以及出现错误时执行的函数(errorFun)等属性。 + defaultCfg: { + rules: {}, + submitFun: function () { }, + errorLabel: '', + 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"); } - }, - 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]); + 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]); - }, - 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]); - }); - } - this.flag++; - var that = this; - + }, + // 用于移除表单字段错误提示信息的方法,接收一个表单字段的选择器(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)创建一个包含错误消息的