You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

990 lines
38 KiB

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("&nbsp;");
//程序员型需要把计算结果的四种进制值显示出来
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("&nbsp;");
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;
})();