视频下载 网友评价 课程大纲 报名咨询

使用javascript模拟观察者模式和事件监听广播机制[本杰首发]

[ 215 查看 / 0 回复 ]

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <title>使用javascript模拟观察者模式和事件监听广播机制 - 作者:张波 [email]zhangbo99@gmail.com[/email]</title>
  5.     <style type="text/css">
  6.         div.box
  7.         {
  8.             float: left;
  9.             width: 300px;
  10.             border: solid 2px blue;
  11.             height: 50px;
  12.             margin-right: 5px;
  13.         }
  14.         #txt
  15.         {
  16.             display: block;
  17.         }
  18.     </style>
  19.     <script type="text/javascript">
  20.         //张波
  21.         //Email:zhangbo99@gmail.com

  22.         //观察者模式的主题
  23.         function ObserverSubject(id)
  24.         {
  25.             this.ID = id; //实例的ID
  26.             this._Listeners = new Array(); //存储当前所有监听器
  27.             this.AddListener = function (listener)//添加新的监听器
  28.             {
  29.                 this._Listeners.push(listener); //监听器加入数组
  30.             };
  31.             this.RemoveListener = function (listener, RemovingCallBack, RemovedCallback) //删除特定监听器,传入删除前回调委托和删除后回调委托
  32.             {
  33.                 for (var i in this._Listeners) {//遍历当前所有监听器
  34.                     if (this._Listeners[i] == listener) { //如果存在要删除的监听器
  35.                         if (RemovingCallBack != undefined && typeof (RemovingCallBack) == "function") {//如果有传入删除前回调委托
  36.                             var removingEventArgs = { Cancel: false }; //定义回调委托参数
  37.                             RemovingCallBack(listener, removingEventArgs); //调用删除前回调委托
  38.                             if (!removingEventArgs.Cancel) {//如果在删除前回调委托中没有取消删除操作
  39.                                 this._Listeners.splice(i, 1); //从当前数组中删除监听器
  40.                                 if (RemovedCallback != undefined && typeof (RemovedCallback) == "function") { //如果有传入删除后回调委托
  41.                                     RemovedCallback(listener, i); //调用删除后回调委托
  42.                                 }
  43.                             }
  44.                         }
  45.                         break; //已找到要删除的监听器,后面的不需要再遍历
  46.                     }
  47.                 }
  48.             };

  49.             this.ClearListeners = function (ClearingCallBack, ClearedCallBack)//清空所有监听器,传入清空前回调委托和清空后回调委托
  50.             {
  51.                 if (ClearingCallBack != undefined && typeof (ClearingCallBack) == "function") {//如果有传入删除前回调委托
  52.                     var args = { ListenersCount: this._Listeners.length, Cancel: false }; //定义回调委托参数,ListenersCount:当前要清空多少监听器,Cancel:是否取消操作
  53.                     ClearingCallBack(this, args); //调用清空前回调委托
  54.                     if (!args.Cancel) {//如果在清空前回调委托中没有取消清空操作
  55.                         this._Listeners.length = 0; //清空当前数组中所有元素(监听器)
  56.                         if (ClearedCallBack != undefined && typeof (ClearedCallBack) == "function") {//如果有传入删除后回调委托
  57.                             ClearedCallBack(); //调用清空后的回调委托,这里没有再传额外参数
  58.                         }
  59.                     }
  60.                 }
  61.             };

  62.             this.EventBroadcast = function (args)//激发事件,实现广播通知(Notify)所有监听器
  63.             {
  64.                 for (var i in this._Listeners) {//遍历当前所有监听器
  65.                     var listener = this._Listeners[i]; //单独取出当前的监听器
  66.                     listener(args); //调用监听器(函数,委托),args参数原样传递(推给监听器)
  67.                 }
  68.             };
  69.         };

  70.         var observer = new ObserverSubject("textElementSubject"); //定义一个可供监听的主题(Subject),以演示使用效果

  71.         //以下定义第1个监听器,在div1中显示,干净格式
  72.         var listener1 = function (args)
  73.         {
  74.             document.getElementById("div1").innerHTML = "第1个Listener收到消息:" + args;
  75.         };
  76.         //以下定义第2个监听器,在div2中显示,删除线格式
  77.         var listener2 = function (args)
  78.         {
  79.             document.getElementById("div2").innerHTML = ("第2个Listener收到消息:" + args).strike();
  80.         };
  81.         //以下定义第3个监听器,在div3中显示,斜体格式
  82.         var listener3 = function (args)
  83.         {
  84.             document.getElementById("div3").innerHTML = ("第3个Listener收到消息:" + args).italics();
  85.         };
  86.         //以下定义第4个监听器,在div4中显示,粗体格式
  87.         var listener4 = function (args)
  88.         {
  89.             document.getElementById("div4").innerHTML = ("第4个Listener收到消息:" + args).bold();
  90.         };

  91.         window.onload = function ()//页面初始化
  92.         {
  93.             observer.AddListener(listener1); //向Subject注册第1个监听器(委托)
  94.             observer.AddListener(listener2); //向Subject注册第2个监听器(委托)
  95.             observer.AddListener(listener3); //向Subject注册第3个监听器(委托)
  96.             observer.AddListener(listener4); //向Subject注册第4个监听器(委托)
  97.             observer.AddListener(function (args)//向Subject注册匿名监听器(委托)
  98.             {
  99.                 //alert("通过alert显示收到的消息:" + args);//监听器处理使用alert处理
  100.             });
  101.             observer.AddListener(function (args)//向Subject注册匿名监听器(委托)
  102.             {
  103.                 document.title = "在标题栏中显示收到的消息:" + args; //监听器处理使用标题栏处理
  104.             });
  105.             observer.AddListener(function (args)//向Subject注册匿名监听器(委托)
  106.             {
  107.                 window.status = "在状态栏中显示收到的消息:" + args; //监听器处理使用状态栏处理
  108.             });
  109.             document.getElementById("txt").onkeyup = function ()//为txt元素注册keyup事件处理程序,这里的txt元素是实际的Subject
  110.             {
  111.                 observer.EventBroadcast(this.value); //激发Subject(observer变量)的事件,由其通知所有监听器,实现广播;
  112.             };
  113.         };

  114.         function Add()//为Subject注册第3个监听器:listener3
  115.         {
  116.             observer.AddListener(listener3);
  117.         }

  118.         function Remove()//为Subject删除第3个监听器:listener3
  119.         {
  120.             observer.RemoveListener(listener3, function (sender, args)//调用删除方法,并传入要删除的委托实例(监听器),和匿名委托作为RemovingCallBack参数
  121.             {
  122.                 args.Cancel = !confirm("将要删除监听委托:\r\n" + sender + "\r\n确定吗?"); //让用户确认是否要删除
  123.             }, function (listener, indexInArray)//传入匿名委托作为RemovedCallBack参数
  124.             {
  125.                 document.getElementById("div3").innerHTML = listener + "<br/>已删除,<br/>它在Observer中的索引为:" + indexInArray; //显示删除后的结果和参数
  126.             });
  127.         }

  128.         function Clear()//清空所有已经注册的监听器
  129.         {
  130.             observer.ClearListeners(function (sender, args)//第一个参数为匿名委托,作为ClearingCallBack参数
  131.             {
  132.                 alert("来自:" + sender.ID + "的确认消息:将要清空的Listener共:" + args.ListenersCount + "个"); //显示事件参数中的数组
  133.                 args.Cancel = !confirm("是否确定要清空?"); //把用户确认的结果反馈到事件参数中
  134.             }, function ()//第二个参数为匿名委托,作为ClearedCallBack参数
  135.             {
  136.                 //以下遍历所有div,用box样式来筛选,并清空这些div的内容
  137.                 var divs = document.getElementsByTagName("div");
  138.                 for (var i in divs) {
  139.                     if (divs[i].className == "box") {
  140.                         divs[i].innerHTML = "";
  141.                     }
  142.                 }
  143.                 window.status = "已清空"; //状态栏刷新
  144.                 document.title = "已清空"; //标题栏刷新
  145.             });
  146.         }
  147.     </script>
  148. </head>
  149. <body>
  150.     <input type="text" id="txt" />
  151.     <div id="div1" class="box">
  152.     </div>
  153.     <div id="div2" class="box">
  154.     </div>
  155.     <div id="div3" class="box">
  156.     </div>
  157.     <div id="div4" class="box">
  158.     </div>
  159.     <input type="button" id="btnAdd" value="添加第3个Listener" onclick="Add();" />
  160.     <input type="button" id="btnRemove" value="移除第3个Listener" onclick="Remove();" />
  161.     <input type="button" id="btnClear" value="移除所有Listener" onclick="Clear();" />
  162.     <%--这是最后一行,感谢您完整阅读了这篇代码--%>
  163. </body>
  164. </html>
复制代码
TOP