【问题标题】:Auto resizing the SELECT element according to selected OPTION's width根据所选 OPTION 的宽度自动调整 SELECT 元素的大小
【发布时间】:2013-12-04 04:22:41
【问题描述】:

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

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

问题:

  • 在 Chrome (Canary) 上,返回的宽度始终为 0。
  • 在Firefox上,在选择较短的选项时,宽度会添加宽度并未调整大小。
  • Safari:结果与 Chrome 相同。

Demo @ JSFiddle

【问题讨论】:

  • 没有可靠的方法来获取option 元素的宽度。您可以改为获取 text 属性的长度,并据此猜测所需的宽度。
  • @RoryMcCrossan 我也想过,但是在不同的浏览器屏幕分辨率设置上不会得到不同的结果?我还发现了这个可能的解决方案:jsfiddle.net/zERB7/3
  • 这里的简单解决方案:stackoverflow.com/a/55343177/1243247
  • 这是一个更现代的 vanilla JS 方法来解决这个问题:stackoverflow.com/a/67239947/4168960

标签: jquery select resize autoresize dom-manipulation


【解决方案1】:

您是对的,没有简单或内置的方法来获取特定选择选项的大小。这是一个JsFiddle,可以满足您的需求。

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

我添加了一个隐藏选择 #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>

【讨论】:

  • 您的小提琴链接与 OP 相同。
  • 好方法,但您必须确保&lt;option&gt; 文本与&lt;span&gt; 具有相同的字体/大小。如果你去掉#width_tmp{display : none;},你会发现&lt;span&gt;更大。这将导致&lt;select&gt; 比应有的更大。文本越长,&lt;select&gt; 中的空白空间越大。
  • 这是一个纯 javascript 尝试版本:jsfiddle.net/FSsG8/635 你也可能通过尝试匹配两个选择之间的字体来获得一些吸引力,有点相似:stackoverflow.com/questions/6385533/…
  • 检查我的解决方案,它更简单整洁:) stackoverflow.com/a/55343177/1243247
  • 这是一个更现代的 vanilla JS 方法来解决这个问题:stackoverflow.com/a/67239947/4168960
【解决方案2】:

你也可以试试这个

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

【讨论】:

  • 这已被否决,但它似乎在 Firefox(不是 Chrome)中有效。
【解决方案3】:

尝试以下简单的 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>

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

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

