JavaScript:原生JS实现Facebook实时消息抓捕

基础知识准备:

HTML5给我们提供了一个新的对象叫作:MutationObserver。为了兼容,还有WebKitMutationObserver、MozMutationObserver,挂靠在window下。


这个对象是干嘛的呢?
mutation:变化、变动、突变;
observer:观察者;
顾名思义,在DOM中,MutationObserver就是监听DOM变化的意思。


那么这个对象能够监听DOM的哪些变化呢?

  1. 子节点变化; ——–> childList
  2. 自身属性变化; ——–> attributes
  3. 自身的文本变化; ——–> characterData

以上三点呢是三大基本点。


至于这个对象怎么使用呢?很简单!

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

var observer = new MutationObserver(function(mutations) {});
   
   
  • 1
  • 2
  • 3

上面的代码中,就是new了一个对象,里面传个callback回调函数而已,就这么简单,这个回调函数干嘛的?该回调函数会在指定的DOM节点(目标节点)发生变化时被调用. 该回调函数有一个参数mutations,这个参数是个数组,数组里每个元素是对象(包含了若干个MutationRecord对象的数组)。


该对象有几个方法要知道:

observe( Node target, optional MutationObserverInit options );
ovserve(要观察的目标节点, 你要观察目标节点的哪些东西-对象);
//举个例子,给你个人(目标节点),你想观察这个人的哪些指标变动:体重、身高、小孩等等

disconnect();//不再观察

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

好了,直接上个例子吧:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <div id="guoyu"></div>

    <script type="text/javascript">
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
        // 选择目标节点
        var target = document.querySelector('#guoyu');
        // 创建观察者对象,一旦目标节点发送变化,该回调立马执行
        var observer = new MutationObserver(function(mutations) {
          mutations.forEach(function(mutation) {
            console.log(mutation.type);
          });
          console.log(mutations);//看看callback参数到底是什么
        });

        // 配置观察选项:你想观察目标节点哪些项
        var config = {
            attributes: true,
            childList: true,
            characterData: true
        }

        // 传入目标节点和观察选项
        observer.observe(target, config);

    </script>

</body>
</html>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

我们在id为”guoyu”的节点中添加一个节点,那么回调函数立马就会被触发执行:
这里写图片描述


看到了吧,我们在节点中插入一个子节点,立马触发了回调函数,并打印了我们想要的结果,而且改变的是childList。


再看一下,我这次把id给改了,看看有什么不同:

这里写图片描述


看到了吗,这次修改id属于属性的修改,打印出来的是attributes。


注: childList, attributes, 或者characterData三个属性中必须至少有一个为true.否则,会抛出异常”An invalid or illegal string was specified”.


下面呢,就着重介绍一下各个属性到底是啥意思!首先我们看看回调函数里的那个参数,这个参数上面说了是个数组,每个元素是个对象,具体名字参见上面截图。


这里写图片描述


我们在观察目标节点的时候,需要配置一个json对象,告诉浏览器我们要监听目标节点的哪些指标,比如:属性、子节点、文本、所有子孙节点等等。那么具体有哪些呢?

这里写图片描述


再举个例子吧,比如,我们既改变文本值,记录characterDataOldValue;又改变属性id的值,记录attributeOldValue。

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <div id="old_guoyu">I'am old</div>

    <script type="text/javascript">
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver

        var target = document.querySelector('#old_guoyu');

        var observer = new MutationObserver(function(mutations) {
          mutations.forEach(function(mutation) {
            console.log(mutation.type);
          });
          console.log(mutations); 
        });

        var config = {
            attributes: true,
            childList: true,
            characterData: true,
            characterDataOldValue: true,//监听老的文本值
            attributeOldValue: true,//记录老的属性值
            subtree: true
        };

        observer.observe(target, config);

    </script>

</body>
</html>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

这里写图片描述


看到没,此次我同时改变了文本值和属性值,回调函数执行了两次,一次是文本改变执行的,另一次是属性id改变执行的。说明MutationObserver准确的监听了所有的变化,并作出反应。


监听Facebook消息

有了上面的基础,我们就可以做很多有趣的东西。我们知道,每当有新的消息的时候,facebook会给你立即推送,但这是有前提的,你的软件必须和Facebook有合作,或者花钱买Facebook的服务消息推送。比如UC浏览器的海外版,UC浏览器就可以实时帮你推送Facebook的消息,因为UC和Facebook达成了合作,才会给你推送。


我们的突破口在Facebook首页的tab上,每当有新的消息,该主页上的tab会显示一个数字,只要我们实时监听到这个数字变化,就可以实时监听Facebook的消息,让你不用花钱也能实时获取消息提醒,这对于没有和Facebook达成合作协议的浏览器厂商十分有用。


这里写图片描述


前端可以使用原生JS实现对消息的实时监听,并把消息发送给浏览器客户端,浏览器客户端进行提醒,下面是一点跑除复杂业务需求的基本代码:

var MutationObserverMRN = window.MutationObserver || window.WebKitMutationObserver;
var observerM, targetM;
var observerR, targetR;
var observerN, targetN;
var configGYFBUI = {
    'characterData' : true,
    'characterDataOldValue' : true,
    'childList': true,
    'subtree' : true
};
function observerMessages(nodeId, type) {
    var idDiv = document.getElementById(nodeId);
    var parentM = (idDiv.childNodes[0].nodeName == 'A') ? idDiv.childNodes[0] : idDiv;
    targetM = parentM.querySelectorAll('span')[1];
    if (!observerM) {
        observerM = new MutationObserverMRN(function(mutations) {
            var strCount = (targetM.innerText == 'undefined') ? '0' : targetM.innerText;
            if (parseInt(strCount) > 0) {
                var url = 'https://m.facebook.com' + parentM.getAttribute('href');
                var href = window.location.href;
                var reg = /messages/;
                if (!reg.test(href)) {
                    JSInterfaceManager.receiveFbNoti(type, url, strCount);
                }
            }
        });
    }
    observerM.observe(targetM, configGYFBUI);
}
function observerRequests(nodeId, type) {
    var idDiv = document.getElementById(nodeId);
    var parentR = (idDiv.childNodes[0].nodeName == 'A') ? idDiv.childNodes[0] : idDiv;
    targetR = parentR.querySelectorAll('span')[1];
    if (!observerR) {
        observerR = new MutationObserverMRN(function(mutations) {
            var strCount = (targetR.innerText == 'undefined') ? '0' : targetR.innerText;
            if (parseInt(strCount) > 0) {
                var url = 'https://m.facebook.com' + parentR.getAttribute('href');
                JSInterfaceManager.receiveFbNoti(type, url, strCount);
            }
        });
    }
    observerR.observe(targetR, configGYFBUI);
}
function observerNotifications(nodeId, type) {
    var idDiv = document.getElementById(nodeId);
    var parentN = (idDiv.childNodes[0].nodeName == 'A') ? idDiv.childNodes[0] : idDiv;
    targetN = parentN.querySelectorAll('span')[1];
    if (!observerN) {
        observerN = new MutationObserverMRN(function(mutations) {
            var strCount = (targetN.innerText == 'undefined') ? '0' : targetN.innerText;
            if (parseInt(strCount) > 0) {
                var url = 'https://m.facebook.com' + parentN.getAttribute('href');
                JSInterfaceManager.receiveFbNoti(type, url, strCount);
            }
        });
    }
    observerN.observe(targetN, configGYFBUI);
}
observerMessages('messages_jewel', 'messages');
observerRequests('requests_jewel', 'requests');
observerNotifications('notifications_jewel', 'notifications');

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq31549551/article/details/82183423