js自定义消息机制研究学习(一) ——看百度搜索输入提示

之前有一次为了做一个类似于谷歌、百度的输入提示,扒了百度的代码(现在的地址http://www.baidu.com/js/bdsug.js?v=1.0.3.0,格式化一下再看)研究了一番,发现百度的消息机制简洁有效,之后根据它写了一套自己的消息机制,应用在其后的一个web ajax聊天程序中。之后和朋友讨论后,完善了一下,做了一个类似于event的事件机制(在普通object上模拟dom事件的自定义事件),现在基于类似的机制应用到了目前的ERP项目中实现了一套js插件机制、iframe通信机制等等(我很惭愧,太懒了,没有学习使用现成的js框架,自己又造了个轮子),现在勤劳一下,拿出来让大家乐呵乐呵,本人主攻后台开发,js只是业余爱好,欢迎指正。



先说说百度的代码,核心的东西,如下:

var J = (function(){
        function C(b){
            var Z = this.__MSG_QS__;
            if (!Z[b]) {
                Z[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
                Z[b].push(arguments[a])
            }
        }
        function G(Y){
            var Z = this.__MSG_QS__[Y.type];
            if (Z == null) {
                return
            }
            for (var a = 0, X = Z.length; a < X; a++) {
                Z[a].rm(Y)
            }
        }
        return {
            ini: function(X){
                X.__MSG_QS__ = {};
                X.on = C;
                X.dm = G;
                return X
            }
        }
    })();



代码是经过压缩处理的,我比较懒,不乱猜测其原名了。

这算是一个很轻量级的消息机制,执行这段代码,获得了J这个对象,可以从代码看出J={ini:function(){……}}



研究一下ini的函数:

function(X){
                X.__MSG_QS__ = {};
                X.on = C;
                X.dm = G;
                return X
            }


它的作用就是为一个对象绑定 :

一个属性__MSG_QS__

两个函数on(=C),dm(=G)

__MSG_QS__的作用是来存储消息队列,它是一个json对象,所以可以存储多个消息队列类似于这样的格式{"click":[],"blur":[]}


on就是增加监听者

function C(b){
            var Z = this.__MSG_QS__;
            if (!Z[b]) {
                Z[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
                Z[b].push(arguments[a])
            }
        }


负责将监听消息的对象加入__MSG_QS__中


dm是触发消息的

function G(Y){
            var Z = this.__MSG_QS__[Y.type];
            if (Z == null) {
                return
            }
            for (var a = 0, X = Z.length; a < X; a++) {
                Z[a].rm(Y)
            }
        }


如果消息侦听队列存在,dm会循环调用监听者的rm函数




写一个简单的示例:

var dataLayer = J.ini({
    getData: function(){
       this.dm({type:"data",data:1})
    }
})

var controlLayer=J.ini({
    rm:function(Y)
    {
         switch(Y.type)
         {
             case "data":
                Y.data++;
                this.dm({type:"show",data:Y.data});
         }
    }
})

var viewLayer=J.ini({
    rm:function(Y)
    {
        switch(Y.type)
         {
             case "show":
                alert(Y.data);
         }
    }    
});
dataLayer.on("data",controlLayer);
controlLayer.on("show",viewLayer);
dataLayer.getData();


dataLayer.getData()会产生一个数据(可以想象是服务器传回的),并触发“data”消息

controlLayer对象收到后,处理数据(+1),然后触发“show“消息

viewLayer对象收到后,只是简单将数据弹出




这只是简单的一个示例,你可以把dataLayer,controlLayer,viewLayer当做是独立的js文件(模块),代码

dataLayer.on("data",controlLayer);
controlLayer.on("show",viewLayer);
dataLayer.getData();


看做是在页面中(或某个main.js)中,那么这些模块之间就很容易的实现消息传递,并且它是低耦合的




举个例子,比如我们不喜欢alert,希望它在页面元素中显示,那么增加一个模块代码:

var viewLayer1=J.ini({
    rm:function(Y)
    {
        switch(Y.type)
         {
             case "show":
                document.getElementById("show").innerHTML=Y.data;
         }
    }    
});

修改一下所谓main.js,如下

dataLayer.on("data",controlLayer);
controlLayer.on("show",viewLayer1);
dataLayer.getData();

是不是很灵活,dataLayer,controlLayer的代码完全不用修改(假设它们是独立的js文件,或很多个相关js文件,或者很长很长的一段代码,你会感到很高兴)




消息机制的另外一个特点,多播,比如需求改了,要求又要有alert,又要在页面显示,这下你会更高兴,修改一下代码


dataLayer.on("data",controlLayer);
controlLayer.on("show",viewLayer,viewLayer1);
dataLayer.getData();




消息也可以有很多的源头,例如:

var dataLayer1 = J.ini({
    getData: function(){
       this.dm({type:"data",data:10})
    }
})

//************省略

dataLayer.on("data",controlLayer);
dataLayer1.on("data",controlLayer);
controlLayer.on("show",viewLayer,viewLayer1);
dataLayer.getData();
dataLayer1.getData();


从这些示例,我们可以看出消息机制的灵活性


具体的原理可以参考观察者模式。

所谓消息,或者也可以称之为事件,基本的思想就是,当对象发生变化的时候,就通知关注这个变化的对象,微博很流行,关注这个词相信大家应该不陌生。

概况一下消息的几个概念:

1. 关注(也可以说是监听)

2. 消息,是我们的数据,也是信息载体。它包含一些我们关注的信息。

3. 触发消息,把数据打包成一个消息,然后发送给每一位关注者

4. 接受并处理消息

举个例子

假设我们现在有两个对象her(一位美女),一个me(偶了),这位美女经常发个图、说说话什么的, me现在要关注她,就得使用她页面上关注功能(on),可是你不想关注她说什么,只想看看她的美图

就是她发美图了,me就会收到。怎么实现?

首先使用her.on("pic",me)  关注她发图的消息,这个关注操作会把me放到her的图片关注者列表中。(列表就是__MSG_QS__["pic"],美女还有很多的其他类型的消息 比如__MSG_QS__["say"]等等)

美女每次发图片,就会调用her.dm({type:'pic',picUrl:''});然后消息机制就会把{type:'pic',picUrl:''}信息传给图片关注者列表中每一位。

me这边必须要有一个方法来收这个图片消息,就是

me.rm(obj)

首先呢,我们rm会收到很多消息,它就像信箱,什么信件都放在里边,我们首先要判断一下收到的消息是什么?

obj.type

如果obj.type=='pic',然后我自己看着办了……



总结

消息机制的优势:

1. 低耦合性 模块之间通过消息传输数据,这样基本上没有对其他模块的调用

2. 灵活性 在使用的时候才组装模块,可以根据需求任意组装模块



PS:全部示例代码

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
        <title>Untitled Document</title>
    </head>
    <body>
        <div id="show">
        </div>
        <script language="JavaScript" type="text/javascript">
            var J = (function(){
                function C(b){
                    var Z = this.__MSG_QS__;
                    if (!Z[b]) {
                        Z[b] = []
                    }
                    for (var a = 1, X = arguments.length, Y; a < X; a++) {
                        Z[b].push(arguments[a])
                    }
                }
                function G(Y){
                    var Z = this.__MSG_QS__[Y.type];
                    if (Z == null) {
                        return
                    }
                    for (var a = 0, X = Z.length; a < X; a++) {
                        Z[a].rm(Y)
                    }
                }
                return {
                    ini: function(X){
                        X.__MSG_QS__ = {};
                        X.on = C;
                        X.dm = G;
                        return X
                    }
                }
            })();
            
            var dataLayer = J.ini({
                getData: function(){
                    this.dm({
                        type: "data",
                        data: 1
                    })
                }
            })
            
            var dataLayer1 = J.ini({
                getData: function(){
                    this.dm({
                        type: "data",
                        data: 10
                    })
                }
            })
            
            var controlLayer = J.ini({
                rm: function(Y){
                    switch (Y.type) {
                        case "data":
                            Y.data++;
                            this.dm({
                                type: "show",
                                data: Y.data
                            });
                    }
                }
            })
            
            
            
            
            var viewLayer = J.ini({
                rm: function(Y){
                    switch (Y.type) {
                        case "show":
                            alert(Y.data);
                    }
                }
            });
            
            var viewLayer1 = J.ini({
                rm: function(Y){
                    switch (Y.type) {
                        case "show":
                            document.getElementById("show").innerHTML = Y.data;
                    }
                }
            });
            
            dataLayer.on("data", controlLayer);
            dataLayer1.on("data", controlLayer);
            controlLayer.on("show", viewLayer, viewLayer1);
            dataLayer.getData();
            dataLayer1.getData();
            
            
            
            
        </script>
    </body>
</html>


ozdoo技术系列文章 转载请署名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值