window.onload = function () { Calculator.initCache(); Calculator.initListeners(); }; //全局计算器对象 var Calculator = (function () { var cal = { //计算器按键编码 keyCodes: { 0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '.', 11: '±', 12: '=', 13: '+', 14: '-', 15: '*', 16: '/', 17: '%', 18: '√', 19: 'x2', 20: '1/x', 21: '(', 22: ')', 23: 'yroot', 24: 'n!', 25: 'Exp', 26: '^', 27: 'sin', 28: 'cos', 29: 'tan', 30: 'powten', 31: 'log', 32: 'sinh', 33: 'cosh', 34: 'tanh', 35: 'π', 36: '↑', 37: 'CE', 38: 'C', 39: 'Back', //以下是程序员型特有的按键 40: 'A', 41: 'B', 42: 'C', 43: 'D', 44: 'E', 45: 'F', 46: '&', 47: '|', 48: '~' }, //映射用于显示的操作符,比如计算时用*,而显示时x更好 operatorFacade: { 13: '+', 14: '-', 15: '×', 16: '÷', 17: '%', 23: 'yroot', 26: '^', 46: '&', 47: '|' }, //当前计算器的类型1 --> 标准型, 2-->科学型, 3-->程序员型,默认标准型 type: 1, //计算器类型前缀,用于从页面获取元素 typePrefix: { 1: "std-", 2: "sci-", 3: "pro-" }, //记录每个类型的计算器的事件监听是否已经绑定,key:typpe数值,value:默认标准型是true(已加载) hasInited: { 1: true, 2: false, 3: false }, //常量 constants: { //鼠标悬停时的颜色 mouseHoverColor: "#CFCFCF", //计算器第一行和下面其它行的颜色是不同的,这个是第一行的背景颜色 firstMouseOutColor: "#F2F2F2", //剩余各行的背景颜色 mouseOutColor: "#E6E6E6" }, cache: { //输入内容显示元素 showInput: null, //上一步计算结果显示区域 preStep: null, //显示四种进制数值的span,只在程序员型有效 scaleSpans: null }, /** * 获取cache.showInput的内容 * @return String */ getShowInput: function () { return cal.cache.showInput.innerHTML; }, /** * 设置showInput的值 * @param value */ setShowInput: function (value) { cal.cache.showInput.innerHTML = value; }, /** * 获取cache.preStep的内容 * @return String */ getPreStep: function () { return cal.cache.preStep.innerHTML; }, setPreStep: function (value) { cal.cache.preStep.innerHTML = value; }, //操作数栈 operandStack: [], //运算符栈 operatorStack: [], //上一次输入是否是二元运算符,如果是并且再次输入二元运算符,那么忽略此次输入 isPreInputBinaryOperator: false, //上次按键是否是一元操作 isPreInputUnaryOperator: false, //等号不可以连按 isPreInputEquals: false, //如果为true,那么接下来输入的数字需要覆盖在showInput上,而不是追加 //上一次计算的结果(=) preResult: 0, //当前使用的进制(只在程序员中有效),默认10进制(DEC) currentScale: 10, isOverride: false, //int校验 intPattern: /^-?\d+$/, //小数校验 floatPattern: /^-?\d+\.\d+$/, //科学计数法校验 scientificPattern: /^\d+\.\d+e(\+|-)\d+$/, //校验16进制数字 hexPattern: /^[0-9A-F]+$/, //辅助判断运算符的优先级 operatorPriority: { ")": 0, "|": 1, "&": 2, "+": 3, "-": 3, "*": 4, "%": 4, "/": 4, "^": 5, "yroot": 5, "(": 6 }, /** * 初始化缓存对象(cal.cache) */ initCache: function () { var prefix = cal.typePrefix[cal.type]; cal.cache.showInput = document.getElementById(prefix + "show-input"); cal.cache.preStep = document.getElementById(prefix + "pre-step"); if (cal.type == 3) { cal.cache.scaleSpans = document.getElementById("pro-scales").getElementsByTagName("span"); } }, //各种事件监听函数 listeners: { /** * 鼠标悬停在按键上的变色效果 */ mouseHoverListener: function (e) { var event = e || window.event; event.currentTarget.style.backgroundColor = cal.constants.mouseHoverColor; }, /** * 鼠标从上排符号中移出的变色效果 */ firstMouseOutListener: function (e) { var event = e || window.event; event.currentTarget.style.backgroundColor = cal.constants.firstMouseOutColor; }, /** * 鼠标从下排数字、符号中移出的变色效果 */ mouseOutListener: function (e) { var event = e || window.event; event.currentTarget.style.backgroundColor = cal.constants.mouseOutColor; }, /** * 按键按下事件监听 */ keyPressListener: function (e) { var event = e || window.event; cal.handleKey(event.currentTarget.value); }, /** * 显示/隐藏计算器类型选择栏 */ toggleTypeBarListener: function () { var bar = document.getElementById(cal.typePrefix[cal.type] + "type-bar"); if (bar.style.display === "block") { bar.style.display = "none"; } else { bar.style.display = "block"; } }, /** * 切换计算器类型监听器 */ switchTypeListener: function (e) { var event = e || window.event; cal.switchType(parseInt(event.currentTarget.value)); }, /** * 切换进制(程序员专用) */ switchScaleListener: function (e) { var event = e || window.event; var scales = document.getElementById("pro-scales").getElementsByTagName("div"), //此处应该使用currentTarget属性,因为target属性在绑定事件的元素有子元素的情况下会返回子元素 scale = parseInt(event.currentTarget.getAttribute("scale")), oldScale = cal.currentScale; //切换选中样式 for (var i = 0, l = scales.length; i < l; ++i) { scales[i].removeAttribute("class"); } event.currentTarget.setAttribute("class", "scale-active"); var lis, btns; if (scale === 16) { //处理上排6个16进制数字 cal.listeners._initFirstRowListeners(); if (oldScale < 10) { cal.listeners._initSecondRowListeners(); } } else if (scale === 10) { if (oldScale === 16) { lis = document.getElementById("pro-top-symbol").getElementsByTagName("li"); cal.disableButtons(lis, cal.listeners.firstMouseOutListener); } else { cal.listeners._initSecondRowListeners(); } } else if (scale === 8) { if (oldScale > 8) { lis = document.getElementById("pro-top-symbol").getElementsByTagName("li"); cal.disableButtons(lis, cal.listeners.firstMouseOutListener); //禁用8和9 btns = cal.getElementsByAttribute("li", "oct-disable", document.getElementById("pro-num-symbol")); cal.disableButtons(btns, cal.listeners.mouseOutListener); } else { cal.listeners._initSecondRowListeners(); } } else if (scale === 2) { if (oldScale === 16) { lis = document.getElementById("pro-top-symbol").getElementsByTagName("li"); cal.disableButtons(lis, cal.listeners.firstMouseOutListener); } //禁用2-9 btns = cal.getElementsByAttribute("li", "bin-disable", document.getElementById("pro-num-symbol")); cal.disableButtons(btns, cal.listeners.mouseOutListener); } cal.currentScale = scale; }, /** * 初始化第一排操运算符事件监听 * @private */ _initFirstRowListeners: function () { var lis = document.getElementById(cal.typePrefix[cal.type] + "top-symbol").getElementsByTagName("li"); cal.rebuildButtons(lis, cal.listeners.firstMouseOutListener); }, /** * 初始化第二排运算符事件监听 * @private */ _initSecondRowListeners: function () { var lis = document.getElementById(cal.typePrefix[cal.type] + "num-symbol").getElementsByTagName("li"); cal.rebuildButtons(lis, cal.listeners.mouseOutListener); if (cal.type === 3) { //程序员型的小数点是禁用的 cal.disableButtons([document.getElementById("pro-point")], cal.listeners.mouseOutListener); } } }, //初始化事件监听器 initListeners: function () { var prefix = cal.typePrefix[cal.type]; //设置上排运算符事件监听,如果是程序员型,因为默认是10进制,而上排是16进制数字,所以不需要设置事件监听 if (cal.type < 3) { cal.listeners._initFirstRowListeners(); } //设置下面一栏数字、四则运算事件监听 cal.listeners._initSecondRowListeners(); //显示/隐藏计算器类型选择侧边栏 cal.addEvent(document.getElementById(prefix + "show-bar"), "click", cal.listeners.toggleTypeBarListener); //为侧边栏下的li绑定切换类型事件 var bar = document.getElementById(prefix + "type-bar"); lis = bar.getElementsByTagName("li"); var li; for (var i = 0, l = lis.length; i < l; ++i) { li = lis[i]; //非当前类型才有必要绑定事件 if (li.className !== "active") { cal.addEvent(li, "click", cal.listeners.switchTypeListener); } } //加载程序员型特有的 if (cal.type === 3) { var scales = document.getElementById("pro-scales").getElementsByTagName("div"), scale; for (i = 0, l = scales.length; i < l; ++i) { scale = scales[i]; cal.addEvent(scale, "click", cal.listeners.switchScaleListener); } } }, /** * 相应按键按下事件 * @param value 按键的value值(即其keyCode) */ handleKey: function (value) { var keyCode = parseInt(value); //如果是一个数字或者小数点,直接显示出来 if (keyCode < 11 || (keyCode > 39 && keyCode < 46)) { cal.showInput(cal.keyCodes[keyCode]); if (cal.type === 3) { //如果是程序员型,那么需要同步显示4中进制的值 cal.showScales(cal.getShowInput()); } } else { switch (keyCode) { //正负号 case 11: cal.unaryOperate(function (oldValue) { oldValue += ""; if (oldValue === "0") { return [oldValue]; } if (oldValue.charAt(0) === '-') { return [oldValue.substring(1)]; } else { return ["-" + oldValue]; } }); break; //开根下 case 18: cal.unaryOperate(function (si) { return [Math.sqrt(si), "sqrt"]; }); break; //平方 case 19: cal.unaryOperate(function (si) { return [Math.pow(si, 2), "sqr"]; }); break; //取倒数 case 20: cal.unaryOperate(function (si) { return [si === 0 ? "0不能作为被除数" : 1 / si, "1/"]; }); break; //阶乘 case 24: cal.unaryOperate(function (si) { if (si < 0) { si = (0 - si); } if (cal.isFloat(si + "")) { si = Math.floor(si); } return [cal.fact(si), "fact"]; }); break; //Exp 转为科学计数法表示 case 25: cal.unaryOperate(function (si) { return [si.toExponential(7)]; }); break; //sin case 27: cal.unaryOperate(function (si) { return [Math.sin(si), "sin"]; }); break; //cos case 28: cal.unaryOperate(function (si) { return [Math.cos(si), "cos"]; }); break; //tan case 29: cal.unaryOperate(function (si) { return [Math.tan(si), "tan"]; }); break; //10的x次方 case 30: cal.unaryOperate(function (si) { return [Math.pow(10, si), "powten"]; }); break; //log case 31: cal.unaryOperate(function (si) { //js的Math.log是e的对数,Windows计算器是10的对数,此处参考Windows return [Math.log10(si), "log"]; }); break; //sinh(双曲正弦函数) case 32: cal.unaryOperate(function (si) { return [Math.sinh(si), "sinh"]; }); break; //cosh(双曲余弦函数) case 33: cal.unaryOperate(function (si) { return [Math.cosh(si), "cosh"]; }); break; //tanh(双曲余切函数) case 34: cal.unaryOperate(function (si) { return [Math.tanh(si), "tanh"]; }); break; //π case 35: cal.unaryOperate(function (si) { return [Math.PI]; }); break; //按位取反(~) case 48: cal.unaryOperate(function (si) { var result = eval("~" + si); //显示四种进制的数值 cal.showScales(result); return [result]; }); break; //二元运算符开始 //加、减、乘、除、取余,运算比较简单,直接利用eval即可求值 case 13: case 14: case 15: case 16: case 17: //x的y次方 case 26: //开任意次方根 case 23: //And Or case 46: case 47: if (cal.isPreInputBinaryOperator) { break; } cal.isPreInputBinaryOperator = true; cal.isOverride = true; cal.binaryOperate(cal.keyCodes[keyCode], cal.operatorFacade[keyCode]); break; case 12: cal.calculate(); break; //ce case 37: cal.ce(); break; //c case 38: cal.clear(); break; //back case 39: cal.back(); break; // ( case 21: cal.setPreStep(cal.getPreStep() + " ("); cal.operatorStack.push("("); break; // ) case 22: cal.rightTag(); break; //向上箭头,把上次计算结果显示出来 case 36: cal.setShowInput(cal.preResult); break; } } }, /** * 执行一元运算 比如取倒数、平方 * @param operation 具体运算回调函数 * 会向operation传递一个参数si,为用户当前的输入,同时operation函数应该返回一个数组,数组的第一个 * 元素是计算的结果,第二个元素示例sqrt,第二个参数可选 */ unaryOperate: function (operation) { var si = cal.getShowInput(), result; if (cal.isInteger(si)) { result = operation(parseInt(si)); } else if (cal.isFloat(si) || cal.isScientific(si)) { result = operation(parseFloat(si)); } if (result != null) { cal.setShowInput(cal.checkLength(result[0])); if (result.length > 1) { //显示prestep有两种情况: //第一种就是这是第一次(指连续调用的第一次)调用一元函数,此时直接接在末尾即可 if (!cal.isPreInputUnaryOperator) { cal.setPreStep(cal.getPreStep() + " " + result[1] + "(" + si + ")"); cal.isPreInputUnaryOperator = true; } else { //第二种就是这不是第一次,那么应该截取最后一个空格之后的内容进行替换 //比如1 + 3 + sqrt(100),那么应该从最后一个空格后替换为此次操作的内容 var pi = cal.getPreStep(); pi = pi.substring(0, pi.lastIndexOf(" ")); pi += (" " + result[1] + "(" + si + ")"); cal.setPreStep(pi); } } //一元运算结束后应该覆盖 cal.isOverride = true; } cal.isPreInputBinaryOperator = false; }, /** * 二元操作(+ - * / %) * @param operator 操作符 * @param facade 运算符门面,用于显示在preStep中 */ binaryOperate: function (operator, facade) { //如果是程序员型,那么需要重置scalesSpan if (cal.type === 3) { cal.resetScales(); } var si = cal.getShowInput(), pi = cal.getPreStep(); if (cal.isNumber(si)) { //压操作数栈 cal.operandStack.push(si); //设置preStep有三种情况:第一种上一步不是一元操作,那么需要设置si,第二种是一元操作,那么由于一元操作会把 //函数表达式(比如sqrt(100))设置到preStep,所以不需要再次设置si //第三种就是如果最后一位是右括号,那么也不需要设置si cal.setPreStep(cal.getPreStep() + ((cal.isPreInputUnaryOperator || pi.charAt(pi.length - 1) === ")") ? (" " + facade) : (" " + si + " " + facade))); var preOp = cal.operatorStack.pop(); if (preOp != null) { var op = cal.operatorPriority[operator], pp = cal.operatorPriority[preOp]; //如果当前运算符优先级更高,那么只需压栈不需要计算 if (op > pp) { cal.operatorStack.push(preOp); } //两者的优先级相等并且高于3(加减),那么只需要计算一步 else if (op > 3 && op === pp) { cal.operatorStack.push(preOp); cal.travelStack(1); } else { cal.operatorStack.push(preOp); cal.setShowInput(cal.checkLength(cal.travelStack(null, op))); } } cal.operatorStack.push(operator); } cal.isPreInputUnaryOperator = false; cal.isPreInputEquals = false; }, /** * 按下=时计算最终结果 */ calculate: function () { if (!cal.isPreInputEquals) { var si = cal.getShowInput(), result; if (cal.isNumber(si)) { cal.operandStack.push(si); result = cal.checkLength(cal.travelStack()); cal.setShowInput(result); cal.preResult = result; cal.setPreStep(" "); //程序员型需要把计算结果的四种进制值显示出来 if (cal.type === 3) { cal.showScales(result); } cal.isOverride = true; } cal._reset(); cal.isPreInputEquals = true; } }, /** * 访问运算栈,返回计算结果 * @param level 计算的层数,如果不指定,那么遍历整个栈 * @param minPri(最小/截止优先级) 此参数针对下面的情况: * 2 + 2 X 3 X 2 ^ 2 X 2,由于最后一个运算符是X,优先级比^低,所以触发了对操作栈的遍历,但是不能全部遍历,应该遍历到第一个X停止 * 如果不停止得到的将是错误的26 X 2 = 52,正确结果是2 + 24 X 2 = 50 * @return Number * @private */ travelStack: function (level, minPri) { var op, f, s, //result取操作数栈栈顶,因为防止在下列情况9 X (6 + 时出现undefined result = cal.operandStack[cal.operandStack.length - 1], l = level || cal.operatorStack.length, p = minPri || 0; for (var i = 0; i < l; ++i) { op = cal.operatorStack.pop(); //遇到minPri或左括号立即停止,左括号也需要再次压入,因为只有一个右括号才能抵消一个左括号 if (cal.operatorPriority[op] < p || op === "(") { cal.operatorStack.push(op); break; } s = cal.operandStack.pop(); f = cal.operandStack.pop(); result = cal._stackHelper(f, s, op); cal.operandStack.push(result); } return result; }, /** * 输入了一个右括号 */ rightTag: function () { var si = cal.getShowInput(); if (cal.isNumber(si)) { cal.setPreStep(cal.getPreStep() + (" " + si + " )")); cal.operandStack.push(si); //遍历计算操作栈,直至遇到左括号 var op = cal.operatorStack.pop(), f, s, result; while (op !== "(" && op != null) { s = cal.operandStack.pop(); f = cal.operandStack.pop(); result = cal._stackHelper(f, s, op); cal.operandStack.push(result); op = cal.operatorStack.pop(); } //此处应该直接把小括号的计算内容弹出,因为此结果显示在了showInput中,而再次执行二元操作时会先有一个压栈的操作, // 并且执行=时也是根据showInput内容计算的 cal.setShowInput(cal.checkLength(cal.operandStack.pop())); } }, /** * 辅助进行一次栈运算 * @param f 第一个操作数 * @param s 第二个操作数 * @param op 运算符 * @return 返回运算结果 * @private */ _stackHelper: function (f, s, op) { var result; if (op === "^") { result = Math.pow(f, s); } else if (op === "yroot") { result = Math.pow(f, 1 / s); } //+ - X / %5中操作 else { //如果是程序员型,那么需要考虑进制的问题 if (cal.type === 3) { var scale = cal.currentScale, fi, si; if (scale === 10) { result = eval(f + op + s); } else if (scale === 16) { fi = parseInt(f, 16); si = parseInt(s, 16); result = eval(fi + op + si).toString(16); } else if (scale === 8) { fi = parseInt(f, 8); si = parseInt(s, 8); result = eval(fi + op + si).toString(8); } else { fi = parseInt(f, 2); si = parseInt(s, 2); result = eval(fi + op + si).toString(2); } } else { result = eval(f + op + s); } } return result; }, /** * 确保结果长度不大于13,如果超出,以科学计数法形式显示(小数点后7位) * @param value 需要检查的结果 */ checkLength: function (value) { var valueStr = value + ""; if (cal.isFloat(valueStr)) { valueStr = valueStr.replace(/0+$/, ""); } return valueStr.length > 12 ? value.toExponential(7) : valueStr; }, //CE ce: function () { cal.setShowInput("0"); if (cal.type === 3) { cal.resetScales(); } }, //C clear: function () { cal.setShowInput("0"); cal.setPreStep(" "); cal._reset(); if (cal.type === 3) { cal.resetScales(); } }, /** * 清空四个进制的值 * @private */ resetScales: function () { for (var i = 0; i < 4; i++) { cal.cache.scaleSpans[i].innerHTML = "0"; } }, back: function () { var oldValue = cal.cache.showInput.innerText; cal.setShowInput(oldValue.length < 2 ? "0" : oldValue.substring(0, oldValue.length - 1)); }, /** * 当计算器类型是程序员时,需要同步显示四种进制的值 * @param num 需要显示的数字 */ showScales: function (num) { var result = cal.calculateScales(num), spans = cal.cache.scaleSpans; for (var i = 0; i < 4; ++i) { spans[i].innerHTML = result[i]; } }, /** * 根据当前进制分别计算出四种进制的值 * @param num 需要计算的值 * @return Array 共4个元素,依次为16、10、8、2进制的值 */ calculateScales: function (num) { var scale = cal.currentScale, result = [], i; if (scale === 10) { i = parseInt(num); result[0] = i.toString(16); result[1] = i; result[2] = i.toString(8); result[3] = i.toString(2); } else if (scale === 16) { //先转成10进制,然后再转成其它进制 i = parseInt(num, 16); result[0] = num; result[1] = i; result[2] = i.toString(8); result[3] = i.toString(2); } else if (scale === 8) { i = parseInt(num, 8); result[0] = i.toString(16); result[1] = i; result[2] = num; result[3] = i.toString(2); } else { i = parseInt(num, 2); result[0] = i.toString(16); result[1] = i; result[2] = i.toString(8); result[3] = num; } return result; }, /** * 校验字符串是否是数字 * @param str * @return 是返回true */ isNumber: function (str) { return cal.isInteger(str) || cal.isFloat(str) || cal.isScientific(str) || cal.isHex(str); }, /** * 校验是否是整数 * @param str */ isInteger: function (str) { return str.match(cal.intPattern); }, /** * 校验是否是小数 * @param str */ isFloat: function (str) { return str.match(cal.floatPattern); }, /** * 是否是科学计数法 * @param str */ isScientific: function (str) { return str.match(cal.scientificPattern); }, /** * 是否是16进制数字 * @param str */ isHex: function (str) { return str.match(cal.hexPattern); }, /** * 显示输入的内容 * 用于相应数字/小数点按键 * @param value 按键的内容,不是keyCode */ showInput: function (value) { var oldValue = cal.getShowInput(); var newValue = oldValue; if (cal.isOverride) { //既然是覆盖,那么如果直接输入.那么肯定是0.x if (value === ".") { newValue = "0."; } else { newValue = value; } } else if (oldValue.length < 13) { if (oldValue === "0") { if (value === ".") { newValue = "0."; } else { newValue = value; } } else { newValue += value; } } cal.setShowInput(newValue); cal.isOverride = false; cal.isPreInputBinaryOperator = false; cal.isPreInputUnaryOperator = false; cal.isPreInputEquals = false; }, /** * 切换计算器类型 * @param type int 要切换到的类型 */ switchType: function (type) { //关闭选择栏 var oldPrefix = cal.typePrefix[cal.type]; document.getElementById(oldPrefix + "type-bar").style.display = "none"; //切换面板 document.getElementById(oldPrefix + "main").style.display = "none"; document.getElementById(cal.typePrefix[type] + "main").style.display = "block"; cal.type = type; if (!cal.hasInited[type]) { cal.initListeners(); cal.hasInited[type] = true; } cal.initCache(); cal._reset(); }, /** * 重置各个标志变量以及操作栈 * @private */ _reset: function () { cal.operandStack = []; cal.operatorStack = []; cal.isPreInputBinaryOperator = false; cal.isPreInputUnaryOperator = false; cal.isPreInputEquals = false; }, /** * 工具方法,为element添加事件处理函数 * @param element 需要添加事件的dom元素 * @param name name事件名称(不含on) * @param handler 事件处理函数 */ addEvent: function (element, name, handler) { if (window.addEventListener) { element.addEventListener(name, handler); } else if (window.attachEvent) { element.attachEvent("on" + name, handler); } }, /** * 工具方法,为element移除特定的事件监听 * @param element 需要移除事件监听的dom元素 * @param name 事件名,没有"on" * @param handler 需要移除的处理函数 */ removeEvent: function (element, name, handler) { if (window.removeEventListener) { element.removeEventListener(name, handler); } else if (window.detachEvent) { element.detachEvent("on" + name, handler); } }, /** * 根据元素的属性进行查找,只要存在此属性即可 * @param tag 目标标签名 * @param attr * @param root 开始查找的起始节点,可选,默认document */ getElementsByAttribute: function (tag, attr, root) { var parent = root || document, result = []; var arr = parent.getElementsByTagName(tag), a; for (var i = 0, l = arr.length; i < l; ++i) { a = arr[i]; if (a.getAttribute(attr) != null) { //这个写法... result[result.length] = a; } } return result; }, /** * 阶乘 * @param n 操作数 int * @return */ fact: (function () { //缓存 var cache = [1]; function factorial(n) { var result = cache[n - 1]; if (result == null) { result = 1; for (var i = 1; i <= n; ++i) { result *= i; } cache[n - 1] = result; } return result; } return factorial; })(), /** * 禁用按键,只有程序员型才会用到 * @param lis 按钮集合 * @param mouseOutListener function 鼠标移出时采用哪个监听函数,取决于按钮的位置(上排/下排) */ disableButtons: function (lis, mouseOutListener) { var li; for (var i = 0, l = lis.length; i < l; ++i) { li = lis[i]; li.setAttribute("class", "disable-btn"); cal.removeEvent(li, "click", cal.listeners.keyPressListener); cal.removeEvent(li, "mouseout", mouseOutListener); cal.removeEvent(li, "mouseover", cal.listeners.mouseHoverListener); } }, /** * 重新设置按键 * @param lis 按钮集合 * @param mouseOutListener function 鼠标移出时采用哪个监听函数,取决于按钮的位置(上排/下排) */ rebuildButtons: function (lis, mouseOutListener) { var li; for (var i = 0, l = lis.length; i < l; ++i) { li = lis[i]; li.removeAttribute("class"); cal.addEvent(li, "click", cal.listeners.keyPressListener); cal.addEvent(li, "mouseout", mouseOutListener); cal.addEvent(li, "mouseover", cal.listeners.mouseHoverListener); } } }; return cal; })();