2

我想改变$.prepend()(并且可能$.append())的功能,以实现“on DOM change event”。

我可以做一些简单的事情吗:

$.prepend = function() { alert('Hello World'); };

或者我需要使用$.extend()函数$.prototype.prependor$.fn.prepend吗?

[我意识到我需要prepend()在我的新函数中包含该函数的原始源代码,否则 jQuery 会崩溃!]


编辑 :: 最终解决方案

对于那些有兴趣的人:

$.extend($, {
domChangeStack: [],
onDomChange: function(selector, fn, unbind, removeFromStack) {
    /* Needs to store: selector, function, unbind flag, removeFromStack flag */
    jQuery.domChangeStack.push([selector, fn, unbind, removeFromStack]);
},
domChangeEvent: function() {
    /* Ideally should only affect inserted HTML/altered DOM, but this doesn't */
    var stackItem, newStack = [];

    while (stackItem = jQuery.domChangeStack.pop()) {
        var selector = stackItem[0],
            fn = stackItem[1],
            unbind = stackItem[2],
            remove = stackItem[3];

        if (unbind) { $(selector).unbind(); }
        // Need to pass the jQuery object as fn is anonymous
        fn($(selector));
        if (!remove) { newStack.push(stackItem); }
    }

    jQuery.domChangeStack = newStack;

    // Show something happened!
    console.log("domChangeEvent: stack size = " + newStack.length);
}
});

$.fn.prepend = function() {

    var result = this.domManip(arguments, true, function( elem ) {
        if ( this.nodeType === 1 ) {
            this.insertBefore( elem, this.firstChild );
        }
    });

    // Need to actually alter DOM above before calling the DOMChange event
    $.domChangeEvent();

    return result;
};

和用法:

/* Run the given function on the elements found by the selector,
 *  don't run unbind() beforehand and don't pop this DOMChange
 *  event off the stack.
 */
$.onDomChange(".element_class", function(jObj) {
       jObj.do_something_awesome();
   }, false, false);
4

2 回答 2

3

您要使用哪种方法取决于您需要更改多少。因为.prepend它只是一种驻留在.fn您体内的方法,所以您不必弄乱原型。

在大多数情况下,它足以重命名原始方法,创建您自己的函数来执行您想要的操作,并以调用原始函数结束,如下所示:

var orgPrepend = $.fn.prepend;
$.fn.prepend = function(){
    // Do what you want here

    // Call org prepend and return
    return orgPrepend.apply(this, arguments);
}

注意:.apply.call或多或少相同。唯一的区别是.apply通过引用传递参数,而.call通过值传递它们,所以我更喜欢在可能的情况下使用.applybefore .call请参阅 MDC 以供参考

但是如果您查看 jQuery 的源代码(请参阅src/manipulation.js),您会发现此方法非常小,因此您可以直接实现它。

在下一个示例中,我将使用.extend它,但这不是必须的;你可以像第一个例子一样替换它。

$.extend($.fn, {
    prepend: function() {
        // Do what you want here
        console.log("prepend was called");
        // Execute domManip
        return this.domManip(arguments, true, function( elem ) {
            if ( this.nodeType === 1 ) {
                this.insertBefore( elem, this.firstChild );
            }
        });
    }
});

您可以以相同的方式覆盖.domManip或任何其他方法,如下例所示。您可能会明白为什么我更喜欢在.extend这里使用。

var _domManip = $.fn.domManip;
$.extend($.fn, {
    domManip: function() {
        // Do what you want here
        console.log("domManip was called");
        _domManip.apply(this, arguments);
    },
    prepend: function() {
        // Do what you want here
        console.log("prepend was called");
        // Execute domManip
        return this.domManip(arguments, true, function( elem ) {
            if ( this.nodeType === 1 ) {
                this.insertBefore( elem, this.firstChild );
            }
        });
    }
});

请参阅jsFiddle 上的测试用例

于 2011-05-19T09:14:44.390 回答
2

我做了一个小测试,看来你必须更换$.fn.prepend. 无论如何,如果您愿意,您可以执行以下操作:

var old=$.fn.prepend;
$.fn.prepend=function(){
   //Trigger DOMchange event
   old.apply(this, arguments);
};

通过这种方式,您可以将旧的 prepend 函数包装在一个新函数中,而无需重写函数代码。

于 2011-05-19T09:14:21.097 回答