1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>javascript高级语法21-命令模式</title>
6 </head>
7 <body>
8 <input type="text" id="flow" />
9 <input type="button" id="" value="添加新流程" onclick="API.addFlow()" /><br>
10 <input type="button" value="回退" onclick="API.re()" />
11 <input type="button" value="重做" onclick="API.again()" />
12 <div id="div01"></div>
13
14 <script id="uuid.js">
15 //生成uuid的轮子
16 /*
17 uuid.js - Version 0.2
18 JavaScript Class to create a UUID like identifier
19 */
20
21 // On creation of a UUID object, set it's initial value
22 function UUID(){
23 this.id = this.createUUID();
24 }
25 // When asked what this Object is, lie and return it's value
26 UUID.prototype.valueOf = function(){ return this.id; }
27 UUID.prototype.toString = function(){ return this.id; }
28 UUID.prototype.createUUID = function(){
29 var dg = new Date(1582, 10, 15, 0, 0, 0, 0);
30 var dc = new Date();
31 var t = dc.getTime() - dg.getTime();
32 var h = '-';
33 var tl = UUID.getIntegerBits(t,0,31);
34 var tm = UUID.getIntegerBits(t,32,47);
35 var thv = UUID.getIntegerBits(t,48,59) + '1'; // version 1, security version is 2
36 var csar = UUID.getIntegerBits(UUID.rand(4095),0,7);
37 var csl = UUID.getIntegerBits(UUID.rand(4095),0,7);
38 var n = UUID.getIntegerBits(UUID.rand(8191),0,7) +
39 UUID.getIntegerBits(UUID.rand(8191),8,15) +
40 UUID.getIntegerBits(UUID.rand(8191),0,7) +
41 UUID.getIntegerBits(UUID.rand(8191),8,15) +
42 UUID.getIntegerBits(UUID.rand(8191),0,15); // this last number is two octets long
43 return tl + h + tm + h + thv + h + csar + csl + h + n;
44 }
45
46 UUID.getIntegerBits = function(val,start,end){
47 var base16 = UUID.returnBase(val,16);
48 var quadArray = new Array();
49 var quadString = '';
50 var i = 0;
51 for(i=0;i<base16.length;i++){
52 quadArray.push(base16.substring(i,i+1));
53 }
54 for(i=Math.floor(start/4);i<=Math.floor(end/4);i++){
55 if(!quadArray[i] || quadArray[i] == '') quadString += '0';
56 else quadString += quadArray[i];
57 }
58 return quadString;
59 }
60
61 UUID.returnBase = function(number, base){
62
63 var convert = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
64 if (number < base) var output = convert[number];
65 else {
66 var MSD = '' + Math.floor(number / base);
67 var LSD = number - MSD*base;
68 if (MSD >= base) var output = this.returnBase(MSD,base) + convert[LSD];
69 else var output = convert[MSD] + convert[LSD];
70 }
71 return output;
72 }
73 UUID.rand = function(max){
74 return Math.floor(Math.random() * max);
75 }
76
77 </script>
78 <script id="keymaster.js">
79 //获取键盘事件的轮子
80 (function(a) {
81 function h(a, b) {
82 var c = a.length;
83 while (c--) if (a[c] === b) return c;
84 return -1
85 }
86 function i(a) {
87 var b, g, i, j, k;
88 b = a.keyCode;
89 if (b == 93 || b == 224) b = 91;
90 if (b in d) {
91 d[b] = !0;
92 for (i in f) f[i] == b && (l[i] = !0);
93 return
94 }
95 if (!l.filter.call(this, a)) return;
96 if (!(b in c)) return;
97 for (j = 0; j < c[b].length; j++) {
98 g = c[b][j];
99 if (g.scope == e || g.scope == "all") {
100 k = g.mods.length > 0;
101 for (i in d) if (!d[i] && h(g.mods, +i) > -1 || d[i] && h(g.mods, +i) == -1) k = !1;
102 (g.mods.length == 0 && !d[16] && !d[18] && !d[17] && !d[91] || k) && g.method(a, g) === !1 && (a.preventDefault ? a.preventDefault() : a.returnValue = !1, a.stopPropagation && a.stopPropagation(), a.cancelBubble && (a.cancelBubble = !0))
103 }
104 }
105 }
106 function j(a) {
107 var b = a.keyCode,
108 c;
109 if (b == 93 || b == 224) b = 91;
110 if (b in d) {
111 d[b] = !1;
112 for (c in f) f[c] == b && (l[c] = !1)
113 }
114 }
115 function k() {
116 for (b in d) d[b] = !1;
117 for (b in f) l[b] = !1
118 }
119 function l(a, b, d) {
120 var e, h, i, j;
121 d === undefined && (d = b, b = "all"), a = a.replace(/\s/g, ""), e = a.split(","), e[e.length - 1] == "" && (e[e.length - 2] += ",");
122 for (i = 0; i < e.length; i++) {
123 h = [], a = e[i].split("+");
124 if (a.length > 1) {
125 h = a.slice(0, a.length - 1);
126 for (j = 0; j < h.length; j++) h[j] = f[h[j]];
127 a = [a[a.length - 1]]
128 }
129 a = a[0], a = g[a] || a.toUpperCase().charCodeAt(0), a in c || (c[a] = []), c[a].push({
130 shortcut: e[i],
131 scope: b,
132 method: d,
133 key: e[i],
134 mods: h
135 })
136 }
137 }
138 function m(a) {
139 var b = (a.target || a.srcElement).tagName;
140 return b != "INPUT" && b != "SELECT" && b != "TEXTAREA"
141 }
142 function n(a) {
143 e = a || "all"
144 }
145 function o() {
146 return e || "all"
147 }
148 function p(a) {
149 var b, d, e;
150 for (b in c) {
151 d = c[b];
152 for (e = 0; e < d.length;) d[e].scope === a ? d.splice(e, 1) : e++
153 }
154 }
155 function q(a, b, c) {
156 a.addEventListener ? a.addEventListener(b, c, !1) : a.attachEvent && a.attachEvent("on" + b, function() {
157 c(window.event)
158 })
159 }
160 var b, c = {},
161 d = {
162 16: !1,
163 18: !1,
164 17: !1,
165 91: !1
166 },
167 e = "all",
168 f = {
169 "⇧": 16,
170 shift: 16,
171 "⌥": 18,
172 alt: 18,
173 option: 18,
174 "⌃": 17,
175 ctrl: 17,
176 control: 17,
177 "⌘": 91,
178 command: 91
179 },
180 g = {
181 backspace: 8,
182 tab: 9,
183 clear: 12,
184 enter: 13,
185 "return": 13,
186 esc: 27,
187 escape: 27,
188 space: 32,
189 left: 37,
190 up: 38,
191 right: 39,
192 down: 40,
193 del: 46,
194 "delete": 46,
195 home: 36,
196 end: 35,
197 pageup: 33,
198 pagedown: 34,
199 ",": 188,
200 ".": 190,
201 "/": 191,
202 "`": 192,
203 "-": 189,
204 "=": 187,
205 ";": 186,
206 "'": 222,
207 "[": 219,
208 "]": 221,
209 "\\": 220
210 };
211 for (b = 1; b < 20; b++) f["f" + b] = 111 + b;
212 for (b in f) l[b] = !1;
213 q(document, "keydown", i), q(document, "keyup", j), q(window, "focus", k), a.key = l, a.key.setScope = n, a.key.getScope = o, a.key.deleteScope = p, a.key.filter = m, typeof module != "undefined" && (module.exports = key)
214 })(this);
215 </script>
216 <script>
217 /*命令模式:
218 * 用于消除调用者和接收者之间的耦合的模式
219 * 并且可以对(调用这个过程进行留痕操作)
220 * 不能乱用这个模式,它会使简单调用的写法变得非常复杂和难以理解
221 * 当你的业务出现了回退操作,重做操作等需求的时候考虑用这个模式
222 */
223 /*需求:
224 有一个添加流程的按钮,单机的时候添加一个新的文本当做流程的描述
225 有返回 重做两个按钮,完成相应任务。
226 */
227 function manager(){
228 this.addFlow = function(id,text){
229 //1.得到目标节点
230 var div = document.getElementById("div01");
231 var newFlow = document.createElement("div");
232 newFlow.setAttribute("id",id);
233 newFlow.innerHTML = text;
234 div.appendChild(newFlow);
235 }
236 }
237 //为对象建立命令访问库
238 manager.prototype.excute = (function(){
239 //命令对象
240 return function(command){
241 return this[command.method](command.id,command.value)
242 }
243 })()
244 //初始化主类
245 var ma = new manager();
246 //用于存储调用对象命令的集合。
247 var commands = new Array();
248 //集合的游标
249 var index = commands.length;
250 //客户端
251
252 var API = function(){
253 this.addFlow = function(){
254 //把调用封装起来
255 var command = {
256 method:"addFlow",
257 id:new UUID().createUUID(),
258 value:document.getElementById("flow").value,
259 }
260 //把调用对象保存起来,用于回退和重做
261 commands.push(command);
262 //重新定位游标
263 index = commands.length;
264 //调用
265 ma.excute(command);
266
267 }
268 //返回
269 this.re = function(){
270 if(index-1<0){
271 alert("已经到最后一步了!")
272 }else{
273 all = document.getElementById("div01").childNodes;
274 document.getElementById("div01").removeChild(all[all.length-1]);
275 index = index - 1;
276 }
277 }
278 //重做
279 this.again = function(){
280 if(index>=commands.length){
281 alert("已经到了最新一步了,不能继续重做了!")
282 }else{
283 var command = commands[index];
284 ma.excute(command);
285 index = index + 1;
286 }
287 }
288 }
289 //实例化api
290 var API = new API();
291
292 //添加支持键盘事件
293 key("ctrl+z",function(){
294 API.re();
295 })
296 key("ctrl+shift+z",function(){
297 API.again();
298 })
299 </script>
300 </body>
301 </html>