【问题标题】:Adding event listeners to 'memory objects' in Javascript?在Javascript中将事件侦听器添加到“内存对象”?
【发布时间】:2020-07-01 04:30:57
【问题描述】:

问题的一些背景: Reverse Engineering the DOM, Javascript events & "what's going on"?

我正在写一些东西,它会在实时搜索中“播放”谷歌页面预览的功能。本质上,我想为 keyup 事件添加一个事件监听器,它将

  1. 查询页面预览结果(向google发送ajax请求)
  2. 读取结果在内存中
  3. 将其实时添加到您的搜索页面

这实际上将创建一个实时页面预览搜索结果,就像谷歌一样。

公平地说,我实际上已经在各种组件中完成了大约 95% 的工作,并且我正处于调整功能以使其更加用户友好的阶段。如果您对我正在做的事情的原因和方式感兴趣,请随时查看我以前的博客文章http://chesser.ca,或者甚至查看http://chesser.ca/gvs.marklet.0.3.js 的“代码的最新版本”(目前非常麻烦,因为我现在有点“介于功能之间”。

您的浏览器的书签代码在这里:

 javascript:(function{var head= document.getElementsByTagName('head')[0];var script= document.createElement('script');script.type= 'text/javascript';script.src= 'http://chesser.ca/gvs.marklet.0.3.js';head.appendChild(script);};)();

