xdomain.js 跨域链接脚本的 jQuery indexOf 错误

发布于 2025-01-02 11:32:10 字数 4336 浏览 3 评论 0原文

我正在使用脚本来检测跨域链接以进行谷歌分析跨域跟踪。原始脚本 (xdomain.js) 由 Luna Metrics 的优秀人员提供。这是经过我修改的脚本,向 StackOverflow 上的 educardocereto 致敬,了解在 GATC 中启用 setAllowAnchor 的建议更改(我已评论了控制台错误首先指向的第 40 行):

var jQueryXD = jQuery.noConflict();
/* I added var because page loads 2 versions 
    of jquery - not the source of the problem.*/

function listenToClicks()
{
    var domains=["domain1.com", "domain2.com"];
    var fileTypes=[".pdf"];

    jQueryXD('a').each(function(index) {
        var link = jQueryXD(this);
        var href = link.attr('href');

        jQueryXD.each(fileTypes, function(i) {
            if(jQueryXD(link).attr('href').indexOf(this)!=-1){ //this is line 40
                valid = false;
                jQueryXD(link).bind('click', function(c) {
                    c.preventDefault();
                    _gat._getTrackerByName()._trackEvent('Download', 'Click - ' +      jQueryXD(link).attr('href'));
                    setTimeout('document.location = "' + jQueryXD(link).attr('href') + '"', 100);
                });
            }
        });

        var valid = false;
        jQueryXD.each(domains, function(j) {
            try
            {
                if((jQueryXD(link).attr('href').indexOf(this)!=-1)&&(window.location.href.indexOf(this)==-1)){  
                    valid = true;

                    if (valid)
                    {
                        jQueryXD(link).bind('click', function(l) {
                            if(typeof(_gat)=="object"){
                                l.preventDefault();
                                if (jQueryXD(link).attr('target') != "_blank")
                                {                               // _gaq.push(['_link',jQueryXD(link).attr('href')]);
                                    _gaq.push(['_link',jQueryXD(link).attr('href'), true]); // mod
                                }
                                else
                                {
                                    var tracker = _gat._getTrackerByName();
                                    //var fullUrl = tracker._getLinkerUrl(jQueryXD(link).attr('href'));
                                    var fullUrl = tracker._getLinkerUrl(jQueryXD(link).attr('href'), true); //mod
                                    window.open(fullUrl);
                                }
                            }
                        });
                    }
                }

            }
            catch(e)
            {
                //Bad A tag
            }           
        });

        var rootDomain = document.domain.split(".")[document.domain.split(".").length - 2] + "." + document.domain.split(".")[document.domain.split(".").length - 1];

        if ( (href.match(/^http/)) && (href.indexOf(rootDomain) == -1) && !valid) {
            jQueryXD(link).bind('click', function(d) {
                    d.preventDefault();
                    _gat._getTrackerByName()._trackEvent('Outbound Link', href);
                    setTimeout('document.location = "' + href + '"', 100);
                });            
        }
    });

}

jQueryXD(document).ready(function() {
    listenToClicks();
});

Chrome javascript 控制台的输出:

 Uncaught TypeError: 
Cannot call method 'indexOf' of undefined        xdomain-nfi-nfs-anchormod-noconflict.js:40
    jQueryXD.each.valid                          xdomain-nfi-nfs-anchormod-noconflict.js:40
    jQuery.extend.each                           jquery-1.2.6.min.js:21
    (anonymous function)                         xdomain-nfi-nfs-anchormod-noconflict.js:39
    jQuery.extend.each                           jquery-1.2.6.min.js:21
    jQuery.fn.jQuery.each                        jquery-1.2.6.min.js:12
    listenToClicks                               xdomain-nfi-nfs-anchormod-noconflict.js:35
    (anonymous function)                         xdomain-nfi-nfs-anchormod-noconflict.js:100
    jQuery.fn.extend.ready                       jquery-1.2.6.min.js:27
    jQuery.extend.ready.jQuery.readyList         jquery-1.2.6.min.js:27
    jQuery.extend.each                           jquery-1.2.6.min.js:21
    jQuery.extend.ready                          jquery-1.2.6.min.js:27

所以,至少它似乎没有混淆两个 jquery 实例。我也用 jquery 1.7.1 尝试过。我使用 1.2.6 是因为该脚本似乎已经在该版本上进行了大部分测试。

I'm using a script to detect cross-domain links for google analytics cross-domain tracking. The original script (xdomain.js) was provided by the great folks at Luna Metrics. Here is the script with my modifications, hat-tip to educardocereto here on StackOverflow for the suggested changes to enable setAllowAnchor in the GATC (I've commented line 40 where the console error first points to):

var jQueryXD = jQuery.noConflict();
/* I added var because page loads 2 versions 
    of jquery - not the source of the problem.*/

