jQuery 根据所选选项的宽度自动调整 SELECT 元素的大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20091481/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 00:57:41  来源:igfitidea点击:

Auto resizing the SELECT element according to selected OPTION's width

jqueryselectresizeautoresizedom-manipulation

提问by Th3Alchemist

I've got this selectelement with different optionin it. Normally the selectelement would get its width from the biggest optionelement, but I want the selectelement to have the default optionvalue's width which is shorter. When the user selects another option, the selectelement should resize itself so the whole text is always visible in the element.

我有这个select不同的元素option。通常select元素会从最大的option元素获取其宽度,但我希望select元素具有option更短的默认值宽度。当用户选择另一个 时optionselect元素应该调整自身大小,以便整个文本在元素中始终可见。

$(document).ready(function() {
    $('select').change(function(){
        $(this).width($('select option:selected').width());
    });
});

Problem:

问题:

  • On Chrome (Canary) it always gets a width returned of 0.
  • On Firefox the width get's added and not resized when selected a shorter option.
  • Safari: Same result as Chrome.
  • 在 Chrome (Canary) 上,它总是返回 0 的宽度。
  • 在 Firefox 上,选择较短的选项时会添加宽度而不是调整大小。
  • Safari:结果与 Chrome 相同。

Demo @ JSFiddle

演示@JSFiddle

回答by kmas

You are right there is no easy or built-in way to get the size of a particular select option. Here is a JsFiddlethat does what you want.

您是对的,没有简单或内置的方法来获取特定选择选项的大小。这是一个可以执行您想要的操作的JsFiddle

It is okay with the latest versions of Chrome, Firefox, IE, Opera and Safari.

最新版本的没问题Chrome, Firefox, IE, Opera and Safari

I have added a hidden select #width_tmp_selectto compute the width of the visible select #resizing_selectthat we want to be auto resizing. We set the hidden select to have a single option, whose text is that of the currently-selected option of the visible select. Then we use the width of the hidden select as the width of the visible select. Note that using a hidden span instead of a hidden select works pretty well, but the width will be a little off as pointed out by sami-al-subhi in the comment below.

我添加了一个隐藏的选择#width_tmp_select来计算#resizing_select我们想要自动调整大小的可见选择的宽度。我们将隐藏的选择设置为具有单个选项,其文本是可见选择的当前选定选项的文本。然后我们使用隐藏选择的宽度作为可见选择的宽度。请注意,使用隐藏的跨度而不是隐藏的选择效果很好,但正如 sami-al-subhi 在下面的评论中指出的那样,宽度会稍微偏离。

$(document).ready(function() {
  $('#resizing_select').change(function(){
    $("#width_tmp_option").html($('#resizing_select option:selected').text()); 
    $(this).width($("#width_tmp_select").width());  
  });
});
#resizing_select {
  width: 50px;
} 
 
#width_tmp_select{
  display : none;
} 
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>

<select id="resizing_select">
  <option>All</option>
  <option>Longer</option>
  <option>A very very long string...</option>
</select>

<select id="width_tmp_select">
  <option id="width_tmp_option"></option>
</select>

回答by KyleMit

Here's a plugin I just wrote for this questionthat dynamically creates and destroys a mock spanso it doesn't clutter up your html. This helps separate concerns, lets you delegate that functionality, and allows for easy reuse across multiple elements.

这是我刚刚为这个问题编写的一个插件,它动态地创建和销毁一个模拟,span这样它就不会弄乱你的 html。这有助于分离关注点,让您委托该功能,并允许跨多个元素轻松重用。

Include this JS anywhere:

在任何地方包含这个 JS:

(function($, window){
  var arrowWidth = 30;

  $.fn.resizeselect = function(settings) {  
    return this.each(function() { 

      $(this).change(function(){
        var $this = $(this);

        // create test element
        var text = $this.find("option:selected").text();
        var $test = $("<span>").html(text).css({
            "font-size": $this.css("font-size"), // ensures same size text
            "visibility": "hidden"               // prevents FOUC
        });


        // add to parent, get width, and get out
        $test.appendTo($this.parent());
        var width = $test.width();
        $test.remove();

        // set select width
        $this.width(width + arrowWidth);

        // run on start
      }).change();

    });
  };

  // run by default
  $("select.resizeselect").resizeselect();                       

})(jQuery, window);