(keyup 事件侦听器当前设置为关闭,本质上是为了使其在当前状态下工作,您在具有实时预览的页面上运行搜索并单击一次小书签(以启动查询),等待一两秒钟,然后再次单击它(显示页面预览)

所以我要对此进行一些更改:

在第 1 部分(针对性能)中,我只对查询前两个元素感兴趣。我想这很容易,唯一阻止我的是我还没有尝试过(而不是所有 divs.length,只需将其设置为 2)

function query_current_pages(){
     var all_divs = document.getElementsByTagName('div');
     for (i=0;i < all_divs.length; i++) {
         if (all_divs[i].className == 'vsc') {
             google.vs.ea(all_divs[i]);
         }
     }
 }

下一个问题(也是我不确定的问题)是如何设置事件侦听器并修改 add_previews 函数,以便在请求返回时添加预览,而不是火腿- 循环遍历 google.vs.ha 内存空间中的所有内容的方法,我想创建一些东西来监听那里的数据,然后开始行动。

我尝试这样做的原因是因为我认为它真的很整洁。那是我在编写代码的过程中学到了很多关于编码的东西。

对于那些对页面预览如何“卡在页面上”感兴趣的人,这里是循环遍历内存中所有图像并将它们放置起来的函数。

 function add_previews(){
    c=document.getElementById('ires');
    nli=document.createElement('div');
    cell = 0;
    for(var Obj in google.vs.ha){
        na=document.createElement('a');
        na.href=Obj;

        nd=document.createElement('div');
        cldiv=document.createElement('div');
        cldiv.style.clear = 'both';

        nd.style.width=google.vs.ha[Obj].data.dim[0]+'px';
        nd.style.height=google.vs.ha[Obj].data.dim[1]+'px';
        nd.style.margin = '5px';
        nd.style.padding = '5px';
        nd.style.cssFloat = 'left';
        nd.style.border = '1px solid #999999';

        if (google.vs.ha[Obj].data.tbts.length) {
            nilDiv = document.createElement('div'); 
            for(i = 0; i < google.vs.ha[Obj].data.tbts.length; i++){
                box = google.vs.ha[Obj].data.tbts[i].box;
                newbox = document.createElement('div');
                newbox.className = 'vsb vsbb';
                newbox.style.position = 'relative';
                newbox.style.top = (box.t)+'px';
                newbox.style.left = box.l+'px';
                newbox.style.height = box.h+'px';
                newbox.style.width = box.w+'px';
                nilDiv.appendChild(newbox);
                newtext = document.createElement('div');
                newtext.className = 'vsb vstb';
                newtext.innerHTML = google.vs.ha[Obj].data.tbts[i].txt;
                newtext.style.top = (box.t)+'px';
                newtext.style.position = 'relative';
                nilDiv.appendChild(newtext);
            }
            nilDiv.style.height = '0px';
            nd.appendChild(nilDiv);
        }

        for(i = 0; i < google.vs.ha[Obj].data.ssegs.length; i++){
            ni=document.createElement('img');
            ni.src += google.vs.ha[Obj].data.ssegs[i];
            ni.className+=' vsi';
            na.appendChild(ni);
        }
        nd.appendChild(na);
        nli.appendChild(nd);
    };
    c.insertBefore(nli,c.firstChild);           
 } 

其中明显需要更改的一点(使用事件侦听器)是将for(var Obj in google.vs.ha){ 修复为传入的单个google.vs.rs 对象。

如果您一直坚持到这个问题:感谢阅读 :) - 亚历克斯

编辑

根据下面的讨论,google.vs.Ga 似乎负责查询数据(答案是覆盖函数)

为了提供信息(和乐趣),这里是 .Ga 代码。

  google.vs.Ga = function (a, b, c) {
        var d = google.vs.b.kfe.kfeHost,
            g = google.vs.Ya(a),
            i = a.getAttribute("sig");
        if (i) {
            var f = google.vs.qa(a);
            if (f) {
                d = [d ? "http://" + d : "", google.vs.b.kfe.kfeUrlPrefix, "&d=", encodeURIComponent(f), "&b=1", "&jsonp=google.vs.r"];
                d.push("&a=");
                d.push(encodeURIComponent(i));
                if (i = a.getAttribute("blobref")) {
                    d.push("&bl=");
                    d.push(i)
                }
                d.push("&rs=");
                i = 0;
                for (var j; j = g[i++];) {
                    d.push(encodeURIComponent(j));
                    i < g.length && d.push("&rs=")
                }
                g = google.vs.m(a) || {
                    ub: a
                };
                g.G = c;
                google.vs.ha[f] = g;
                c = d.join("");
                c = new google.vs.Ia(f, c, function () {
                    google.vs.P(a, h);
                    o(google.vs.k, f)
                });
                b ? p(google.vs.k, c) : q(google.vs.k, c)
            }
        }
    };

【问题讨论】:

  • 我有点困惑——数据更新时事件会调用什么函数?
  • 您是否尝试确定预览图像何时可用,并触发您正在寻找的事件?
  • @matt - 是的 - 试图找出图像何时可用并在那时触发。

标签: javascript listener dom-events


【解决方案1】:

google.vs.ha 对象是一个基本的 JavaScript 对象,具有键/值对属性,没有可说的函数。话虽如此,这些简单的对象无法在更改时通知您。

在我看来,你基本上有两种选择:

  • 定期检查 google.vs.ha 以获取您正在寻找的数据,跟踪您已经抓取了哪些图像。这可以通过 setInterval();

  • 来完成
  • 确定页面或 google 中的功能。 namespace 负责做加载数据的工作。一旦您确定了数据的加载位置以及 google.vs.ha 对象的确切更新位置,您就可以将原始函数替换为您自己的包含事件通知的工艺之一。

例如,如果我有一个如下所示的基本功能:

var Example = function(value){
  var closured = ' world';
  this.value = value;
  this.doSomething = function(){ alert(this.value + closured); };
};

var test = new Example('hello');
test.doSomething(); // will only alert 'hello world';

var oldFunc = test.doSomething;
var notifyMe = function(){ alert('notified'); }; // callback function

// Update previous method to do it's normal thing, but then notify after
test.doSomething = function(){
  oldFunc.apply(this, arguments);
  notifyMe();
};

test.doSomething(); // will alert 'hello world', and then 'notified'

在上面的代码中,我们已经用我们自己的一个有效地替换了旧的 doSomething 函数。这个新版本仍然执行它之前的职责(通过 oldFunc.apply),但之后会通知您。

请注意,您的新函数只能访问对象的“公共”属性,而不能访问由闭包(例如“闭包”变量)捕获的私有元素。我似乎记得在某个地方,Google 倾向于避免使用私有变量作为闭包方法,因为这可能会增加内存管理的复杂性,因此这可能不是问题。

更新:我在 Google 搜索结果页面上玩了一下。我重新进行了搜索,但在点击预览之前,我在 Chrome 控制台中执行了以下操作:

var old = google.vs.Ga;
var newFunc = function(){
  old.apply(this, arguments);
  console.log(arguments);
};

google.vs.Ga = newFunc; 

而且好像是点击预览后触发的。

【讨论】:

  • 覆盖谷歌的一个功能似乎是个好主意,但我还不会打赌它们也保持当前的实现不变。我猜这是一件新鲜的事情。您放在这里的更新仍然是一种非常干净的方法。来自我的 +1。
  • 是的 - google.vs.ea 调用 google.vs.Ga 所以你是说我可以使用 Javascript 复制现有的 Ga 然后在其后添加我自己的代码行? IIRC .ga 并不完全是返回结果集的那个 - 但它很接近。如果我知道如何覆盖该功能,我相信我可以找到合适的来处理。我一定会告诉你的:)
  • @naugtur 是的,但是当你构建 JavaScript 来操作页面上的数据时,它总是取决于它们是否改变了它们的实现。有些事情可能比其他事情更容易出错,但最终你仍然必须做出假设才能完成工作。
  • @Alex C 是的,这是正确的。我没有遵循 google.vs.Ga 上的面包屑路径,但这似乎是一个不错的起点
  • @naugtur - 好点,幸运的是,在这种情况下,它更多是为了探索、学习和享受编码。我真的只需要看到实时预览搜索正常工作一次,我就会感到满意。 (这真是一个为艺术而艺术的案例)——我喜欢马特向我们展示如何覆盖函数的默认行为的方式。
【解决方案2】:

图像是在下载后存储的,对吗?明显的。 所以他们唯一可以改变的就是一个 AJAX 请求。

因此,每次 AJAX 请求成功时,您都必须进行一些检查。 jQuery 为成功的 AJAX 调用提供了全局绑定,因此即使没有它也应该可以实现。

现在,当我们知道这一点时 - 检查可能会从查看响应对象中可用的某些变量或 XMLHTTPRequest 对象本身的调用类型开始。这可以进一步减少您必须调用更新程序的次数。

【讨论】:

  • 有趣的是——它们以数据 URI 的形式出现。函数google.vs.ea(div[@class=vsc]); 调用将数据加载到内存中的ajax 请求。视觉搜索博客确实说浏览器会在某处缓存这些数据 - 但我已经看到 ajax 请求似乎每次都会发生。根据下面的马特,看起来我的行动方案可能是用我自己的一项功能覆盖谷歌的一项功能。
  • “调用将数据加载到内存中的 ajax 请求” - 为什么不挂钩呢?
猜你喜欢
  • 2018-12-10
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2012-08-17
  • 1970-01-01
  • 2012-09-09
  • 2016-10-19
  • 2011-09-12
相关资源
最近更新 更多