【讨论】:

    【解决方案4】:

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

    // 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;
    }
    

    然后在你的表单选择元素上使用它:

    $(this).getSelectWidth();
    

    【讨论】:

      【解决方案5】:

      这是我刚刚为this question 编写的插件,它可以动态创建和销毁模拟span,因此它不会弄乱您的html。这有助于分离关注点,让您可以委派该功能,并允许跨多个元素轻松重用。

      在任何地方包含这个 JS:

      (function($, window){
        $(function() {
          let arrowWidth = 30;
      
          $.fn.resizeselect = function(settings) {  
            return this.each(function() { 
      
              $(this).change(function(){
                let $this = $(this);
      
                // get font-weight, font-size, and font-family
                let style = window.getComputedStyle(this)
                let { fontWeight, fontSize, fontFamily } = style
      
                // create test element
                let text = $this.find("option:selected").text();
                let $test = $("<span>").html(text).css({
                  "font-size": fontSize, 
                  "font-weight": fontWeight, 
                  "font-family": fontFamily,
                  "visibility": "hidden" // prevents FOUC
                });
      
                // add to body, get width, and get out
                $test.appendTo($this.parent());
                let width = $test.width();
                $test.remove();
      
                // set select width
                $this.width(width + arrowWidth);
      
                // run on start
              }).change();
      
            });
          };
      
          // run by default
          $("select.resizeselect").resizeselect();                       
        })
      })(jQuery, window);
      

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

      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 - 在任何 jQuery 对象上调用 .resizeselect()

        $("select").<b>resizeselect</b>()

      jsFiddle 和 StackSnippets 中的演示:

      (function($, window){
        $(function() {
          let arrowWidth = 30;
      
          $.fn.resizeselect = function(settings) {  
            return this.each(function() { 
      
              $(this).change(function(){
                let $this = $(this);
      
                // get font-weight, font-size, and font-family
                let style = window.getComputedStyle(this)
                let { fontWeight, fontSize, fontFamily } = style
      
                // create test element
                let text = $this.find("option:selected").text();
                let $test = $("<span>").html(text).css({
                  "font-size": fontSize, 
                  "font-weight": fontWeight, 
                  "font-family": fontFamily,
                  "visibility": "hidden" // prevents FOUC
                });
      
                // add to body, get width, and get out
                $test.appendTo($this.parent());
                let 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>

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

      【讨论】:

      • 我建议将行 var $test = $("&lt;span&gt;").html(text); 更改为 var $test = $("&lt;span style=\"font-size:"+$this.css("font-size")+"\"&gt;").html(text); 以确保创建的临时跨度的字体大小与选择元素的字体大小相匹配。如果 span 的字体大小变小或变大,动态调整大小将被大小差异抵消。
      • 主要工作!我使用 Bootstrap 的默认 CSS 总是将选择元素的宽度设置为 100%,这会返回不正确的宽度。我将追加从 body 更改为 #myForm$("&lt;span&gt;") 更改为 $('&lt;span style="visibility:hidden"&gt;') 只是为了让我安心。
      • 不幸的是,它不能在 Ipad/Android 平板电脑上运行,有什么想法吗?我认为可能是这些设备中选项的字体大小不同,但如果我设置了静态字体大小,它并不能解决它
      • 我通过为表单元素提供静态字体大小来修复上述问题,我上面的建议是在脚本本身上提供静态字体大小
      • 这里有一个更现代的 vanilla JS 方法来解决这个问题:stackoverflow.com/a/67239947/4168960
      【解决方案6】:

      这是另一个简单的 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);
          }
      });
      

      【讨论】:

        【解决方案7】:

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

        这里的好处是您只需添加此代码,它适用于每个选择,因此无需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>

        【讨论】:

          【解决方案8】:

          这是我实现以下行为的方式:

          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>

          【讨论】:

          • 很难阅读带有格式的代码示例 - 稍微清理一下可能是个好主意:)
          【解决方案9】:

          这里有一个更现代的 vanilla JS 方法来解决这个问题。它或多或少与this answer 中的原理相同,只是没有 jQuery。

          1. 获取选择元素并监听它的变化。
          2. 创建一个新的选择元素和选项,并将当前selectedIndex 的文本传递给选项。
          3. position: fixedvisibility: hidden 样式添加到新的选择元素。这样可以确保它不会影响您的布局,但仍然可以测量其边界框。
          4. 将选项附加到选择。
          5. 将选择附加到原始选择元素。
          6. 使用getBoundingClientRect().width 获取新的所需尺寸
          7. 根据新的尺寸设置原来的宽度。
          8. 删除新的。
          9. 调度更改事件以最初触发此逻辑。

          const select = document.querySelector('select')
          
          select.addEventListener('change', (event) => {
            let tempSelect = document.createElement('select'),
                tempOption = document.createElement('option');
          
            tempOption.textContent = event.target.options[event.target.selectedIndex].text;
            tempSelect.style.cssText += `
                visibility: hidden;
                position: fixed;
                `;
            tempSelect.appendChild(tempOption);
            event.target.after(tempSelect);
            
            const tempSelectWidth = tempSelect.getBoundingClientRect().width;
            event.target.style.width = `${tempSelectWidth}px`;
            tempSelect.remove();
          });
          
          select.dispatchEvent(new Event('change'));
          <select>
            <option>Short option</option>
            <option>Some longer option</option>
            <option>A very long option with a lot of text</option>
          </select>

          【讨论】:

            【解决方案10】:

            这里有一个示例,说明从选择框自动调整大小开始,然后在选择新框时如何自动调整宽度。

            只需将其复制并粘贴到 Visual Studio 代码文档中,并将其命名为 index.html,然后双击该文件(对于超级新手)。

             $(document).ready(function() {
                // Auto set the width of the select box for Manufacture on startup
                $("#width_tmp_option").html($('#Manufacture')[0][0].label); 
                  $('#Manufacture').width($('#width_tmp_select').width());
            
                // Adust the width of the select box each time Manufacture is changed
                $('#Manufacture').change(function(){
                  $("#width_tmp_option").html($('#Manufacture option:selected').text()); 
                  $(this).width($("#width_tmp_select").width());
                });
            });
            #Manufacture {
              font-size:17px;
            } 
            #width_tmp_select{
              display : none;
              font-size:17px;
            } 
            <!-- JS (Jquery) -->
            <script src="https://code.jquery.com/jquery-3.6.0.js"
            integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
            crossorigin="anonymous"></script>
            <!-- HTML -->
            <!-- These are hidden dummy selects that I use to store some html in them and then retrieve the width to resize my select boxes. -->
            <select id="width_tmp_select">
              <option id="width_tmp_option"></option>
            </select>
            
            <select id="Manufacture">
                <option>Toyota</option>
                <option>Ford</option>
                <option>Lamborghini</option>
            </select>

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-07-31
              • 1970-01-01
              • 2023-04-03
              • 2015-03-03
              • 2012-06-19
              • 2017-07-28
              • 1970-01-01
              相关资源
              最近更新 更多