1

我已经编写了一个非常简单的 jQuery 插件来在客户端对一个ul或多个ol元素进行切片,但是我在多个元素上启动它时目睹了非常奇怪的行为。该插件基本上隐藏了列表中的额外项目,只显示指定数量的项目。它将更多/更少链接附加到列表中,以便用户可以切换项目。以下是插件的代码。

/**
 * jQuery list slice v1.0
 *
 * Slices a list ('ul', 'ol') and shows a more/less link to either show more
 * or less 'li's respectively.
 *
 * @USAGE:
 *      For a list like the following:
 *
 *      <ul id="sample-list">
 *          <li>Item 1</li>
 *          <li>Item 2</li>
 *          <li>Item 3</li>
 *      </ul>
 *
 *      Initiate the sliceList as follows:
 *
 *      $('ul.sample-list').listSlice({
 *          default_items: 2, // Set Any other options here
 *      });
 */

(function($) {
    $.fn.listSlice = function(options) {
        // Merge or Override user defined options
        options = $.extend({}, $.fn.listSlice.options, options);

        var entity = $(this);

        /**
         * Slices the initiating list to show the number of default_items
         * and append a more link to the list.
         */
        function sliceList(){

            entity.find('li').addClass('listSliceItem');

            // Make sure we do not count items in ignore_list
            ignore_list = options.ignore_list.split(',');
            $.each(ignore_list, function() {
                var class_name = '.' + $.trim(this);
                var id_name = '#' + $.trim(this);

                var obj = entity.find(class_name);
                obj.removeClass('listSliceItem');
                if (!(obj.is('li'))) {
                    obj.closest('li').removeClass('listSliceItem');
                }

                var obj = entity.find(id_name);
                obj.removeClass('listSliceItem');
                if (!(obj.is('li'))) {
                    obj.closest('li').removeClass('listSliceItem');
                }
            });

            $.each(entity, function() {
                var current_entity = $(this);
                var should_apply = true;
                if((current_entity.find('li.listSliceItem').length) <= (
                        options.default_items)) {
                    should_apply = false;
                }

                // Make sure we apply more/less only to lists that have
                // enough 'li' elements.
                if(should_apply) {
                current_entity.find('li.listSliceItem' +
                            ':gt(' + (options.default_items - 1).toString() +
                            ')').hide();
                current_entity.append('<' + options.link_container +
                                ' class="' + options.link_container_class + '">' +
                                '<a href="#!" class="listSliceMore ' +
                                options.link_class + '">' + options.more_text + '</a>');
                }
            });

        }

        /**
         * uses the slideToggle method to toggle between showing more or less
         * list items in the initiated list.
         */
        function toggleMoreLess(btn){
            var dad = btn.parent().parent();
            dad.find('li.listSliceItem' +
                     ':gt(' + (options.default_items - 1).toString() +
                     ')').slideToggle(options.animation_time);
            btn.text(btn.text() == options.more_text ? options.less_text : options.more_text);
        }

        /**
         * Initiate the sliceList method and more link click method.
         */
        sliceList();
        $('a.listSliceMore').click( function() {
            toggleMoreLess($(this));
            return false; // Cancel Default Anchor Action.
                          // This prevents appending '#!' to the end of the url
        });
    }

    // Default options
    $.fn.listSlice.options = {

        // Default number of items to be displayed (Accepts Integer only).
        default_items: 5,

        // More Anchor link's label when hiding items (Accepts Strings only).
        more_text: 'More',

        // More Anchor link's label when showing all items (Accepts Strings only).
        less_text: 'Less',

        // Class names to be applied to the More link (Accepts Strings only).
        link_class: 'more link',

        // Class names to be applied to the More link's container (Accepts Strings only).
        link_container_class: 'more',

        // An element that wraps the more link. (Accepts Strings only)
        link_container: 'li',

        // Amount of time in miliseconds the show/hide animation should run.(Accepts Integer and Strings)
        animation_time: 500,

        // Ignore 'li' items to be counted as the part of list which have following classes
        // or id's. A comma separated list of classes or id's or both. (Accepts Strings Only)
        ignore_list: 'ignore, no-include, all',
    }

})(jQuery);

现在,这是场景。假设我的 HTML 格式如下:

<div id ="one">
    <ul class="item_list">
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
    </ul>
</div>

<div id ="two">
    <ul class="item_list">
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
    </ul>
</div>

<div id ="three">
    <ul class="item_list">
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
    </ul>
</div>

<div id ="four">
    <ul class="item_list">
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
        <li> Sample Item </li>
    </ul>
</div>

我启动我的插件如下:

<script type="text/javascript">
    $('.item_list').listSlice();
</script>

它工作得很好。但是假设我想为以上四个元素设置不同的选项,我将它们分别绑定如下。

<script type="text/javascript">
    $('div#one .item_list').listSlice({
        some_option: some_value,
    });
    $('div#two .item_list').listSlice({
        some_option: some_value,
    });
    $('div#three .item_list').listSlice({
        some_option: some_value,
    });
    $('div#four .item_list').listSlice({
        some_option: some_value,
    });
</script>

这是它变得有点混乱的时候。我在这里看到的行为是:

  1. 如果我单击more/less第一个列表的链接,Click 会被触发 4 次,因此动画会上下滑动 4 次。

  2. 如果我点击第二个列表的更多/更少链接,点击会被触发 3 次。

  3. 如果我点击第三个列表的更多/更少链接,点击会被触发 2 次。

  4. 如果我单击第四个列表的更多/更少链接,它工作正常。(即点击仅被触发1次)

这是一个显示我面临的问题的jsfiddle 。

有人知道是什么原因造成的吗?谢谢。

4

2 回答 2

1

在您的更多链接上添加preventDefault()到您的点击处理程序。这会将操作限制为仅toggleMoreLess()功能:

    $('a.listSliceMore').click( function() {
        toggleMoreLess($(this));
        e.preventDefault();
        return false; // Cancel Default Anchor Action.
                      // This prevents appending '#!' to the end of the url
    });
于 2013-05-09T14:38:05.337 回答
0

多次实例化插件,将click事件绑定到a.listSliceMore元素实例化插件的次数。我通过确保取消绑定上一个点击事件来修复它。

    $('a.listSliceMore').unbind('click').click( function() {
        toggleMoreLess($(this));
        return false; // Cancel Default Anchor Action.
                      // This prevents appending '#!' to the end of the url
    });
于 2013-05-10T06:32:00.420 回答