【问题标题】:Select all options in optgroup选择 optgroup 中的所有选项
【发布时间】:2012-10-24 10:15:15
【问题描述】:

我有一个带有options 分组的select 元素。单击option 时,我需要选择(或取消选择)optgroup 中的所有options。我还需要能够同时选择多个optgroups。

我希望它的工作方式是这样的:

  • 如果未选择任何内容,我想单击一个选项并选择同一 optgroup 中的所有选项。
  • 如果已经选择了一个或多个 optgroup,我想单击另一个 optgroup 中的一个选项,然后选择所有这些选项。
  • 如果已经选择了一个或多个 optgroup,我希望能够按住 Ctrl 键单击未选择的 optgroup 中的一个选项,并选择该 optgroup 中的所有选项。
  • 如果已经选择了一个或多个 optgroup,我希望能够按住 Ctrl 键单击所选 optgroup 中的一个选项,并取消选择该组中的所有选项。

查看 Stack Overflow 上的其他答案,我创建了以下内容:

HTML:

<select multiple="multiple" size="10">
    <optgroup label="Queen">
        <option value="Mercury">Freddie</option>
        <option value="May">Brian</option>
        <option value="Taylor">Roger</option>
        <option value="Deacon">John</option>
    </optgroup>
    <optgroup label="Pink Floyd">
        <option value="Waters">Roger</option>
        <option value="Gilmour">David</option>    
        <option value="Mason">Nick</option>                
        <option value="Wright">Richard</option>
    </optgroup>
</select>

jQuery:

$('select').click(selectSiblings);
function selectSiblings(ev) {
    var clickedOption = $(ev.target);
    var siblings = clickedOption.siblings();
    if (clickedOption.is(":selected")) {
        siblings.attr("selected", "selected");
    } else {
        siblings.removeAttr("selected");
    }
}​

我在这里做了一个例子:http://jsfiddle.net/mflodin/Ndkct/ (遗憾的是 jsFiddle 似乎不再支持 IE8。)

这在 Firefox (16.0) 中按预期工作,但在 IE8 中根本不起作用。从其他答案中我发现IE8无法处理optgroupoption上的click事件,这就是我将它绑定到select然后使用$(ev.target)的原因。但在 IE8 中,$(ev.target) 仍然指向整个select,而不是指向被点击的option。如何找出点击了哪个option(或包含optgroup)以及它是被选中还是被取消选中?

另一个意外的行为,但相比之下较小,是在 Chrome (20.0) 中,直到鼠标离开 select 才会发生取消选择。有人知道解决方法吗? ​