function listenToClicks()
{
    var domains=["domain1.com", "domain2.com"];
    var fileTypes=[".pdf"];

    jQueryXD('a').each(function(index) {
        var link = jQueryXD(this);
        var href = link.attr('href');

        jQueryXD.each(fileTypes, function(i) {
            if(jQueryXD(link).attr('href').indexOf(this)!=-1){ //this is line 40
                valid = false;
                jQueryXD(link).bind('click', function(c) {
                    c.preventDefault();
                    _gat._getTrackerByName()._trackEvent('Download', 'Click - ' +      jQueryXD(link).attr('href'));
                    setTimeout('document.location = "' + jQueryXD(link).attr('href') + '"', 100);
                });
            }
        });

        var valid = false;
        jQueryXD.each(domains, function(j) {
            try
            {
                if((jQueryXD(link).attr('href').indexOf(this)!=-1)&&(window.location.href.indexOf(this)==-1)){  
                    valid = true;

                    if (valid)
                    {
                        jQueryXD(link).bind('click', function(l) {
                            if(typeof(_gat)=="object"){
                                l.preventDefault();
                                if (jQueryXD(link).attr('target') != "_blank")
                                {                               // _gaq.push(['_link',jQueryXD(link).attr('href')]);
                                    _gaq.push(['_link',jQueryXD(link).attr('href'), true]); // mod
                                }
                                else
                                {
                                    var tracker = _gat._getTrackerByName();
                                    //var fullUrl = tracker._getLinkerUrl(jQueryXD(link).attr('href'));
                                    var fullUrl = tracker._getLinkerUrl(jQueryXD(link).attr('href'), true); //mod
                                    window.open(fullUrl);
                                }
                            }
                        });
                    }
                }

            }
            catch(e)
            {
                //Bad A tag
            }           
        });

        var rootDomain = document.domain.split(".")[document.domain.split(".").length - 2] + "." + document.domain.split(".")[document.domain.split(".").length - 1];

        if ( (href.match(/^http/)) && (href.indexOf(rootDomain) == -1) && !valid) {
            jQueryXD(link).bind('click', function(d) {
                    d.preventDefault();
                    _gat._getTrackerByName()._trackEvent('Outbound Link', href);
                    setTimeout('document.location = "' + href + '"', 100);
                });            
        }
    });

}

jQueryXD(document).ready(function() {
    listenToClicks();
});

The output from the Chrome javascript console:

 Uncaught TypeError: 
Cannot call method 'indexOf' of undefined        xdomain-nfi-nfs-anchormod-noconflict.js:40
    jQueryXD.each.valid                          xdomain-nfi-nfs-anchormod-noconflict.js:40
    jQuery.extend.each                           jquery-1.2.6.min.js:21
    (anonymous function)                         xdomain-nfi-nfs-anchormod-noconflict.js:39
    jQuery.extend.each                           jquery-1.2.6.min.js:21
    jQuery.fn.jQuery.each                        jquery-1.2.6.min.js:12
    listenToClicks                               xdomain-nfi-nfs-anchormod-noconflict.js:35
    (anonymous function)                         xdomain-nfi-nfs-anchormod-noconflict.js:100
    jQuery.fn.extend.ready                       jquery-1.2.6.min.js:27
    jQuery.extend.ready.jQuery.readyList         jquery-1.2.6.min.js:27
    jQuery.extend.each                           jquery-1.2.6.min.js:21
    jQuery.extend.ready                          jquery-1.2.6.min.js:27

So, atleast it seems to be not mixing up the two jquery instances. I've also tried it with jquery 1.7.1. I'm using 1.2.6 because the script seems to have been moste tested on that version.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

海之角 2025-01-09 11:32:10

在这里,您缓存了 jQuerified 元素和 href 属性。

var link = jQueryXD(this);
var href = link.attr('href');

那么为什么你以后要这样做:

jQueryXD(link).attr('href').indexOf(this)

你可以调用 link.attr('href').indexOf(this) 因为 link 已经是一个 jQuery 对象,或者你可以使用直接使用您缓存的 href 并执行此 href.indexOf(this)

不过,我认为当链接没有 href 属性时,您看到的错误就会发生。因此,在继续您的逻辑之前,您最好检查 href 是否未定义。

我在 jQuery 1.2.6 和 1.7 上测试了它。看起来运行良好。

这是完成的脚本。

var jQueryXD = jQuery.noConflict();
/* I added var because page loads 2 versions 
    of jquery - not the source of the problem.*/

