├── LICENSE ├── README.md ├── css └── cal.css ├── images ├── 10_x.png ├── 1_x.png ├── x_2.png ├── x_y.png └── x_y_sqrt.png ├── index.html ├── js └── cal.js └── screenshots ├── programmer.png ├── science.png └── standard.png /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "{}" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright 2015 seaswalker 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/README.md -------------------------------------------------------------------------------- /css/cal.css: -------------------------------------------------------------------------------- 1 | /*各界面共用部分开始*/ 2 | * { 3 | font-family: "微软雅黑"; 4 | } 5 | 6 | .standard-main, 7 | .science-main, 8 | .programmer-main { 9 | background-color: #F2F2F2; 10 | margin: 40px auto 0px; 11 | box-shadow: 0px 0px 15px #4D4D4D; 12 | } 13 | 14 | ul { 15 | list-style: none; 16 | margin: 0px; 17 | padding: 0px; 18 | } 19 | 20 | li { 21 | float: left; 22 | text-align: center; 23 | cursor: pointer; 24 | } 25 | 26 | li img { 27 | height: 14px; 28 | } 29 | 30 | .title { 31 | height: 30px; 32 | line-height: 30px; 33 | } 34 | 35 | .result { 36 | height: 120px; 37 | text-align: right; 38 | } 39 | 40 | .second { 41 | font-size: 40px; 42 | font-weight: bold; 43 | padding-right: 10px; 44 | } 45 | 46 | .pre { 47 | color: #A7A7A7; 48 | padding-right: 10px; 49 | } 50 | 51 | /*计算器类型*/ 52 | .type { 53 | height: 20px; 54 | text-align: left; 55 | margin-left: 10px; 56 | font-weight: bold; 57 | margin-top: 10px; 58 | cursor: pointer; 59 | } 60 | 61 | /*类型选择侧边栏*/ 62 | .type-bar { 63 | display: none; 64 | height: 90px; 65 | width: 100px; 66 | position: absolute; 67 | top: 110px; 68 | background-color: #E6E6E6; 69 | } 70 | 71 | .type-bar li { 72 | float: left; 73 | width: 100px; 74 | text-align: center; 75 | line-height: 30px; 76 | } 77 | 78 | .active { 79 | background-color: #CFCFCF; 80 | } 81 | 82 | /*数字加粗*/ 83 | .number { 84 | font-weight: bold; 85 | } 86 | 87 | /*共用部分结束*/ 88 | 89 | /*计算器标准版界面开始*/ 90 | .standard-main { 91 | width: 350px; 92 | height: 480px; 93 | } 94 | 95 | #std-top-symbol { 96 | border-top: 1px #A7A7A7 solid; 97 | height: 52px; 98 | } 99 | 100 | #std-num-symbol { 101 | background-color: #E6E6E6; 102 | height: 270px; 103 | font-size: 20px; 104 | } 105 | 106 | #std-top-symbol li, 107 | #std-num-symbol li { 108 | line-height: 52px; 109 | width: 87.5px; 110 | } 111 | 112 | /*标准界面结束*/ 113 | 114 | /*科学型界面开始*/ 115 | .science-main { 116 | display: none; 117 | width: 350px; 118 | } 119 | 120 | .sci-result { 121 | height: 120px; 122 | text-align: right; 123 | } 124 | 125 | #sci-top-symbol { 126 | border-top: 1px #A7A7A7 solid; 127 | height: 135px; 128 | } 129 | 130 | #sci-top-symbol li, 131 | #sci-num-symbol li { 132 | line-height: 45px; 133 | width: 70px; 134 | } 135 | 136 | #sci-num-symbol { 137 | height: 235px; 138 | background-color: #E6E6E6; 139 | } 140 | 141 | /*科学型界面结束*/ 142 | 143 | /*程序员型界面开始*/ 144 | .programmer-main { 145 | display: none; 146 | width: 350px; 147 | } 148 | 149 | .pro-result { 150 | height: 220px; 151 | text-align: right; 152 | } 153 | 154 | #pro-top-symbol { 155 | border-top: 1px #A7A7A7 solid; 156 | height: 45px; 157 | } 158 | 159 | #pro-top-symbol li { 160 | line-height: 45px; 161 | width: 58px; 162 | } 163 | 164 | #pro-num-symbol li { 165 | line-height: 45px; 166 | width: 70px; 167 | } 168 | 169 | #pro-num-symbol { 170 | height: 235px; 171 | background-color: #E6E6E6; 172 | } 173 | 174 | /*四个进制*/ 175 | #pro-scales { 176 | margin-left: 20px; 177 | } 178 | 179 | #pro-scales div { 180 | text-align: left; 181 | margin-top: 5px; 182 | cursor: pointer; 183 | } 184 | 185 | /*当前使用的进制*/ 186 | .scale-active { 187 | color: cornflowerblue; 188 | } 189 | 190 | /*按键不可用*/ 191 | .disable-btn { 192 | color: #CACACA; 193 | } 194 | 195 | /*程序员型界面结束*/ -------------------------------------------------------------------------------- /images/10_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/images/10_x.png -------------------------------------------------------------------------------- /images/1_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/images/1_x.png -------------------------------------------------------------------------------- /images/x_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/images/x_2.png -------------------------------------------------------------------------------- /images/x_y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/images/x_y.png -------------------------------------------------------------------------------- /images/x_y_sqrt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/images/x_y_sqrt.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 计算器 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |   计算器 16 |
17 | 18 |
19 | 20 |
21 | ☰   Standard 22 |
23 | 24 |
25 |   26 |
27 | 28 |
0
29 |
30 | 36 | 37 | 59 | 60 | 65 |
66 | 67 |
68 |
69 |   计算器 70 |
71 | 72 |
73 | 74 |
75 | ☰   Science 76 |
77 | 78 |
79 |   80 |
81 | 82 |
0
83 |
84 | 85 | 102 | 103 | 130 | 131 | 136 |
137 | 138 |
139 |
140 |   计算器 141 |
142 | 143 |
144 | 145 |
146 | ☰   Programmer 147 |
148 | 149 |
150 |   151 |
152 | 153 |
0
154 | 155 |
156 |
HEX   0
157 |
DEC   0
158 |
OCT   0
159 |
BIN    0
160 |
161 |
162 | 163 | 171 | 172 | 199 | 200 | 205 |
206 | 207 | 208 | -------------------------------------------------------------------------------- /js/cal.js: -------------------------------------------------------------------------------- 1 | window.onload = function () { 2 | Calculator.initCache(); 3 | Calculator.initListeners(); 4 | }; 5 | 6 | //全局计算器对象 7 | var Calculator = (function () { 8 | var cal = { 9 | //计算器按键编码 10 | keyCodes: { 11 | 0: '0', 12 | 1: '1', 13 | 2: '2', 14 | 3: '3', 15 | 4: '4', 16 | 5: '5', 17 | 6: '6', 18 | 7: '7', 19 | 8: '8', 20 | 9: '9', 21 | 10: '.', 22 | 11: '±', 23 | 12: '=', 24 | 13: '+', 25 | 14: '-', 26 | 15: '*', 27 | 16: '/', 28 | 17: '%', 29 | 18: '√', 30 | 19: 'x2', 31 | 20: '1/x', 32 | 21: '(', 33 | 22: ')', 34 | 23: 'yroot', 35 | 24: 'n!', 36 | 25: 'Exp', 37 | 26: '^', 38 | 27: 'sin', 39 | 28: 'cos', 40 | 29: 'tan', 41 | 30: 'powten', 42 | 31: 'log', 43 | 32: 'sinh', 44 | 33: 'cosh', 45 | 34: 'tanh', 46 | 35: 'π', 47 | 36: '↑', 48 | 37: 'CE', 49 | 38: 'C', 50 | 39: 'Back', 51 | //以下是程序员型特有的按键 52 | 40: 'A', 53 | 41: 'B', 54 | 42: 'C', 55 | 43: 'D', 56 | 44: 'E', 57 | 45: 'F', 58 | 46: '&', 59 | 47: '|', 60 | 48: '~' 61 | }, 62 | //映射用于显示的操作符,比如计算时用*,而显示时x更好 63 | operatorFacade: { 64 | 13: '+', 65 | 14: '-', 66 | 15: '×', 67 | 16: '÷', 68 | 17: '%', 69 | 23: 'yroot', 70 | 26: '^', 71 | 46: '&', 72 | 47: '|' 73 | }, 74 | //当前计算器的类型1 --> 标准型, 2-->科学型, 3-->程序员型,默认标准型 75 | type: 1, 76 | //计算器类型前缀,用于从页面获取元素 77 | typePrefix: { 78 | 1: "std-", 79 | 2: "sci-", 80 | 3: "pro-" 81 | }, 82 | //记录每个类型的计算器的事件监听是否已经绑定,key:typpe数值,value:默认标准型是true(已加载) 83 | hasInited: { 84 | 1: true, 85 | 2: false, 86 | 3: false 87 | }, 88 | //常量 89 | constants: { 90 | //鼠标悬停时的颜色 91 | mouseHoverColor: "#CFCFCF", 92 | //计算器第一行和下面其它行的颜色是不同的,这个是第一行的背景颜色 93 | firstMouseOutColor: "#F2F2F2", 94 | //剩余各行的背景颜色 95 | mouseOutColor: "#E6E6E6" 96 | }, 97 | cache: { 98 | //输入内容显示元素 99 | showInput: null, 100 | //上一步计算结果显示区域 101 | preStep: null, 102 | //显示四种进制数值的span,只在程序员型有效 103 | scaleSpans: null 104 | }, 105 | /** 106 | * 获取cache.showInput的内容 107 | * @return String 108 | */ 109 | getShowInput: function () { 110 | return cal.cache.showInput.innerHTML; 111 | }, 112 | /** 113 | * 设置showInput的值 114 | * @param value 115 | */ 116 | setShowInput: function (value) { 117 | cal.cache.showInput.innerHTML = value; 118 | }, 119 | /** 120 | * 获取cache.preStep的内容 121 | * @return String 122 | */ 123 | getPreStep: function () { 124 | return cal.cache.preStep.innerHTML; 125 | }, 126 | setPreStep: function (value) { 127 | cal.cache.preStep.innerHTML = value; 128 | }, 129 | //操作数栈 130 | operandStack: [], 131 | //运算符栈 132 | operatorStack: [], 133 | //上一次输入是否是二元运算符,如果是并且再次输入二元运算符,那么忽略此次输入 134 | isPreInputBinaryOperator: false, 135 | //上次按键是否是一元操作 136 | isPreInputUnaryOperator: false, 137 | //等号不可以连按 138 | isPreInputEquals: false, 139 | //如果为true,那么接下来输入的数字需要覆盖在showInput上,而不是追加 140 | //上一次计算的结果(=) 141 | preResult: 0, 142 | //当前使用的进制(只在程序员中有效),默认10进制(DEC) 143 | currentScale: 10, 144 | isOverride: false, 145 | //int校验 146 | intPattern: /^-?\d+$/, 147 | //小数校验 148 | floatPattern: /^-?\d+\.\d+$/, 149 | //科学计数法校验 150 | scientificPattern: /^\d+\.\d+e(\+|-)\d+$/, 151 | //校验16进制数字 152 | hexPattern: /^[0-9A-F]+$/, 153 | //辅助判断运算符的优先级 154 | operatorPriority: { 155 | ")": 0, 156 | "|": 1, 157 | "&": 2, 158 | "+": 3, 159 | "-": 3, 160 | "*": 4, 161 | "%": 4, 162 | "/": 4, 163 | "^": 5, 164 | "yroot": 5, 165 | "(": 6 166 | }, 167 | /** 168 | * 初始化缓存对象(cal.cache) 169 | */ 170 | initCache: function () { 171 | var prefix = cal.typePrefix[cal.type]; 172 | cal.cache.showInput = document.getElementById(prefix + "show-input"); 173 | cal.cache.preStep = document.getElementById(prefix + "pre-step"); 174 | if (cal.type == 3) { 175 | cal.cache.scaleSpans = document.getElementById("pro-scales").getElementsByTagName("span"); 176 | } 177 | }, 178 | //各种事件监听函数 179 | listeners: { 180 | /** 181 | * 鼠标悬停在按键上的变色效果 182 | */ 183 | mouseHoverListener: function (e) { 184 | var event = e || window.event; 185 | event.currentTarget.style.backgroundColor = cal.constants.mouseHoverColor; 186 | }, 187 | /** 188 | * 鼠标从上排符号中移出的变色效果 189 | */ 190 | firstMouseOutListener: function (e) { 191 | var event = e || window.event; 192 | event.currentTarget.style.backgroundColor = cal.constants.firstMouseOutColor; 193 | }, 194 | /** 195 | * 鼠标从下排数字、符号中移出的变色效果 196 | */ 197 | mouseOutListener: function (e) { 198 | var event = e || window.event; 199 | event.currentTarget.style.backgroundColor = cal.constants.mouseOutColor; 200 | }, 201 | /** 202 | * 按键按下事件监听 203 | */ 204 | keyPressListener: function (e) { 205 | var event = e || window.event; 206 | cal.handleKey(event.currentTarget.value); 207 | }, 208 | /** 209 | * 显示/隐藏计算器类型选择栏 210 | */ 211 | toggleTypeBarListener: function () { 212 | var bar = document.getElementById(cal.typePrefix[cal.type] + "type-bar"); 213 | if (bar.style.display === "block") { 214 | bar.style.display = "none"; 215 | } else { 216 | bar.style.display = "block"; 217 | } 218 | }, 219 | /** 220 | * 切换计算器类型监听器 221 | */ 222 | switchTypeListener: function (e) { 223 | var event = e || window.event; 224 | cal.switchType(parseInt(event.currentTarget.value)); 225 | }, 226 | /** 227 | * 切换进制(程序员专用) 228 | */ 229 | switchScaleListener: function (e) { 230 | var event = e || window.event; 231 | var scales = document.getElementById("pro-scales").getElementsByTagName("div"), 232 | //此处应该使用currentTarget属性,因为target属性在绑定事件的元素有子元素的情况下会返回子元素 233 | scale = parseInt(event.currentTarget.getAttribute("scale")), 234 | oldScale = cal.currentScale; 235 | //切换选中样式 236 | for (var i = 0, l = scales.length; i < l; ++i) { 237 | scales[i].removeAttribute("class"); 238 | } 239 | event.currentTarget.setAttribute("class", "scale-active"); 240 | var lis, btns; 241 | if (scale === 16) { 242 | //处理上排6个16进制数字 243 | cal.listeners._initFirstRowListeners(); 244 | if (oldScale < 10) { 245 | cal.listeners._initSecondRowListeners(); 246 | } 247 | } else if (scale === 10) { 248 | if (oldScale === 16) { 249 | lis = document.getElementById("pro-top-symbol").getElementsByTagName("li"); 250 | cal.disableButtons(lis, cal.listeners.firstMouseOutListener); 251 | } else { 252 | cal.listeners._initSecondRowListeners(); 253 | } 254 | } else if (scale === 8) { 255 | if (oldScale > 8) { 256 | lis = document.getElementById("pro-top-symbol").getElementsByTagName("li"); 257 | cal.disableButtons(lis, cal.listeners.firstMouseOutListener); 258 | //禁用8和9 259 | btns = cal.getElementsByAttribute("li", "oct-disable", document.getElementById("pro-num-symbol")); 260 | cal.disableButtons(btns, cal.listeners.mouseOutListener); 261 | } else { 262 | cal.listeners._initSecondRowListeners(); 263 | } 264 | } else if (scale === 2) { 265 | if (oldScale === 16) { 266 | lis = document.getElementById("pro-top-symbol").getElementsByTagName("li"); 267 | cal.disableButtons(lis, cal.listeners.firstMouseOutListener); 268 | } 269 | //禁用2-9 270 | btns = cal.getElementsByAttribute("li", "bin-disable", document.getElementById("pro-num-symbol")); 271 | cal.disableButtons(btns, cal.listeners.mouseOutListener); 272 | } 273 | cal.currentScale = scale; 274 | }, 275 | /** 276 | * 初始化第一排操运算符事件监听 277 | * @private 278 | */ 279 | _initFirstRowListeners: function () { 280 | var lis = document.getElementById(cal.typePrefix[cal.type] + "top-symbol").getElementsByTagName("li"); 281 | cal.rebuildButtons(lis, cal.listeners.firstMouseOutListener); 282 | }, 283 | /** 284 | * 初始化第二排运算符事件监听 285 | * @private 286 | */ 287 | _initSecondRowListeners: function () { 288 | var lis = document.getElementById(cal.typePrefix[cal.type] + "num-symbol").getElementsByTagName("li"); 289 | cal.rebuildButtons(lis, cal.listeners.mouseOutListener); 290 | if (cal.type === 3) { 291 | //程序员型的小数点是禁用的 292 | cal.disableButtons([document.getElementById("pro-point")], cal.listeners.mouseOutListener); 293 | } 294 | } 295 | }, 296 | //初始化事件监听器 297 | initListeners: function () { 298 | var prefix = cal.typePrefix[cal.type]; 299 | //设置上排运算符事件监听,如果是程序员型,因为默认是10进制,而上排是16进制数字,所以不需要设置事件监听 300 | if (cal.type < 3) { 301 | cal.listeners._initFirstRowListeners(); 302 | } 303 | //设置下面一栏数字、四则运算事件监听 304 | cal.listeners._initSecondRowListeners(); 305 | //显示/隐藏计算器类型选择侧边栏 306 | cal.addEvent(document.getElementById(prefix + "show-bar"), "click", cal.listeners.toggleTypeBarListener); 307 | //为侧边栏下的li绑定切换类型事件 308 | var bar = document.getElementById(prefix + "type-bar"); 309 | lis = bar.getElementsByTagName("li"); 310 | var li; 311 | for (var i = 0, l = lis.length; i < l; ++i) { 312 | li = lis[i]; 313 | //非当前类型才有必要绑定事件 314 | if (li.className !== "active") { 315 | cal.addEvent(li, "click", cal.listeners.switchTypeListener); 316 | } 317 | } 318 | //加载程序员型特有的 319 | if (cal.type === 3) { 320 | var scales = document.getElementById("pro-scales").getElementsByTagName("div"), 321 | scale; 322 | for (i = 0, l = scales.length; i < l; ++i) { 323 | scale = scales[i]; 324 | cal.addEvent(scale, "click", cal.listeners.switchScaleListener); 325 | } 326 | } 327 | }, 328 | /** 329 | * 相应按键按下事件 330 | * @param value 按键的value值(即其keyCode) 331 | */ 332 | handleKey: function (value) { 333 | var keyCode = parseInt(value); 334 | //如果是一个数字或者小数点,直接显示出来 335 | if (keyCode < 11 || (keyCode > 39 && keyCode < 46)) { 336 | cal.showInput(cal.keyCodes[keyCode]); 337 | if (cal.type === 3) { 338 | //如果是程序员型,那么需要同步显示4中进制的值 339 | cal.showScales(cal.getShowInput()); 340 | } 341 | } else { 342 | switch (keyCode) { 343 | //正负号 344 | case 11: 345 | cal.unaryOperate(function (oldValue) { 346 | oldValue += ""; 347 | if (oldValue === "0") { 348 | return [oldValue]; 349 | } 350 | if (oldValue.charAt(0) === '-') { 351 | return [oldValue.substring(1)]; 352 | } else { 353 | return ["-" + oldValue]; 354 | } 355 | }); 356 | break; 357 | //开根下 358 | case 18: 359 | cal.unaryOperate(function (si) { 360 | return [Math.sqrt(si), "sqrt"]; 361 | }); 362 | break; 363 | //平方 364 | case 19: 365 | cal.unaryOperate(function (si) { 366 | return [Math.pow(si, 2), "sqr"]; 367 | }); 368 | break; 369 | //取倒数 370 | case 20: 371 | cal.unaryOperate(function (si) { 372 | return [si === 0 ? "0不能作为被除数" : 1 / si, "1/"]; 373 | }); 374 | break; 375 | //阶乘 376 | case 24: 377 | cal.unaryOperate(function (si) { 378 | if (si < 0) { 379 | si = (0 - si); 380 | } 381 | if (cal.isFloat(si + "")) { 382 | si = Math.floor(si); 383 | } 384 | return [cal.fact(si), "fact"]; 385 | }); 386 | break; 387 | //Exp 转为科学计数法表示 388 | case 25: 389 | cal.unaryOperate(function (si) { 390 | return [si.toExponential(7)]; 391 | }); 392 | break; 393 | //sin 394 | case 27: 395 | cal.unaryOperate(function (si) { 396 | return [Math.sin(si), "sin"]; 397 | }); 398 | break; 399 | //cos 400 | case 28: 401 | cal.unaryOperate(function (si) { 402 | return [Math.cos(si), "cos"]; 403 | }); 404 | break; 405 | //tan 406 | case 29: 407 | cal.unaryOperate(function (si) { 408 | return [Math.tan(si), "tan"]; 409 | }); 410 | break; 411 | //10的x次方 412 | case 30: 413 | cal.unaryOperate(function (si) { 414 | return [Math.pow(10, si), "powten"]; 415 | }); 416 | break; 417 | //log 418 | case 31: 419 | cal.unaryOperate(function (si) { 420 | //js的Math.log是e的对数,Windows计算器是10的对数,此处参考Windows 421 | return [Math.log10(si), "log"]; 422 | }); 423 | break; 424 | //sinh(双曲正弦函数) 425 | case 32: 426 | cal.unaryOperate(function (si) { 427 | return [Math.sinh(si), "sinh"]; 428 | }); 429 | break; 430 | //cosh(双曲余弦函数) 431 | case 33: 432 | cal.unaryOperate(function (si) { 433 | return [Math.cosh(si), "cosh"]; 434 | }); 435 | break; 436 | //tanh(双曲余切函数) 437 | case 34: 438 | cal.unaryOperate(function (si) { 439 | return [Math.tanh(si), "tanh"]; 440 | }); 441 | break; 442 | //π 443 | case 35: 444 | cal.unaryOperate(function (si) { 445 | return [Math.PI]; 446 | }); 447 | break; 448 | //按位取反(~) 449 | case 48: 450 | cal.unaryOperate(function (si) { 451 | var result = eval("~" + si); 452 | //显示四种进制的数值 453 | cal.showScales(result); 454 | return [result]; 455 | }); 456 | break; 457 | //二元运算符开始 458 | //加、减、乘、除、取余,运算比较简单,直接利用eval即可求值 459 | case 13: 460 | case 14: 461 | case 15: 462 | case 16: 463 | case 17: 464 | //x的y次方 465 | case 26: 466 | //开任意次方根 467 | case 23: 468 | //And Or 469 | case 46: 470 | case 47: 471 | if (cal.isPreInputBinaryOperator) { 472 | break; 473 | } 474 | cal.isPreInputBinaryOperator = true; 475 | cal.isOverride = true; 476 | cal.binaryOperate(cal.keyCodes[keyCode], cal.operatorFacade[keyCode]); 477 | break; 478 | case 12: 479 | cal.calculate(); 480 | break; 481 | //ce 482 | case 37: 483 | cal.ce(); 484 | break; 485 | //c 486 | case 38: 487 | cal.clear(); 488 | break; 489 | //back 490 | case 39: 491 | cal.back(); 492 | break; 493 | // ( 494 | case 21: 495 | cal.setPreStep(cal.getPreStep() + " ("); 496 | cal.operatorStack.push("("); 497 | break; 498 | // ) 499 | case 22: 500 | cal.rightTag(); 501 | break; 502 | //向上箭头,把上次计算结果显示出来 503 | case 36: 504 | cal.setShowInput(cal.preResult); 505 | break; 506 | } 507 | } 508 | }, 509 | /** 510 | * 执行一元运算 比如取倒数、平方 511 | * @param operation 具体运算回调函数 512 | * 会向operation传递一个参数si,为用户当前的输入,同时operation函数应该返回一个数组,数组的第一个 513 | * 元素是计算的结果,第二个元素示例sqrt,第二个参数可选 514 | */ 515 | unaryOperate: function (operation) { 516 | var si = cal.getShowInput(), 517 | result; 518 | if (cal.isInteger(si)) { 519 | result = operation(parseInt(si)); 520 | } else if (cal.isFloat(si) || cal.isScientific(si)) { 521 | result = operation(parseFloat(si)); 522 | } 523 | if (result != null) { 524 | cal.setShowInput(cal.checkLength(result[0])); 525 | if (result.length > 1) { 526 | //显示prestep有两种情况: 527 | //第一种就是这是第一次(指连续调用的第一次)调用一元函数,此时直接接在末尾即可 528 | if (!cal.isPreInputUnaryOperator) { 529 | cal.setPreStep(cal.getPreStep() + " " + result[1] + "(" + si + ")"); 530 | cal.isPreInputUnaryOperator = true; 531 | } else { 532 | //第二种就是这不是第一次,那么应该截取最后一个空格之后的内容进行替换 533 | //比如1 + 3 + sqrt(100),那么应该从最后一个空格后替换为此次操作的内容 534 | var pi = cal.getPreStep(); 535 | pi = pi.substring(0, pi.lastIndexOf(" ")); 536 | pi += (" " + result[1] + "(" + si + ")"); 537 | cal.setPreStep(pi); 538 | } 539 | } 540 | //一元运算结束后应该覆盖 541 | cal.isOverride = true; 542 | } 543 | cal.isPreInputBinaryOperator = false; 544 | }, 545 | /** 546 | * 二元操作(+ - * / %) 547 | * @param operator 操作符 548 | * @param facade 运算符门面,用于显示在preStep中 549 | */ 550 | binaryOperate: function (operator, facade) { 551 | //如果是程序员型,那么需要重置scalesSpan 552 | if (cal.type === 3) { 553 | cal.resetScales(); 554 | } 555 | var si = cal.getShowInput(), 556 | pi = cal.getPreStep(); 557 | if (cal.isNumber(si)) { 558 | //压操作数栈 559 | cal.operandStack.push(si); 560 | //设置preStep有三种情况:第一种上一步不是一元操作,那么需要设置si,第二种是一元操作,那么由于一元操作会把 561 | //函数表达式(比如sqrt(100))设置到preStep,所以不需要再次设置si 562 | //第三种就是如果最后一位是右括号,那么也不需要设置si 563 | cal.setPreStep(cal.getPreStep() + ((cal.isPreInputUnaryOperator || pi.charAt(pi.length - 1) === ")") ? 564 | (" " + facade) : (" " + si + " " + facade))); 565 | var preOp = cal.operatorStack.pop(); 566 | if (preOp != null) { 567 | var op = cal.operatorPriority[operator], 568 | pp = cal.operatorPriority[preOp]; 569 | //如果当前运算符优先级更高,那么只需压栈不需要计算 570 | if (op > pp) { 571 | cal.operatorStack.push(preOp); 572 | } 573 | //两者的优先级相等并且高于3(加减),那么只需要计算一步 574 | else if (op > 3 && op === pp) { 575 | cal.operatorStack.push(preOp); 576 | cal.travelStack(1); 577 | } else { 578 | cal.operatorStack.push(preOp); 579 | cal.setShowInput(cal.checkLength(cal.travelStack(null, op))); 580 | } 581 | } 582 | cal.operatorStack.push(operator); 583 | } 584 | cal.isPreInputUnaryOperator = false; 585 | cal.isPreInputEquals = false; 586 | }, 587 | /** 588 | * 按下=时计算最终结果 589 | */ 590 | calculate: function () { 591 | if (!cal.isPreInputEquals) { 592 | var si = cal.getShowInput(), 593 | result; 594 | if (cal.isNumber(si)) { 595 | cal.operandStack.push(si); 596 | result = cal.checkLength(cal.travelStack()); 597 | cal.setShowInput(result); 598 | cal.preResult = result; 599 | cal.setPreStep(" "); 600 | //程序员型需要把计算结果的四种进制值显示出来 601 | if (cal.type === 3) { 602 | cal.showScales(result); 603 | } 604 | cal.isOverride = true; 605 | } 606 | cal._reset(); 607 | cal.isPreInputEquals = true; 608 | } 609 | }, 610 | /** 611 | * 访问运算栈,返回计算结果 612 | * @param level 计算的层数,如果不指定,那么遍历整个栈 613 | * @param minPri(最小/截止优先级) 此参数针对下面的情况: 614 | * 2 + 2 X 3 X 2 ^ 2 X 2,由于最后一个运算符是X,优先级比^低,所以触发了对操作栈的遍历,但是不能全部遍历,应该遍历到第一个X停止 615 | * 如果不停止得到的将是错误的26 X 2 = 52,正确结果是2 + 24 X 2 = 50 616 | * @return Number 617 | * @private 618 | */ 619 | travelStack: function (level, minPri) { 620 | var op, f, s, 621 | //result取操作数栈栈顶,因为防止在下列情况9 X (6 + 时出现undefined 622 | result = cal.operandStack[cal.operandStack.length - 1], 623 | l = level || cal.operatorStack.length, 624 | p = minPri || 0; 625 | for (var i = 0; i < l; ++i) { 626 | op = cal.operatorStack.pop(); 627 | //遇到minPri或左括号立即停止,左括号也需要再次压入,因为只有一个右括号才能抵消一个左括号 628 | if (cal.operatorPriority[op] < p || op === "(") { 629 | cal.operatorStack.push(op); 630 | break; 631 | } 632 | s = cal.operandStack.pop(); 633 | f = cal.operandStack.pop(); 634 | result = cal._stackHelper(f, s, op); 635 | cal.operandStack.push(result); 636 | } 637 | return result; 638 | }, 639 | /** 640 | * 输入了一个右括号 641 | */ 642 | rightTag: function () { 643 | var si = cal.getShowInput(); 644 | if (cal.isNumber(si)) { 645 | cal.setPreStep(cal.getPreStep() + (" " + si + " )")); 646 | cal.operandStack.push(si); 647 | //遍历计算操作栈,直至遇到左括号 648 | var op = cal.operatorStack.pop(), 649 | f, s, result; 650 | while (op !== "(" && op != null) { 651 | s = cal.operandStack.pop(); 652 | f = cal.operandStack.pop(); 653 | result = cal._stackHelper(f, s, op); 654 | cal.operandStack.push(result); 655 | op = cal.operatorStack.pop(); 656 | } 657 | //此处应该直接把小括号的计算内容弹出,因为此结果显示在了showInput中,而再次执行二元操作时会先有一个压栈的操作, 658 | // 并且执行=时也是根据showInput内容计算的 659 | cal.setShowInput(cal.checkLength(cal.operandStack.pop())); 660 | } 661 | }, 662 | /** 663 | * 辅助进行一次栈运算 664 | * @param f 第一个操作数 665 | * @param s 第二个操作数 666 | * @param op 运算符 667 | * @return 返回运算结果 668 | * @private 669 | */ 670 | _stackHelper: function (f, s, op) { 671 | var result; 672 | if (op === "^") { 673 | result = Math.pow(f, s); 674 | } else if (op === "yroot") { 675 | result = Math.pow(f, 1 / s); 676 | } 677 | //+ - X / %5中操作 678 | else { 679 | //如果是程序员型,那么需要考虑进制的问题 680 | if (cal.type === 3) { 681 | var scale = cal.currentScale, 682 | fi, si; 683 | if (scale === 10) { 684 | result = eval(f + op + s); 685 | } else if (scale === 16) { 686 | fi = parseInt(f, 16); 687 | si = parseInt(s, 16); 688 | result = eval(fi + op + si).toString(16); 689 | } else if (scale === 8) { 690 | fi = parseInt(f, 8); 691 | si = parseInt(s, 8); 692 | result = eval(fi + op + si).toString(8); 693 | } else { 694 | fi = parseInt(f, 2); 695 | si = parseInt(s, 2); 696 | result = eval(fi + op + si).toString(2); 697 | } 698 | } else { 699 | result = eval(f + op + s); 700 | } 701 | } 702 | return result; 703 | }, 704 | /** 705 | * 确保结果长度不大于13,如果超出,以科学计数法形式显示(小数点后7位) 706 | * @param value 需要检查的结果 707 | */ 708 | checkLength: function (value) { 709 | var valueStr = value + ""; 710 | if (cal.isFloat(valueStr)) { 711 | valueStr = valueStr.replace(/0+$/, ""); 712 | } 713 | return valueStr.length > 12 ? value.toExponential(7) : valueStr; 714 | }, 715 | //CE 716 | ce: function () { 717 | cal.setShowInput("0"); 718 | if (cal.type === 3) { 719 | cal.resetScales(); 720 | } 721 | }, 722 | //C 723 | clear: function () { 724 | cal.setShowInput("0"); 725 | cal.setPreStep(" "); 726 | cal._reset(); 727 | if (cal.type === 3) { 728 | cal.resetScales(); 729 | } 730 | }, 731 | /** 732 | * 清空四个进制的值 733 | * @private 734 | */ 735 | resetScales: function () { 736 | for (var i = 0; i < 4; i++) { 737 | cal.cache.scaleSpans[i].innerHTML = "0"; 738 | } 739 | }, 740 | back: function () { 741 | var oldValue = cal.cache.showInput.innerText; 742 | cal.setShowInput(oldValue.length < 2 ? "0" : oldValue.substring(0, oldValue.length - 1)); 743 | }, 744 | /** 745 | * 当计算器类型是程序员时,需要同步显示四种进制的值 746 | * @param num 需要显示的数字 747 | */ 748 | showScales: function (num) { 749 | var result = cal.calculateScales(num), 750 | spans = cal.cache.scaleSpans; 751 | for (var i = 0; i < 4; ++i) { 752 | spans[i].innerHTML = result[i]; 753 | } 754 | }, 755 | /** 756 | * 根据当前进制分别计算出四种进制的值 757 | * @param num 需要计算的值 758 | * @return Array 共4个元素,依次为16、10、8、2进制的值 759 | */ 760 | calculateScales: function (num) { 761 | var scale = cal.currentScale, 762 | result = [], 763 | i; 764 | if (scale === 10) { 765 | i = parseInt(num); 766 | result[0] = i.toString(16); 767 | result[1] = i; 768 | result[2] = i.toString(8); 769 | result[3] = i.toString(2); 770 | } else if (scale === 16) { 771 | //先转成10进制,然后再转成其它进制 772 | i = parseInt(num, 16); 773 | result[0] = num; 774 | result[1] = i; 775 | result[2] = i.toString(8); 776 | result[3] = i.toString(2); 777 | } else if (scale === 8) { 778 | i = parseInt(num, 8); 779 | result[0] = i.toString(16); 780 | result[1] = i; 781 | result[2] = num; 782 | result[3] = i.toString(2); 783 | } else { 784 | i = parseInt(num, 2); 785 | result[0] = i.toString(16); 786 | result[1] = i; 787 | result[2] = i.toString(8); 788 | result[3] = num; 789 | } 790 | return result; 791 | }, 792 | /** 793 | * 校验字符串是否是数字 794 | * @param str 795 | * @return 是返回true 796 | */ 797 | isNumber: function (str) { 798 | return cal.isInteger(str) || cal.isFloat(str) || cal.isScientific(str) || cal.isHex(str); 799 | }, 800 | /** 801 | * 校验是否是整数 802 | * @param str 803 | */ 804 | isInteger: function (str) { 805 | return str.match(cal.intPattern); 806 | }, 807 | /** 808 | * 校验是否是小数 809 | * @param str 810 | */ 811 | isFloat: function (str) { 812 | return str.match(cal.floatPattern); 813 | }, 814 | /** 815 | * 是否是科学计数法 816 | * @param str 817 | */ 818 | isScientific: function (str) { 819 | return str.match(cal.scientificPattern); 820 | }, 821 | /** 822 | * 是否是16进制数字 823 | * @param str 824 | */ 825 | isHex: function (str) { 826 | return str.match(cal.hexPattern); 827 | }, 828 | /** 829 | * 显示输入的内容 830 | * 用于相应数字/小数点按键 831 | * @param value 按键的内容,不是keyCode 832 | */ 833 | showInput: function (value) { 834 | var oldValue = cal.getShowInput(); 835 | var newValue = oldValue; 836 | if (cal.isOverride) { 837 | //既然是覆盖,那么如果直接输入.那么肯定是0.x 838 | if (value === ".") { 839 | newValue = "0."; 840 | } else { 841 | newValue = value; 842 | } 843 | } else if (oldValue.length < 13) { 844 | if (oldValue === "0") { 845 | if (value === ".") { 846 | newValue = "0."; 847 | } else { 848 | newValue = value; 849 | } 850 | } else { 851 | newValue += value; 852 | } 853 | } 854 | cal.setShowInput(newValue); 855 | cal.isOverride = false; 856 | cal.isPreInputBinaryOperator = false; 857 | cal.isPreInputUnaryOperator = false; 858 | cal.isPreInputEquals = false; 859 | }, 860 | /** 861 | * 切换计算器类型 862 | * @param type int 要切换到的类型 863 | */ 864 | switchType: function (type) { 865 | //关闭选择栏 866 | var oldPrefix = cal.typePrefix[cal.type]; 867 | document.getElementById(oldPrefix + "type-bar").style.display = "none"; 868 | //切换面板 869 | document.getElementById(oldPrefix + "main").style.display = "none"; 870 | document.getElementById(cal.typePrefix[type] + "main").style.display = "block"; 871 | cal.type = type; 872 | if (!cal.hasInited[type]) { 873 | cal.initListeners(); 874 | cal.hasInited[type] = true; 875 | } 876 | cal.initCache(); 877 | cal._reset(); 878 | }, 879 | /** 880 | * 重置各个标志变量以及操作栈 881 | * @private 882 | */ 883 | _reset: function () { 884 | cal.operandStack = []; 885 | cal.operatorStack = []; 886 | cal.isPreInputBinaryOperator = false; 887 | cal.isPreInputUnaryOperator = false; 888 | cal.isPreInputEquals = false; 889 | }, 890 | /** 891 | * 工具方法,为element添加事件处理函数 892 | * @param element 需要添加事件的dom元素 893 | * @param name name事件名称(不含on) 894 | * @param handler 事件处理函数 895 | */ 896 | addEvent: function (element, name, handler) { 897 | if (window.addEventListener) { 898 | element.addEventListener(name, handler); 899 | } else if (window.attachEvent) { 900 | element.attachEvent("on" + name, handler); 901 | } 902 | }, 903 | /** 904 | * 工具方法,为element移除特定的事件监听 905 | * @param element 需要移除事件监听的dom元素 906 | * @param name 事件名,没有"on" 907 | * @param handler 需要移除的处理函数 908 | */ 909 | removeEvent: function (element, name, handler) { 910 | if (window.removeEventListener) { 911 | element.removeEventListener(name, handler); 912 | } else if (window.detachEvent) { 913 | element.detachEvent("on" + name, handler); 914 | } 915 | }, 916 | /** 917 | * 根据元素的属性进行查找,只要存在此属性即可 918 | * @param tag 目标标签名 919 | * @param attr 920 | * @param root 开始查找的起始节点,可选,默认document 921 | */ 922 | getElementsByAttribute: function (tag, attr, root) { 923 | var parent = root || document, 924 | result = []; 925 | var arr = parent.getElementsByTagName(tag), 926 | a; 927 | for (var i = 0, l = arr.length; i < l; ++i) { 928 | a = arr[i]; 929 | if (a.getAttribute(attr) != null) { 930 | //这个写法... 931 | result[result.length] = a; 932 | } 933 | } 934 | return result; 935 | }, 936 | /** 937 | * 阶乘 938 | * @param n 操作数 int 939 | * @return 940 | */ 941 | fact: (function () { 942 | //缓存 943 | var cache = [1]; 944 | 945 | function factorial(n) { 946 | var result = cache[n - 1]; 947 | if (result == null) { 948 | result = 1; 949 | for (var i = 1; i <= n; ++i) { 950 | result *= i; 951 | } 952 | cache[n - 1] = result; 953 | } 954 | return result; 955 | } 956 | return factorial; 957 | })(), 958 | /** 959 | * 禁用按键,只有程序员型才会用到 960 | * @param lis 按钮集合 961 | * @param mouseOutListener function 鼠标移出时采用哪个监听函数,取决于按钮的位置(上排/下排) 962 | */ 963 | disableButtons: function (lis, mouseOutListener) { 964 | var li; 965 | for (var i = 0, l = lis.length; i < l; ++i) { 966 | li = lis[i]; 967 | li.setAttribute("class", "disable-btn"); 968 | cal.removeEvent(li, "click", cal.listeners.keyPressListener); 969 | cal.removeEvent(li, "mouseout", mouseOutListener); 970 | cal.removeEvent(li, "mouseover", cal.listeners.mouseHoverListener); 971 | } 972 | }, 973 | /** 974 | * 重新设置按键 975 | * @param lis 按钮集合 976 | * @param mouseOutListener function 鼠标移出时采用哪个监听函数,取决于按钮的位置(上排/下排) 977 | */ 978 | rebuildButtons: function (lis, mouseOutListener) { 979 | var li; 980 | for (var i = 0, l = lis.length; i < l; ++i) { 981 | li = lis[i]; 982 | li.removeAttribute("class"); 983 | cal.addEvent(li, "click", cal.listeners.keyPressListener); 984 | cal.addEvent(li, "mouseout", mouseOutListener); 985 | cal.addEvent(li, "mouseover", cal.listeners.mouseHoverListener); 986 | } 987 | } 988 | }; 989 | return cal; 990 | })(); -------------------------------------------------------------------------------- /screenshots/programmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/screenshots/programmer.png -------------------------------------------------------------------------------- /screenshots/science.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/screenshots/science.png -------------------------------------------------------------------------------- /screenshots/standard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/js_calculator/c9aea84a6d7d0ed89f8c974a891f6490dacbdbb3/screenshots/standard.png --------------------------------------------------------------------------------