You can initialize the plugin in one of two ways:

您可以通过以下两种方式之一初始化插件:

  1. HTML- Add the class .resizeselectto any select element:

    <select class="btn btn-select resizeselect">
      <option>All</option>
      <option>Longer</option>
      <option>A very very long string...</option>
    </select>
    
  2. JavaScript- Call .resizeselect()on any jQuery object:

    $("select").resizeselect()
    
  1. HTML- 将类添加.resizeselect到任何选择元素:

    <select class="btn btn-select resizeselect">
      <option>All</option>
      <option>Longer</option>
      <option>A very very long string...</option>
    </select>
    
  2. JavaScript- 调用.resizeselect()任何 jQuery 对象:

    $("select").resizeselect()
    

Here's a Demo in jsFiddle

这是jsFiddle 中的一个演示

Here's a Demo in Stack Snippets:

这是 Stack Snippets 中的一个演示:

(function($, window){
  var arrowWidth = 30;

  $.fn.resizeselect = function(settings) {  
    return this.each(function() { 

      $(this).change(function(){
        var $this = $(this);

        // create test element
        var text = $this.find("option:selected").text();
        var $test = $("<span>").html(text).css({
         "font-size": $this.css("font-size"), // ensures same size text
            "visibility": "hidden"               // prevents FOUC
        });
        
        // add to parent, get width, and get out
        $test.appendTo($this.parent());
        var width = $test.width();
        $test.remove();

        // set select width
        $this.width(width + arrowWidth);

        // run on start
      }).change();

    });
  };

  // run by default
  $("select.resizeselect").resizeselect();                       

})(jQuery, window);
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>

<select class="resizeselect">
  <option>All</option>
  <option>Longer</option>
  <option>A very very long string...</option>
</select>

Updated to include sizing suggestions from Garywoo& Eric Warnke

更新以包含来自GarywooEric Warnke 的尺码建议

回答by Jo?o Pimentel Ferreira

This working solution makes use here of a temporary auxiliary selectinto which the selected option from the main select is cloned, such that one can assess the true width which the main selectshould have.

这个工作解决方案在这里使用了一个临时辅助select,从主选择中选择的选项被克隆到其中,这样人们就可以评估主select应该具有的真实宽度。

The nice thing here is that you just add this code and it's applicable to every selects, thus no need to idsand extra naming.

这里的好处是您只需添加此代码,它适用于每个选择,因此无需ids额外命名。

$('select').change(function(){
  var text = $(this).find('option:selected').text()
  var $aux = $('<select/>').append($('<option/>').text(text))
  $(this).after($aux)
  $(this).width($aux.width())
  $aux.remove()
}).change()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select>
  <option>REALLY LONG TEXT, REALLY LONG TEXT, REALLY LONG TEXT</option>
  <option>ABCDEFGHIJKL</option>
  <option>ABC</option>
</select>

回答by Divyesh

Try the following simple JavaScript and convert it in jQuery :)

尝试以下简单的 JavaScript 并将其转换为 jQuery :)

<html><head><title>Auto size select</title>

<script>
var resized = false;

function resizeSelect(selected) {
  if (resized) return;
  var sel = document.getElementById('select');
  for (var i=0; i<sel.options.length; i++) {
    sel.options[i].title=sel.options[i].innerHTML;
    if (i!=sel.options.selectedIndex) sel.options[i].innerHTML='';
  }
  resized = true;
  sel.blur();
}

function restoreSelect() {
  if (!resized) return;
  var sel = document.getElementById('select');
  for (var i=0; i<sel.options.length; i++) {
    sel.options[i].innerHTML=sel.options[i].title;
  }  
  resized = false;
}
</script>

</head>
<body onload="resizeSelect(this.selectedItem)">
<select id="select" 
  onchange="resizeSelect(this.selectedItem)"
  onblur="resizeSelect(this.selectedItem)"
  onfocus="restoreSelect()">
