话不多说,直接上源代码
一、tool.js
封装一些共用方法,以及相关的浏览器兼容细节,供Base.js调用
//浏览器检测,一旦加载即执行 (function() { window.sys = {}; var ua = navigator.userAgent.toLowerCase(); var s; (s = ua.match(/msie ([\d.]+)/)) ? sys.ie = s[]: (s = ua.match(/firefox\/([\d.]+)/)) ? sys.firefox = s[] : (s = ua.match(/chrome\/([\d.]+)/)) ? sys.chrome = s[] : (s = ua.match(/opera\/.*version\/([\d.]+)/)) ? sys.opera = s[] : (s = ua.match(/version\/([\d.]+).*safari/)) ? sys.safari = s[] : ; ]; })(); //取代window.onLoad的页面初始化加载函数 function addDomLoaded(fn) { var timer; var isReady = false; function doReady() { if (timer) { clearInterval(timer); } //isReady限制该方法仅执行一次 if (isReady) return; isReady = true; fn(); } if (document.addEventListener) { //如果支持W3C,包括IE9+,chrome等 addEvent(document, 'DOMContentLoaded', function() { fn(); removeEvent(document, 'DOMContentLoaded', arguments.callee); }); } ) || (sys.firefox && sys.firefox < ) || (sys.webkit && sys.webkit < )) { //下面两种方法都可以,不过这些低版本的浏览器市面上基本没有了,所以基本用不到 /*timer = setInterval(function () { if (/loaded|complete/.test(document.readyState)) { //loaded是部分加载,有可能只是DOM加载完毕,complete是完全加载,类似于onload doReady(); } }, 1);*/ timer = setInterval(function() { if (document && document.getElementById && document.getElementsByTagName && document.body) { doReady(); } }, ); } ) { //对于ie来说,检测readyState的方法,在页面具有iframe的时候失效,通过检测元素的scroll事件来实现 timer = setInterval(function() { try { document.documentElement.doScroll('left'); doReady(); } catch (e) {}; }, ); } } function hasClass(elem, className) { return (new RegExp('(\\s+|^)' + className + '(\\s+|$)')).test(elem.className); } //获取元素的样式,可以是内联样式,也可以是写在外部样式表中的样式 function getStyle(elem, attr) { if (typeof window.getComputedStyle != 'undefined') { //W3C return window.getComputedStyle(elem, null) [attr]; } else if (typeof elem.currentStyle != 'undefined') { //IE return elem.currentStyle[attr]; } } //跨浏览器添加link规则 function insertRule(sheet, selectorText, cssText, position) { if (typeof sheet.insertRule != 'undefined') { //W3C sheet.insertRule(selectorText + '{' + cssText + '}', position); } else if (typeof sheet.addRule != 'undefined') { //IE sheet.addRule(selectorText, cssText, position); } } //跨浏览器移除link规则 function deleteRule(sheet, index) { if (typeof sheet.deleteRule != 'undefined') { //W3C sheet.deleteRule(index); } else if (typeof sheet.removeRule != 'undefined') { //IE sheet.removeRule(index); } } //跨浏览器获取浏览器视图的宽度和高度 function getViewSize() { var clientWidth = window.innerWidth; var clientHeight = window.innerHeight; if (typeof clientWidth != 'number') { if (document.compatMode == 'CSS1Compat') { clientWidth = document.documentElement.clientWidth; clientHeight = document.documentElement.clientHeight; } else { //IE6混杂模式下 clientWidth = document.body.clientWidth; clientHeight = document.body.clientHeight; } } return { width: clientWidth, height: clientHeight } } //跨浏览器事件绑定,原事件绑定程序 //DOM0级事件绑定(onclick等),事件处理程序是在元素作用域,this引用的是当前元素;只能绑定一个处理函数 //DOM2级addEventListener(),元素作用域,可绑定多个,顺序执行 //DOM2级IE attacheEvent(),全局window作用域,其中的event也属于window的属性,可绑定多个,逆序执行(貌似这个函数有内存泄漏的问题?) //综上,跨浏览器事件绑定程序,需要解决的问题包括 //1,支持同一元素的同一事件可以绑定多个处理函数 //2,如果同一元素的同一事件多次注册同一个处理函数,则仅生效一次 //3,函数体内的this指定的是当前正在处理事件的节点 //4,监听函数的执行顺序应当是按照注册绑定的顺序执行 //5,在函数体内,不在使用event=event||window.event,来标准化event对象 function addEvent(elem, type, listener) { //type = type.replace(/^on/i, '').toLowerCase(); //将处理函数的作用域限制在元素内部,并将event对象传递过去 if (elem.addEventListener) { elem.addEventListener(type, listener, false); } else { //为了避开attachEvent的内存泄漏问题,采用传统的事件绑定 if (!elem.events) { //创建事件类型的哈希表 elem.events = {}; } if (!elem.events[type]) { elem.events[type] = []; } //判断同一个函数的事件是否已经被注册 if (!addEvent.contain(listener, elem.events[type])) { elem.events[type].push(listener); } //真实绑定 elem['on' + type] = addEvent.exec; } } //判断事件处理函数是否已经被注册 addEvent.contain = function(listener, listenerArr) { for (var i in listenerArr) { if (listenerArr[i] == listener) { return true; } } return false; }; //IE下最终绑定的事件处理函数 addEvent.exec = function(event) { //这里的this就是绑定事件的elem了 var e = event || addEvent.fixEvent(window.event); var fns = this.events[e.type]; ; i < fns.length; i++) { fns[i].call(this, e); } }; addEvent.fixEvent = function(event) { event.target = event.srcElement; event.preventDefault = addEvent.fixEvent.preventDefault; event.stopPropagation = addEvent.fixEvent.stopPropagation; return event; }; addEvent.fixEvent.preventDefault = function() { this.returnValue = false; }; addEvent.fixEvent.stopPropagation = function() { this.cancelBubble = true; }; //跨浏览器删除事件 function removeEvent(elem, type, listener) { if (elem.removeEventListener) { elem.removeEventListener(type, listener, false); } else { var fns = elem.events[type]; ; i < fns.length; i++) { if (fns[i] == listener) { fns.splice(i, ); } } } } //获得元素在页面上的水平偏移量 function getElementLeft(elem) { var pNode = elem.offsetParent; var left = elem.offsetLeft; while (pNode) { left += pNode.offsetLeft; pNode = pNode.offsetParent; } return left; } //获得元素在页面上的竖直偏移量 function getElementTop(elem) { var pNode = elem.offsetParent; var top = elem.offsetTop; while (pNode) { top += pNode.offsetTop; pNode = pNode.offsetParent; } return top; } function getScroll(){ return{ top:document.documentElement.scrollTop||document.body.scrollTop, left:document.documentElement.scrollLeft||document.body.scrollLeft } } //去除字符串开始和结束的空格 function trim(str) { str = str.replace(/(^\s*)|(\s*$)/g, ''); return str; } //和dom查找相关 var query = function(selectorText, pNode) { var regExps = { id: /^#([\w_\-]+)/, className: /^\.([\w_\-]+)/, tag: /^\w+$/, attribute: /(\w+)?\[([^=\]]+)(?:=(["'])?([^\]"']+)\3?)?\]/ }; var queryActions = { id: function(id, pNode) { var result = []; result.push(document.getElementById(id)); return result; }, tag: function(tag, pNode) { var curPNode = null; var result = []; if (pNode != undefined) { curPNode = pNode; } else { curPNode = document; } return curPNode.getElementsByTagName(tag); }, className: function(className, parentNode) { var pNode = null; if (parentNode != undefined) { pNode = parentNode; } else { pNode = document; } var result = []; var elems = pNode.getElementsByTagName('*'); ; i < elems.length; i++) { if (hasClass(elems[i], className)) { result.push(elems[i]); } } return result; }, attribute: function(tag, key, value, pNode) { var curPNode = null; if (pNode) { curPNode = pNode; } else { curPNode = document; } var elems = curPNode.getElementsByTagName(tag || '*'); var result = []; ; i >= ; i--) { var curElem = elems[i]; if (curElem.getAttribute(key)) { if (!value) { result.push(curElem); } else { if (curElem.getAttribute(key).toLowerCase() === value.toLowerCase()) { result.push(curElem); } } } } return result; } }; var fnName, regResult; var params = []; if (regResult = selectorText.match(regExps['id'])) { fnName = 'id'; ]); } if (regResult = selectorText.match(regExps['tag'])) { fnName = 'tag', ]); } if (regResult = selectorText.match(regExps['className'])) { fnName = 'className', ]); } if (regResult = selectorText.match(regExps['attribute'])) { fnName = 'attribute', ], regResult[], regResult[]); } if (pNode) { params.push(pNode); } var elemResult = queryActions[fnName].apply(null, params); return elemResult; };
tool.js
二、Base.js 调用tool.js,效果类似于一个轻量级的jquery
//前台调用 function $(args) { return new Base(args); } function Base(args) { this.elements = []; if (typeof args === 'string') { //说明是css选择符 args = trim(args); var selectors = []; ) { selectors = args.split(/\s+/); } else { //说明选择符不具有层次关系,为了方便处理,依旧将其转换为数组 selectors.push(args); } var pNodes = []; var childNodes = []; ; i < selectors.length; i++) { var curSelector = selectors[i]; ) { pNodes.push(document); } childNodes = []; ; j < pNodes.length; j++) { var temps = query(curSelector, pNodes[j]); ; k < temps.length; k++) { childNodes.push(temps[k]); } } pNodes = childNodes; } this.elements = childNodes; } else if (typeof args === 'object') { //说明传入的是dom对象,或者this if (args != undefined) { ] = args; } } else if (typeof args === 'function') { this.ready(args); } } //页面加载函数,类似于jquery的$(document).ready Base.prototype.ready = function(fn) { addDomLoaded(fn); }; //获取某一个节点,返回的是DOM节点对象 Base.prototype.getElem = function(num) { return this.elements[num]; }; //返回符合条件的首个DOM节点对象 Base.prototype.first = function() { ]; }; //返回符合条件的最后一个DOM节点对象 Base.prototype.last = function() { ]; }; //返回当前节点的上一个同级节点,返回的是Base对象 Base.prototype.next = function() { ; i < this.elements.length; i++) { this.elements[i] = this.elements[i].nextSibling; if (this.elements[i] == null) { throw new Error('找不到下一个同级节点!'); } ) { this.next(); } } return this; }; Base.prototype.prev = function() { ; i < this.elements.length; i++) { this.elements[i] = this.elements[i].previousSibling; if (this.elements[i] == null) { throw new Error('找不到上一个同级节点!'); } ) { this.prev(); } } return this; }; //获取某一个节点,返回的是Base对象 Base.prototype.eq = function(num) { var element = this.elements[num]; this.elements = []; ] = element; return this; }; Base.prototype.css = function(attr, value) { , len = this.elements.length; i < len; i++) { ) { return getStyle(this.elements[i], attr); } this.elements[i].style[attr] = value; } return this; }; //获取长度 Base.prototype.len = function() { return this.elements.length; }; Base.prototype.addClass = function(className) { , len = this.elements.length; i < len; i++) { if (!hasClass(this.elements[i], className)) { this.elements[i].className += ' ' + className; } } return this; }; Base.prototype.removeClass = function(className) { , len = this.elements.length; i < len; i++) { if (hasClass(this.elements[i], className)) { this.elements[i].className = this.elements[i].className.replace(new RegExp('(\\s+|^)' + className + '(\\s+|$)'), ' '); } } return this; }; //获取或者设置innerHTML //潜在问题,如果是赋值的话,所有都赋值,如果是取值的话,貌似只是返回首个值 Base.prototype.html = function(htmlText) { , len = this.elements.length; i < len; i++) { ) { return this.elements[i].innerHTML; } else { this.elements[i].innerHTML = htmlText; } } return this; }; //添加link或者style的css规则,不常用 Base.prototype.addRule = function(num, selectorText, cssText, position) { var sheet = document.styleSheets[num]; insertRule(sheet, selectorText, cssText, position); return this; }; //删除link或者style的css规则,不常用 Base.prototype.removeRule = function(num, index) { var sheet = document.styleSheets[num]; deleteRule(sheet, index); return this; }; //设置元素显示 Base.prototype.show = function() { ; i >= ; i--) { this.elements[i].style.display = 'block'; }; return this; }; //设置元素隐藏 Base.prototype.hide = function() { ; i >= ; i--) { this.elements[i].style.display = 'none'; }; return this; }; //检查元素是否处于隐藏状态 Base.prototype.isVisible = function() { var flag=true; ; i >= ; i--) { var curElem=this.elements[i]; if(curElem.style.display=='none'||curElem.style.visibility=='hidden'){ flag=false; } }; return flag; }; //设置已知宽度和高度的物体,在整个视图窗口居中 //前提:当前元素position:absolute,父元素是body对象 Base.prototype.screenCenter = function(width, height) { var viewSize = getViewSize(); var left, top; , len = this.elements.length; i < len; i++) { var curElem = this.elements[i]; ) { left = (viewSize.width - width) / ; top = (viewSize.height - height) / ; } else { //没有传入元素的宽和高,就自己获取 left = (viewSize.width - curElem.offsetWidth) / ; top = (viewSize.height - curElem.offsetHeight) / ; } this.elements[i].style.top = top + 'px'; this.elements[i].style.left = left + 'px'; }; return this; }; //浏览器大小调整事件,可以用任意$()对象调用 Base.prototype.resize = function(fn) { addEvent(window, 'resize', fn); //window.onresize = fn; return this; }; //设置hover事件 Base.prototype.hover = function(over, out) { , len = this.elements.length; i < len; i++) { //this.elements[i].onmouseover = over; addEvent(this.elements[i], 'mouseover', over); //this.elements[i].onmouseout = out; addEvent(this.elements[i], 'mouseout', out); }; return this; }; //toggle:点击切换方法,可以传递多个函数作为参数,执行完一轮则从头开始执行 Base.prototype.toggle = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; var args = arguments; //最终方法,这样的话每一个元素都具有单独的一个count计数器,并且不会产生诸如curElem.count这样的属性污染 (function(curElem, args) { ; addEvent(curElem, 'click', function() { args[count++ % args.length].call(this); }); })(curElem, args); //方法二:可以解决方法一的问题,但是依旧不行,因为如果选择器选择的是多个元素的话,公用一个count对象,可能会出现问题 // addEvent(curElem, 'click', function() { // //注意,在函数内定义函数,这是一个闭包 // //闭包可以访问外部函数的变量,但是保存的永远是外部函数变量的最后取值 // //因此这里count的取值才能始终累加 // //不是增添多次click事件,并且每次click事件的执行函数事实上都不相同 // args[count++ % args.length].call(this); // }); //方法一:这种方式是不行的,执行的永远是第一个函数 //addEvent(curElem,'click',args[count++%args.length]); } return this; }; function tog(curElem, args) { ; addEvent(curElem, 'click', function() { args[count++ % args.length].call(this); }); } //添加点击事件 Base.prototype.click = function(fn) { ; i < this.elements.length; i++) { addEvent(this.elements[i], 'click', fn); } return this; }; //插件入口 Base.prototype.extend = function(name, fn) { Base.prototype[name] = fn; }; Base.prototype.find = function(selector) { var pNodes = this.elements; this.elements = []; ; i < pNodes.length; i++) { var tmps = query(selector, pNodes[i]); ; j < tmps.length; j++) { this.elements.push(tmps[j]); } } return this; }; //调用方法$().animate(styles,speed,callback,easing); //styles:必选,如{width:100px}目前支持,top,left,width,height,opacity //speed 可选,默认动画的速度,每多长时间执行一次,默认为30ms //step 每一次动画执行步长,默认为10像素 //callback:动画执行之后的回调 //easing:动画速度的缓动函数,默认匀速 Base.prototype.animate = function(styles, callback, speed, step, easing) { function setValue(curElem, attr, nowValue) { curElem.style[attr] = (attr == ) : nowValue + 'px'); if (attr == 'opacity') { curElem.style.filter = 'opacity(alpha=' + nowValue + ')'; } document.getElementById('content').innerHTML += attr + ':' + getStyle(curElem, attr) + '</br>'; } var finalValue, startValue, nowValue; ; ; ; i < this.elements.length; i++) { var curElem = this.elements[i]; if (curElem.timer) { clearInterval(curElem.timer); } var temp = []; for (var attr in styles) { //每一组都有startValue,finalValue startValue = (attr == : parseInt(getStyle(curElem, attr))); finalValue = (attr == : parseInt(styles[attr])); step = (startValue < finalValue ? step : -step); temp.push([attr, startValue, step, finalValue]); //将各项值都复原,第二次动画的时候貌似不能复原了。。。 setValue(curElem, attr, startValue); } curElem.timer = setInterval(function() { var flag = true; //判断是否所有的动画都已经结束,除了初始化的这次,如果为true,代表所有动画都结束 ; i < temp.length; i++) { attr = temp[i][]; nowValue = temp[i][]; step = temp[i][]; finalValue = temp[i][]; && finalValue <= nowValue + step) || (step < && finalValue >= nowValue + step)) { //应当所有的动画都执行完毕,才能清除掉计时器 // clearInterval(curElem.timer); nowValue = finalValue; setValue(curElem, attr, finalValue); } else { nowValue += step; setValue(curElem, attr, nowValue); } temp[i][] = nowValue; if (nowValue != finalValue) { flag = false; } }; if (flag) { clearInterval(curElem.timer); if (callback) { callback.call(curElem); } } }, speed); }; return this; }; Base.prototype.fadeIn = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; $(curElem).animate({ }); }; return this; }; Base.prototype.fadeOut = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; $(curElem).animate({ }); }; return this; }; Base.prototype.slideUp = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; if (getStyle(curElem, 'display') != 'none') { var startHeight = getStyle(curElem, 'height'); $(curElem).animate({ }, function() { $(this).hide().css('height', startHeight); //console.log(getStyle(this,'height')); }); } }; return this; }; Base.prototype.slideDown = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; //console.log(getStyle(curElem,'display')); if (getStyle(curElem, 'display') == 'none') { var startHeight = getStyle(curElem, 'height'); $(curElem).css('height', '0px').show().animate({ 'height': startHeight }); } }; return this; }; //设置绑定事件方法 Base.prototype.bind = function(type, fn) { ; i < this.elements.length; i++) { var curElem = this.elements[i]; addEvent(curElem, type, fn); }; return this; }; //设置focus事件 Base.prototype.focus = function(fn) { this.bind('focus', fn); }; //设置blur事件 Base.prototype.blur = function(fn) { this.bind('blur', fn); }; //获得或者设置表单元素的value Base.prototype.val = function(curValue) { ; i < this.elements.length; i++) { var curElem = this.elements[i]; if (curValue) { curElem.value = curValue; } else { return curElem.value; } } return this; }; Base.prototype.attr = function(attr, value) { ; i < this.elements.length; i++) { var curElem = this.elements[i]; if (value == undefined) { return curElem.getAttribute(attr); } else { curElem.setAttribute(attr, value); } } return this; }; //在之前插入元素 Base.prototype.insertBefore = function(elem) { , len = this.elements.length; i < len; i++) { var curElem = this.elements[i]; var pNode = elem.parentNode; pNode.insertBefore(curElem, elem); } return this; }; Base.prototype.insertAfter = function(elem) { , len = this.elements.length; i < len; i++) { var curElem = this.elements[i]; var pNode = elem.parentNode; if (pNode.lastChild === elem) { pNode.appendChild(curElem); } else { pNode.insertBefore(curElem, elem.nextSibling); } } return this; }; //获取元素的高度 Base.prototype.top = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; return getElementTop(curElem); }; }; Base.prototype.left = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; return getElementLeft(curElem); }; }; Base.prototype.width = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; return curElem.offsetWidth; }; }; Base.prototype.height = function() { ; i < this.elements.length; i++) { var curElem = this.elements[i]; return curElem.offsetHeight; }; };
base.js
三、Base_drag.js基于Base.js的拖拽插件
//将拖拽封装为库 $().extend('drag', function() { var tags=arguments; for (var i = 0; i < this.elements.length; i++) { var curElem = this.elements[i]; addEvent(curElem, 'mousedown', function(e) { var diffX = e.clientX - getElementLeft(this); var diffY = e.clientY - getElementTop(this); var that = this; //限定只有点击部分区域才可以拖动 var flag = false; for (var j = 0; j < tags.length; j++) { if (e.target.tagName.toLowerCase() == tags[j].toLowerCase()) { flag = true; break; } } function move(e) { var left = e.clientX - diffX; var top = e.clientY - diffY; //如果超出了当前视图边缘则禁止脱宅 if (left < 0) { left = 0; } if (top < 0) { top = 0; } var viewSize = getViewSize(); if (left > viewSize.width - that.offsetWidth) { left = viewSize.width - that.offsetWidth; } if (top > viewSize.height - that.offsetHeight) { top = viewSize.height - that.offsetHeight; } that.style.left = left + 'px'; that.style.top = top + 'px'; } function up(e) { removeEvent(document, 'mousemove', move); removeEvent(document, 'mouseup', up); } if (flag) { addEvent(document, 'mousemove', move); addEvent(document, 'mouseup', up); } }); } });
Base_drag.js
四、Base_screenlock.js 基于Base.js的锁屏插件
//javascript锁屏插件 $().extend('lock', function() { var viewSize = getViewSize(); for (var i = this.elements.length - 1; i >= 0; i--) { var curElem = this.elements[i]; curElem.style.width = viewSize.width + 'px'; curElem.style.height = viewSize.height + 'px'; curElem.style.display = 'block'; }; document.documentElement.style.overflow = 'hidden'; return this; }); $().extend('unlock', function() { for (var i = 0; i < this.elements.length; i++) { this.elements[i].style.display = 'none'; }; document.documentElement.style.overflow = 'auto'; return this; });
Base_screenlock.js