function listenToClicks() {
    var domains = ["domain1.com", "domain2.com"];
    var fileTypes = [".pdf"];

    jQueryXD('a').each(function(index) {
        var link = jQueryXD(this);
        var href = link.attr('href');
        if(!href){
            // This element doesnt have a href
            return true;
        }

        var valid = false;
        jQueryXD.each(fileTypes, function(i) {
            if (href.indexOf(this) != -1) { //this is line 40
                valid = false;
                link.bind('click', function(c) {
                    c.preventDefault();
                    _gat._getTrackerByName()._trackEvent('Download', 'Click - ' + link.attr('href'));
                    setTimeout('document.location = "' + href + '"', 100);
                });
            }
        });

        jQueryXD.each(domains, function(j) {
            try {
                if ((href.indexOf(this) != -1) && (window.location.href.indexOf(this) == -1)) {
                    valid = true;

                    if (valid) {
                        link.bind('click', function(l) {
                            if (typeof(_gat) == "object") {
                                l.preventDefault();
                                if (link.attr('target') != "_blank") { // _gaq.push(['_link',jQueryXD(link).attr('href')]);
                                    _gaq.push(['_link', href, true]); // mod
                                }
                                else {
                                    var tracker = _gat._getTrackerByName();
                                    //var fullUrl = tracker._getLinkerUrl(href);
                                    var fullUrl = tracker._getLinkerUrl(href, true); //mod
                                    window.open(fullUrl);
                                }
                            }
                        });
                    }
                }

            }
            catch (e) {
                //Bad A tag
            }
        });

        var rootDomain = document.domain.split(".")[document.domain.split(".").length - 2] + "." + document.domain.split(".")[document.domain.split(".").length - 1];

        if ((href.match(/^http/)) && (href.indexOf(rootDomain) == -1) && !valid) {
            jQueryXD(link).bind('click', function(d) {
                d.preventDefault();
                _gat._getTrackerByName()._trackEvent('Outbound Link', href);
                setTimeout('document.location = "' + href + '"', 100);
            });
        }
    });

}

jQueryXD(document).ready(function() {
    listenToClicks();
});

但你可能会在这里重新发明轮子。有一些更好的脚本可以实现同样的目的。我想您可能有兴趣研究 GAS。它是 ga.js 的包装器,扩展并添加了一些内容,包括 crossDomain 和 downloadTracking。

剧透:我是 GAS 的主要开发人员。

https://github.com/CardinalPath/gas

Here you cache both the jQuerified element and the href attr.

var link = jQueryXD(this);
var href = link.attr('href');

Than why do you later do this:

jQueryXD(link).attr('href').indexOf(this)

You could either call link.attr('href').indexOf(this) since link is already a jQuery object or you could use directly the href you cached and do this href.indexOf(this).

Still I think the error you see happens when a link doesn't have an href attribute. So you better check if the href is not undefined before continuing your logic.

I tested it on both jQuery 1.2.6 and 1.7. It seems to be working fine.

Here's the finished script.

var jQueryXD = jQuery.noConflict();
/* I added var because page loads 2 versions 
    of jquery - not the source of the problem.*/

function listenToClicks() {
    var domains = ["domain1.com", "domain2.com"];
    var fileTypes = [".pdf"];

    jQueryXD('a').each(function(index) {
        var link = jQueryXD(this);
        var href = link.attr('href');
        if(!href){
            // This element doesnt have a href
            return true;
        }

        var valid = false;
        jQueryXD.each(fileTypes, function(i) {
            if (href.indexOf(this) != -1) { //this is line 40
                valid = false;
                link.bind('click', function(c) {
                    c.preventDefault();
                    _gat._getTrackerByName()._trackEvent('Download', 'Click - ' + link.attr('href'));
                    setTimeout('document.location = "' + href + '"', 100);
                });
            }
        });

        jQueryXD.each(domains, function(j) {
            try {
                if ((href.indexOf(this) != -1) && (window.location.href.indexOf(this) == -1)) {
                    valid = true;

                    if (valid) {
                        link.bind('click', function(l) {
                            if (typeof(_gat) == "object") {
                                l.preventDefault();
                                if (link.attr('target') != "_blank") { // _gaq.push(['_link',jQueryXD(link).attr('href')]);
                                    _gaq.push(['_link', href, true]); // mod
                                }
                                else {
                                    var tracker = _gat._getTrackerByName();
                                    //var fullUrl = tracker._getLinkerUrl(href);
                                    var fullUrl = tracker._getLinkerUrl(href, true); //mod
                                    window.open(fullUrl);
                                }
                            }
                        });
                    }
                }

            }
            catch (e) {
                //Bad A tag
            }
        });

        var rootDomain = document.domain.split(".")[document.domain.split(".").length - 2] + "." + document.domain.split(".")[document.domain.split(".").length - 1];

        if ((href.match(/^http/)) && (href.indexOf(rootDomain) == -1) && !valid) {
            jQueryXD(link).bind('click', function(d) {
                d.preventDefault();
                _gat._getTrackerByName()._trackEvent('Outbound Link', href);
                setTimeout('document.location = "' + href + '"', 100);
            });
        }
    });

}

jQueryXD(document).ready(function() {
    listenToClicks();
});

But you might be reinventing the wheel here. There are some better scripts out there to achieve the same thing. I think you might be interested in looking into GAS. It's a wrapper around ga.js that extends and add a bunch of stuff including crossDomain and downloadTracking.

Spoiler: I'm the main developer of GAS.

https://github.com/CardinalPath/gas

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文