简体   繁体   中英

Writing an .add*() plug-in function using jQuery

Okay, so I have discovered how to write jQuery plug-ins and I think this will tidy up my code a lot. I've been looking at a lot of tutorials which just adds style to the set of matched elements passed on the plug-in function.

...but I want to add new elements to the when using my function. Say that I want to do this:

$children
    .addCousins()
        .addClass("x")
    .end()
    .addClass("y");

So I've written this function, .addCousins() . What it does, nobody knows, but know that it works in theory. I only need to wrap my head around how to add more elements (if there are any) when .addCousins() is called. For each element in $children there can be zero or more "cousins", which should be added when doing the .each() in the plug-in function.

Here's what I have so far:

(function($){
    $.fn.extend({
        addCousins: function () {
            return this.each(
                    function () {
                        var index = $(this)
                            .prevAll("td.radio")
                                .andSelf()
                                    .length - 1;

                        $(this)
                            .prev("td[rowspan=2]")
                                .parent()
                                    .next()
                                        .children("td.radio")
                                            .eq(index); // here is the "cousin" which should be added to the selection
                    }
                );
        }
    });
})(jQuery);

I've been trying various solutions all day, but no progress yet. The selection of the cousin (the implementation of the selection you need not worry about) is done in the inner anonymous function, but, yeah, I don't really know how to go from here.

I hope I've been more or less clear about what I want.

Edit #1. Here is some testable HTML (I think)...

<table>
    <tr>
        <td rowspan="2">Here are cousins</td>
        <td class="radio">1</td>
        <td class="radio">2</td>
        <td class="radio">3</td>
    </tr>
    <tr>
        <td class="radio">4</td>
        <td class="radio">5</td>
        <td class="radio">6</td>
    </tr>
    <tr>
        <td rowspan="2">Here are NO cousins</td>
        <td class="radio">7</td>
        <td class="radio">8</td>
        <td class="radio">9</td>
    </tr>
</table>

...and my updated plug-in function.

(function($){
    $.fn.extend({ 
        cousins: function () {
            this
                .each(
                    function () {
                        var index = $(this)
                            .prevAll("td.radio")
                                .andSelf()
                                    .length - 1;

                        $(this)
                            .prev("td[rowspan=2]")
                                .parent()
                                    .next()
                                        .children("td.radio")
                                            .eq(index)
                                                .addClass("cousin");
                                            .end()
                                        .end()
                                    .end()
                                .end()
                            .end()
                            .prev()
                                .find("td[rowspan=2]")
                                    .nextAll("td.radio")
                                        .eq(index)
                                            .addClass("cousin");
                    }
                );

            return $("td.cousin")
                .removeClass("cousin");
        }
    });
})(jQuery);

If table cell 2 is selected an passed on to .cousins() , table cell 4 should be returned. Vice versa for table cell 4...

Edit #2. My (not yet working) update:

cousins: function () {
    var $cousins = $();

    this
        .each(
            function () {
                var index =
                    $(this)
                        .prevAll("td.radio")
                            .andSelf()
                                .length - 1;
                var $next = null;
                var $prev = null;

                $next = 
                    $(this)
                        .prev("td[rowspan=2]")
                            .parent()
                                .next()
                                    .children("td.radio")
                                        .get(index);
                $prev =
                    $(this)
                        .parent()
                            .prev()
                                .find("td[rowspan=2]")
                                    .nextAll("td.radio")
                                        .get(index);

                if ($next == null && $prev == null) {
                    $cousins.push($(this));
                } else {
                    $cousins.push($next);
                    $cousins.push($prev);
                }
            }
        );

    return $cousins;
}

As I understand it, you want to add elements to the set, and have .end get you back the previous set.

You can use .add for this: http://jsfiddle.net/AjkRb/1/ .

(function($){
    $.fn.extend({
        addCousins: function () {
            var toAdd = [];
            this.each(function () {
                var index = $(this)
                    .prevAll("td.radio")
                    .andSelf()
                    .length - 1;

                toAdd.push($(this)
                    .parent()
                    .next()
                    .children("td.radio")
                    .get(index));  // add native element (get instead of eq)
            });
            return this.add(toAdd);
        }
    });
})(jQuery);

Usage can then be as follows:

$("tr:first td.radio")
  .addCousins()
    .addClass("red")
    .end()
  .addClass("big");

Viktor, assuming your code to correctly select the elements of interest (cousins), then there's a number of ways to approach adding them to the original selection.

A consideration is that the elements in the returned jq object should be in DOM order and fortunately, "as of jQuery 1.4 the results from .add() will always be returned in document order (rather than a simple concatenation) .add() ". pimvdb's code correctly addresses this.

On another tack, I would prefer the additional flexibility offerd by a .cousins() plugin rather than .addCousins() , where :

  • .cousins() would select just the cousins
  • .cousins().andSelf() would be equivalent to .addCousins()

Here's the code for .cousins() :

(function($) {
    $.fn.extend({
        cousins: function(options) {
            var settings = {
                sibling_selector: '*',
                uncle_selector: '*',
                cousin_selector: '*'
            };
            if (options) {
                $.extend(settings, options);
            }
            var c = [];//cousins
            this.each(function() {
                var $this = $(this);
                var index = $this.parent().children(settings.sibling_selector).index($this);
                $this.parent().siblings(settings.uncle_selector).each(function() {
                    c.push($(this).children(settings.cousin_selector).get(index));
                });
            });
            return this.pushStack(c);
        }
    });
})(jQuery);

DEMO

Notes:

  • to generalize the plugin, this version accepts an options map (see demo).
  • .pushStack() allows the method chain .cousins(...).andSelf() and .cousins(...).end() to behave as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM