jQuery插件中的点击事件触发多次

3

我正在使用一个名为printElement的jquery插件:

http://projects.erikzaadi.com/jQueryPlugins/jQuery.printElement/

第一次点击它能够正常工作,但在关闭弹出窗口后,再次点击它会继续弹出窗口。第二次点击会弹出四次,第三次点击就有可能会弹出36个窗口。每次都是在我关闭前一个弹出窗口之后才会显示。我尝试了使用bind()和unbind()以及event.stopPropagation(),但并没有任何改变。

这里是我调用它的地方:

$('a[href="#print"]').click(function(){$("body").printElement();});

以下是插件代码:

/// <reference path="http://code.jquery.com/jquery-1.4.1-vsdoc.js" />
/*
* Print Element Plugin 1.2
*
* Copyright (c) 2010 Erik Zaadi
*
* Inspired by PrintArea (http://plugins.jquery.com/project/PrintArea) and
* https://dev59.com/lHRB5IYBdhLWcg3w6LR2     in-safari-chrome
*
*  Home Page : http://projects.erikzaadi/jQueryPlugins/jQuery.printElement 
*  Issues (bug reporting) :      http://github.com/erikzaadi/jQueryPlugins/issues/labels/printElement
*  jQuery plugin page : http://plugins.jquery.com/project/printElement 
*  
*  Thanks to David B (http://github.com/ungenio) and icgJohn  (http://www.blogger.com/profile/11881116857076484100)
*  For their great contributions!
* 
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*   
*   Note, Iframe Printing is not supported in Opera and Chrome 3.0, a popup window will be shown instead
*/
; (function (window, undefined) {
var document = window["document"];
var $ = window["jQuery"];
$.fn["printElement"] = function (options) {
    var mainOptions = $.extend({}, $.fn["printElement"]["defaults"], options);
    //iframe mode is not supported for opera and chrome 3.0 (it prints the entire page).
    //http://www.google.com/support/forum/p/Webmasters/thread?tid=2cb0f08dce8821c3&hl=en
    if (mainOptions["printMode"] == 'iframe') {
        if ($.browser.opera || (/chrome/.test(navigator.userAgent.toLowerCase())))
            mainOptions["printMode"] = 'popup';
    }
    //Remove previously printed iframe if exists
    $("[id^='printElement_']").remove();

    return this.each(function () {
        //Support Metadata Plug-in if available
        var opts = $.meta ? $.extend({}, mainOptions, $(this).data()) : mainOptions;
        _printElement($(this), opts);
    });
};
$.fn["printElement"]["defaults"] = {
    "printMode": 'iframe', //Usage : iframe / popup
    "pageTitle": '', //Print Page Title
    "overrideElementCSS": null,
    /* Can be one of the following 3 options:
    * 1 : boolean (pass true for stripping all css linked)
    * 2 : array of $.fn.printElement.cssElement (s)
    * 3 : array of strings with paths to alternate css files (optimized for print)
    */
    "printBodyOptions": {
        "styleToAdd": 'padding:10px;margin:10px;', //style attributes to add to the body of print document
        "classNameToAdd": '' //css class to add to the body of print document
    },
    "leaveOpen": false, // in case of popup, leave the print page open or not
    "iframeElementOptions": {
        "styleToAdd": 'border:none;position:absolute;width:0px;height:0px;bottom:0px;left:0px;', //style attributes to add to the iframe element
        "classNameToAdd": '' //css class to add to the iframe element
    }
};
$.fn["printElement"]["cssElement"] = {
    "href": '',
    "media": ''
};
function _printElement(element, opts) {
    //Create markup to be printed
    var html = _getMarkup(element, opts);

    var popupOrIframe = null;
    var documentToWriteTo = null;
    if (opts["printMode"].toLowerCase() == 'popup') {
        popupOrIframe = window.open('about:blank', 'printElementWindow', 'width=650,height=440,scrollbars=yes');
        documentToWriteTo = popupOrIframe.document;
    }
    else {
        //The random ID is to overcome a safari bug http://www.cjboco.com.sharedcopy.com/post.cfm/442dc92cd1c0ca10a5c35210b8166882.html
        var printElementID = "printElement_" + (Math.round(Math.random() * 99999)).toString();
        //Native creation of the element is faster..
        var iframe = document.createElement('IFRAME');
        $(iframe).attr({
            style: opts["iframeElementOptions"]["styleToAdd"],
            id: printElementID,
            className: opts["iframeElementOptions"]["classNameToAdd"],
            frameBorder: 0,
            scrolling: 'no',
            src: 'about:blank'
        });
        document.body.appendChild(iframe);
        documentToWriteTo = (iframe.contentWindow || iframe.contentDocument);
        if (documentToWriteTo.document)
            documentToWriteTo = documentToWriteTo.document;
        iframe = document.frames ? document.frames[printElementID] : document.getElementById(printElementID);
        popupOrIframe = iframe.contentWindow || iframe;
    }
    focus();
    documentToWriteTo.open();
    documentToWriteTo.write(html);
    documentToWriteTo.close();
    _callPrint(popupOrIframe);
};

function _callPrint(element) {
    if (element && element["printPage"])
        element["printPage"]();
    else
        setTimeout(function () {
            _callPrint(element);
        }, 50);
}

function _getElementHTMLIncludingFormElements(element) {
    var $element = $(element);
    //Radiobuttons and checkboxes
    $(":checked", $element).each(function () {
        this.setAttribute('checked', 'checked');
    });
    //simple text inputs
    $("input[type='text']", $element).each(function () {
        this.setAttribute('value', $(this).val());
    });
    $("select", $element).each(function () {
        var $select = $(this);
        $("option", $select).each(function () {
            if ($select.val() == $(this).val())
                this.setAttribute('selected', 'selected');
        });
    });
    $("textarea", $element).each(function () {
        //Thanks http://blog.ekini.net/2009/02/24/jquery-getting-the-latest-textvalue-inside-a-textarea/
        var value = $(this).attr('value');
        //fix for issue 7 (http://plugins.jquery.com/node/13503 and http://github.com/erikzaadi/jQueryPlugins/issues#issue/7)
        if ($.browser.mozilla && this.firstChild)
            this.firstChild.textContent = value;
        else
            this.innerHTML = value;
    });
    //http://dbj.org/dbj/?p=91
    var elementHtml = $('<div></div>').append($element.clone()).html();
    return elementHtml;
}

function _getBaseHref() {
    var port = (window.location.port) ? ':' + window.location.port : '';
    return window.location.protocol + '//' + window.location.hostname + port + window.location.pathname;
}

function _getMarkup(element, opts) {
    var $element = $(element);
    var elementHtml = _getElementHTMLIncludingFormElements(element);

    var html = new Array();
    html.push('<html><head><title>' + opts["pageTitle"] + '</title>');
    if (opts["overrideElementCSS"]) {
        if (opts["overrideElementCSS"].length > 0) {
            for (var x = 0; x < opts["overrideElementCSS"].length; x++) {
                var current = opts["overrideElementCSS"][x];
                if (typeof (current) == 'string')
                    html.push('<link type="text/css" rel="stylesheet" href="' + current + '" >');
                else
                    html.push('<link type="text/css" rel="stylesheet" href="' + current["href"] + '" media="' + current["media"] + '" >');
            }
        }
    }
    else {
        $("link", document).filter(function () {
            return $(this).attr("rel").toLowerCase() == "stylesheet";
        }).each(function () {
            html.push('<link type="text/css" rel="stylesheet" href="' + $(this).attr("href") + '" media="' + $(this).attr('media') + '" >');
        });
    }
    //Ensure that relative links work
    html.push('<base href="' + _getBaseHref() + '" />');
    html.push('</head><body style="' + opts["printBodyOptions"]["styleToAdd"] + '" class="' + opts["printBodyOptions"]["classNameToAdd"] + '">');
    html.push('<div class="' + $element.attr('class') + '">' + elementHtml + '</div>');
    html.push('<script type="text/javascript">function printPage(){focus();print();' + ((!$.browser.opera && !opts["leaveOpen"] && opts["printMode"].toLowerCase() == 'popup') ? 'close();' : '') + '}</script>');
    html.push('</body></html>');

    return html.join('');
};
})(window);