<option>text text</option>
<option>text text text text text</option>
<option>text text text </option>
<option>text text text text </option>
<option>text</option>
<option>text text text text text text text text text</option>
<option>text text</option>
</select>
</body></html>

Here is a jsfiddle for it: https://jsfiddle.net/sm4dnwuf/1/

这是一个 jsfiddle:https://jsfiddle.net/sm4dnwuf/1/

Basically what it does is temporarily remove unselected elements when it is not in focus (causing it to size to just the size of the selected).

基本上它的作用是在未聚焦时临时删除未选择的元素(使其大小为所选元素的大小)。

回答by Hyman

You can use a simple function:

您可以使用一个简单的函数:

// Function that helps to get the select element width.
$.fn.getSelectWidth = function() {
  var width = Math.round($(this).wrap('<span></span>').width());
  $(this).unwrap();
  return width;
}

Then just use it on your form select element:

然后只需在您的表单选择元素上使用它:

$(this).getSelectWidth();

回答by Antwerp Danish

Here's yet another plain jQuery solution:

这是另一个简单的 jQuery 解决方案:

$('#mySelect').change(function(){
    var $selectList = $(this);

    var $selectedOption = $selectList.children('[value="' + this.value + '"]')
        .attr('selected', true);
    var selectedIndex = $selectedOption.index();

    var $nonSelectedOptions = $selectList.children().not($selectedOption)
        .remove()
        .attr('selected', false);

    // Reset and calculate new fixed width having only selected option as a child
    $selectList.width('auto').width($selectList.width());

    // Add options back and put selected option in the right place on the list
    $selectedOption.remove();
    $selectList.append($nonSelectedOptions);
    if (selectedIndex >= $nonSelectedOptions.length) {
         $selectList.append($selectedOption);
    } else {
         $selectList.children().eq(selectedIndex).before($selectedOption);
    }
});

回答by Arye

Here is how I've achieved the following behavior:

这是我如何实现以下行为:

  1. On document load: The select's width is already based on the width of the selected option (repainting does not occur).

  2. On change: The select's width is updated to the width of the newly selected option.

  1. 文档加载时:选择的宽度已经基于所选选项的宽度(不会重新绘制)。

  2. 更改时:选择的宽度更新为新选择的选项的宽度。

/* WIDTH, ADJUSTMENT, CONTENT BASED */
$( document ).on( 'change', '.width-content-based', function(){
 let text_modified_font;
 let text_modified_string;
 let descendants_emptied_elements;
 
 text_modified_font =
  $( this ).css( 'font-weight' ) + ' ' + $( this ).css( 'font-size' ) + ' ' + $( this ).css( 'font-family' );
 
 if
 (
  $( this ).is( 'select' )
 )
 {
  text_modified_string =
   $( this ).find( ':selected' ).text();
  
  descendants_emptied_elements =
   $( this ).find( '[data-text]' );
 }
 
 else
 {
  text_modified_string =
   $( this ).val();
 }
 
 $( this ).css( { 'width': text_width_estimate( text_modified_string, text_modified_font ) + 'px' } );
 
 if
 (
  descendants_emptied_elements.length
 )
 {
  descendants_emptied_elements.each( function(){
   $( this ).text( $( this ).attr( 'data-text' ) ).removeAttr( 'data-text' );
  });
 }
});

/* DOCUMENT, ON READY */
$( document ).ready( function(){
 
 $( '.width-content-based' ).trigger( 'change' );
 
});

/* TEXT WIDTH ESTIMATE */ function text_width_estimate( text, font ) { let canvas = text_width_estimate.canvas || ( text_width_estimate.canvas = document.createElement( 'canvas' ) ); let context = canvas.getContext( '2d' ); context.font = font; let metrics = context.measureText( text ); return metrics.width + 3; }
select { -webkit-appearance: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<select class="width-content-based">
 <option value="AF" data-text="Afghanistan"></option>
 <option value="AX" data-text="?land Islands"></option>
 <option value="AL" selected>Albania</option>
</select>

回答by Dheeraj

You can try this also

你也可以试试这个

select option{width:0; }
select option:hover{width:auto;}