【问题讨论】:

    标签: javascript jquery html


    【解决方案1】:

    不是选择选项跨浏览器问题的具体问题的答案,我认为已经回答了,但是选择数据并将其传递回服务器的问题的解决方案是将您的标记更改为哪个更适合多选

    如果你改用复选框,你可以把它们放在一个列表中,并添加增强js来全选和取消全选

    http://jsfiddle.net/Ndkct/43/

    <dl>
    <dt>Queen</dt>
    <dd>
        <ul>
            <li>
                <input id="Mercury" name="bandmembers" value="Mercury" type="checkbox" />
                <label for="Mercury">Freddie</label>
            </li>    
            <li>
                <input id="May" name="bandmembers" value="May" type="checkbox" />
                <label for="May">Brian</label>
            </li>    
            <li>
                <input id="Taylor" name="bandmembers" value="Taylor" type="checkbox" />
                <label for="Taylor">Roger</label>
            </li>    
            <li>
                <input id="Deacon" name="bandmembers" value="Deacon" type="checkbox" />
                <label for="Deacon">John</label>
            </li>    
        </ul>
    </dd>
    <dt>Pink Floyd</dt> ...
    

    现在的 js 已经够简单了

    $("dt")
        .css("cursor","pointer")
        .click(function(){
            var $el = $(this).next();
            var $checks = $el.find(":checkbox");
            if($checks.is(":not(:checked)")){
               $checks.attr("checked",true); 
            }else{
               $checks.attr("checked",false); 
            }
        });
    

    (这个小提琴http://jsfiddle.net/Ndkct/44/添加了一个父复选框以使其更有用)

    【讨论】:

    • 不错的替代解决方案!对于用户来说,它甚至可能更清楚。
    • ta,我也这么认为。列表框和整个左移/控制按钮多选的东西也不是用户友好的。您具有层次结构的优势,可以在这里快速选择许多项目,只需查看它就可以告诉您发生了什么
    【解决方案2】:

    由于 Internet Explorer 版本 10 仍然不支持 optgroupoption 上的任何有用事件,因此任何针对此问题的跨浏览器解决方案都不能依赖来自这些元素的直接事件。

    注意: MSDN 文档声称 optgroup 支持 click 事件,但从 IE 10 开始,这似乎仍然不是现实:http://msdn.microsoft.com/en-us/library/ie/ms535876(v=vs.85).aspx

    我在 Chrome 27、Firefox 20、Safari 6、IE 9 和 IE 10 中测试了以下内容(我目前无法访问 IE 8)。

    这是一个你可以玩的例子:http://jsfiddle.net/potatosalad/Ndkct/38/

    // Detect toggle key (toggle selection)
    $('select')
        .on('mousedown', function(event) {
            // toggleKey = Command for Mac OS X; Control for others
            var toggleKey = (!event.metaKey && event.ctrlKey && !(/Mac OS/.test(navigator.userAgent))) ? event.ctrlKey : event.metaKey;
            if (toggleKey === true) {
                $(this).data('toggleKey', true);
            }
            $(this).data('_mousedown', true);
        })
        .on('mouseup', function() {
            $(this).data('_mousedown', null);
        });
    // Chrome fix for mouseup outside select
    $(document).on('mouseup', ':not(select)', function() {
        var $select = $('select');
        if ($select.data('_mousedown') === true) {
            $select.data('_mousedown', null);
            $select.trigger('change');
        }
    });
    
    $('select')
        .on('focus',  storeState)
        .on('change', changeState);
    
    function storeState() {
        $(this).data('previousGroup', $('option:selected', this).closest('optgroup'));
        $(this).data('previousVal',   $(this).val());
    };
    
    function changeState() {
        var select = this,
            args   = Array.prototype.slice.call(arguments);
    
        var previousGroup = $(select).data('previousGroup'),
            previousVal   = $(select).data('previousVal');
        var currentGroup  = null,
            currentVal    = $(select).val();
    
        var selected = $('option:selected', select),
            groups   = selected.closest('optgroup');
    
        console.log("[change] %o -> %o", previousVal, currentVal);
    
        if ((previousVal === currentVal) && (groups && groups.length == 1)) {
            // selected options have not changed
            // AND
            // only 1 optgroup is selected
            // -> do nothing
        } else if (currentVal === null || currentVal.length === 0) {
            // zero options selected
            // -> store state and do nothing
            storeState.apply(select, args);
        } else { // a select/deselect change has occurred
            if ($(select).data('toggleKey') === true
                && (previousVal !== null && previousGroup !== null && groups !== null)
                && (previousVal.length > currentVal.length)
                && (previousGroup.length === groups.length)
                && (previousGroup.get(0) === groups.get(0))) {
                // options within the same optgroup have been deselected
                // -> deselect all and store state
                $(select).val(null);
                storeState.apply(select, args);
            } else if (currentVal.length === 1) {
                // single option selected
                // -> use groups
                currentGroup = groups;
            } else if (groups.length === 1) {
                // multiple options selected within same optgroup
                // -> use groups
                currentGroup = groups;
            } else {
                // multiple options selected spanning multiple optgroups
                // -> use last optgroup
                currentGroup = groups.last();
            }
        }
    
        $(select).data('toggleKey', null);
    
        if (currentGroup !== null) {
            $('optgroup', select).not(currentGroup).children(':selected').attr('selected', false);
            $(currentGroup).children(':not(:selected)').attr('selected', true);
            storeState.apply(select, args);
        }
    };
    

    它的工作原理是将先前选择的组和选项存储在 select 元素上,并确定应该选择(或取消选择)哪个 optgroup

    可以根据开发人员的需要更改某些行为。例如,在选择跨越多个optgroups 的多个options 的情况下(通过单击并向下拖动,如屏幕截图所示):

    这种情况下的默认冲突解决方案是始终使用最后一个optgroup,但可以更改为始终使用第一个,或具有最多已选择选项的optgroup

    【讨论】:

    • 这适用于选择单个 optgroup,但不适用于多个 optgroup。我会更新我的问题,以更清楚地说明我需要什么。根据我的需要修改代码可能很简单,但不幸的是我现在没有时间研究它。尽管如此,我仍会为您迄今为止所做的工作以及有关 IE 兼容性的信息奖励 +1。
    【解决方案3】:

    这个解决了问题,你只需要在init选择后添加这个代码。

    $( '.chzn-results .group-result' ).each( function () {
        var self      = $( this )
            , options = $( '~li', self )
            , next    = options.filter( '.group-result' ).get( 0 )
        ;
        self.data( 'chzn-options', options.slice( 0, options.index( next ) ) );
    } )
    .click( function () { 
        $( this ).data( 'chzn-options' ).mouseup()
     } )
    .hover( function () { 
        $( this ).data( 'chzn-options' ).addClass( 'highlighted' );
     }, function () { 
        $( this ).data( 'chzn-options' ).removeClass( 'highlighted' );
     } )
    .css( { cursor: 'pointer' } )
    

    感谢 adriengibrat 在 github 上发布了此修复:
    https://github.com/harvesthq/chosen/issues/323

    【讨论】:

      【解决方案4】:
          <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
      
      
      $(document).ready(function() {
          $('select').click(function(tar) {
              var justClickValue = tar.target.value;
      
              var selectedGroup = $('option[value="'+justClickValue+'"]').parent();
      
              if (selectedGroup.hasClass("allSelected")) {
                  selectedGroup.removeClass("allSelected");
                  $("option").each(function() {
                      $(this).removeAttr("selected");
                  });
              } else {
                  $(".allSelected").removeClass("allSelected");
                  selectedGroup.addClass("allSelected");
                  $(".allSelected option").each(function() {
                      $(this).attr("selected", "selected");
                  });
              }
          });
      });
      

      【讨论】:

        【解决方案5】:

        根据您的问题选择/取消选择所有选项。 你可以试试下面的代码,可能对你有帮助。

        代码:

        javascript代码:

         <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js">
        

               $(function(){
        
                        $('#allcheck').click(function(){
                        var chk=$('#select_option >optgroup > option');
                        chk.each(function(){
                          $(this).attr('selected','selected');
                    });
           });  
        $('#alluncheck').click(function(){
        
                      var chk=$('#select_option >optgroup > option');
                      chk.each(function(){
                      $(this).removeAttr('selected');
                  });
             });});
        

        HTML 代码:

               <select multiple="multiple" size="10" id="select_option" name="option_value[]">
                  <optgroup label="Queen">
                    <option value="Mercury">Freddie</option>
                    <option value="May">Brian</option>
                    <option value="Taylor">Roger</option>
                    <option value="Deacon">John</option>
                </optgroup>
                <optgroup label="Pink Floyd">
                    <option value="Waters">Roger</option>
                    <option value="Gilmour">David</option>    
                    <option value="Mason">Nick</option>                
                    <option value="Wright">Richard</option>
               </optgroup>
         </select>
        <br>
               <strong>Select&nbsp;&nbsp;<a style="cursor:pointer;" id="allcheck">All</a>
          &nbsp;|&nbsp;<a style="cursor:pointer;"  id="alluncheck">None</a></strong>
        

        【讨论】:

        • 这与我想要的无关。我想点击一个option而不是一个链接来选择所有options
        【解决方案6】:

        希望这会奏效

        $("#SelectID").live("click",function() {
        var elements = this.options; //or document.getElementById("SelectID").options;
        for(var i = 0; i < elements.length; i++){
           if(!elements[i].selected)
            elements[i].selected = true;
        }
        }
        

        【讨论】:

        • 这不是我想要的。这将选择所有optgroups 中的所有option 元素。它应该只选择那些与被点击的option 相同的optgroup
        • 您还缺少 live 函数的结尾括号。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-01
        相关资源
        最近更新 更多