我尝试了以下这段代码:

我尝试了以下这段代码:

$('a[href="#print"]').bind( "click", function() {
$("body").printElement();
});

this:

$('a[href="#print"]').unbind().bind( "click", function() {
$("body").printElement();
});

this:

 $('a[href="#print"]').unbind("click").bind( "click", function() {
$("body").printElement();
});

this:

  $('a[href="#print"]').click(function(e){
      e.stopPropagation();
      $("body").printElement();
   });

this:

  $('a[href="#print"]').click(function(e){
      e.stopImmediatePropagation();
      $("body").printElement();
   });

this:

$('a[href="#print"]').on( "click", function() {
$("body").printElement();
});

我已经将stopPropgation方法与bind方法以不同的组合方式混合使用。它们都能在第一次正常工作,并且之后多次触发。


你是在处理程序或函数内初始化插件吗?你确定你没有多次调用它吗? - A. Wolff
3
这似乎不是插件的问题,而是您的代码多次绑定点击处理程序的问题。 - Jason P
@A. Wolff - 它被称为文档准备函数内部。我没有看到任何证据表明它被调用了多次。 - Fletchling
@JasonP - 如果是这种情况,这样做会修复它吗?$('a[href="#print"]').unbind().click(function(){$("body").printElement();}); - Fletchling
1
jsfiddle 上一切都正常工作。但是弹出窗口中的 HTML 没有正确渲染,这是我无法解决的 jsfiddle 问题。它将 JS 生成的 HTML 标签视为在 ' 外部,并给出警告,尽管每次单击时弹出窗口确实只打开一次。 - matewka
显示剩余3条评论
2个回答

0
这只是一个猜测,但值得一试:这段代码是在 body 内部吗?
$('a[href="#print"]').click(function(){$("body").printElement();});

该插件会复制正文中的所有内容,并在一个 iframe 中进行再现,这可能会导致每次运行插件时都会评估事件绑定,从而创建一个循环。尝试将代码移到你正在打印的区域之外(即 body 外部)。

这是一个有趣的想法,因为它在 body 底部的 js 文件中。但是,那并没有解决问题。不过,我仍然感谢你的帮助。 - Fletchling

0

问题已解决:

$('a[href="#print"]').one( "click", function() {
    $("body").printElement();
});

当我阅读这里的文档时,我认为它会在我第一次点击链接时触发,如果我再次点击它,什么也不会发生。但是,绝望迫使我尝试,现在它正在工作。谢谢大家的帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接