【问题标题】:Adjust width of select element according to selected option's width根据所选选项的宽度调整选择元素的宽度
【发布时间】:2015-02-03 20:26:09
【问题描述】:

我希望选择元素具有更短的默认选项值宽度。当用户选择另一个选项时,选择元素应自行调整大小,以便整个文本始终在元素中可见。

我在Auto resizing the SELECT element according to selected OPTION's width这个问题中找到了解决办法,但是bootstrap不能用,不知道为什么。

这是我的尝试:

$(document).ready(function() {
  $('select').change(function(){
    $("#width_tmp").html($('select option:selected').text());
    // 30 : the size of the down arrow of the select box 
    $(this).width($("#width_tmp").width()+30); 
  });
});
.btn-select {
  color: #333;
  background-color: #f5f5f5;
  border-color: #ccc;
  padding:7px;
}
select {
  width: 60px;
}

#width_tmp{
  display : none;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>

<div class="form-group">
  <div class="input-group">

    <span class="input-group-btn">
      <select class="btn btn-select align-left">
        <option>All</option>
        <option>Longer</option>
        <option>A very very long string...</option>
      </select>
      <span id="width_tmp"></span>
    </span>

    <input type="text" class="form-control" placeholder="Search by...">

    <span class="input-group-btn">
      <button class="btn btn-default" type="button">
        <i class="fa fa-search"></i>
      </button>
    </span>

  </div>
</div>

【问题讨论】:

标签: javascript jquery twitter-bootstrap twitter-bootstrap-3 html-select


【解决方案1】:

出现此问题是因为#width_tmp 嵌套在.input-group-btn 下,因此它从引导程序继承font-size: 0; 属性。因此,计算出的元素宽度始终为零:

要解决此问题,只需移动 &lt;span id="width_tmp"&gt;&lt;/span&gt; 使其不在输入组内。


纯JS解决方案

// resize on initial load
document.querySelectorAll("select").forEach(resizeSelect)

// delegated listener on change
document.body.addEventListener("change", (e) => {
    if (e.target.matches("select")) {
        resizeSelect(e.target)
    }
})

function resizeSelect(sel) {
  let tempOption = document.createElement('option');
  tempOption.textContent = sel.selectedOptions[0].textContent;

  let tempSelect = document.createElement('select');
  tempSelect.style.visibility = "hidden";
  tempSelect.style.position = "fixed"
  tempSelect.appendChild(tempOption);
  
  sel.after(tempSelect);
  sel.style.width = `${+tempSelect.clientWidth + 4}px`;
  tempSelect.remove();
}

jsFiddle 中的演示和堆栈片段

// resize on initial load
document.querySelectorAll("select").forEach(resizeSelect)

// delegated listener on change
document.body.addEventListener("change", (e) => {
    if (e.target.matches("select")) {
        resizeSelect(e.target)
    }
})

function resizeSelect(sel) {
  let tempOption = document.createElement('option');
  tempOption.textContent = sel.selectedOptions[0].textContent;

  let tempSelect = document.createElement('select');
  tempSelect.style.visibility = "hidden";
  tempSelect.style.position = "fixed"
  tempSelect.appendChild(tempOption);
  
  sel.after(tempSelect);
  sel.style.width = `${+tempSelect.clientWidth + 4}px`;
  tempSelect.remove();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<select>
  <option value="2">Some longer option</option>
  <option value="1">Short option</option>
  <option value="3">An very long option with a lot of text</option>
</select>

<select>
  <option>Short option 2</option>
  <option>Some longer option 2</option>
  <option selected>An very long option with a lot of text 2</option>
</select>

jQuery插件解决方案

另一种选择是使用插件来处理从头到尾的整个操作。这是我刚刚制作的一个。

插件动态创建和销毁span,因此它不会弄乱您的html。这有助于分离关注点,并允许您将该功能委托给另一个文件,并轻松地在多个页面中重复使用多个元素。

(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);
.btn-select {
  color: #333;
  background-color: #f5f5f5;
  border-color: #ccc;
  padding:7px;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>

<div class="form-group">
  <div class="input-group">

    <span class="input-group-btn">
      <select class="btn btn-select resizeselect">
        <option>All</option>
        <option>Longer</option>
        <option>A very very long string...</option>
      </select>
    </span>

    <input type="text" class="form-control" placeholder="Search by...">

    <span class="input-group-btn">
      <button class="btn btn-default" type="button">
        <i class="fa fa-search"></i>
      </button>
    </span>

  </div>
</div>

【讨论】:

  • 非常感谢@KyleMit :)
  • 第一行需要从(function($, window){改为$(function($, window){,相当于说$( document ).ready() { (function($, window){,否则你的类属性只有在页面上的链接被点击后才会改变(因为文档将在脚本执行后加载)
  • 我建议将行 var $test = $("&lt;span&gt;").html(text); 更改为 var $test = $("&lt;span style=\"font-size:"+$this.css("font-size")+"\"&gt;").html(text); 以确保创建的临时跨度的字体大小与选择元素的字体大小相匹配。如果 span 的字体大小变小或变大,动态调整大小将被大小差异抵消。
  • 我想建议不仅采用@Garywoo 建议的“字体大小”,而且检索window.getComputedStyle(this) 并分配相同的font-weightfont-sizefont-familyline-height 到跨度。
  • 这里有一个更现代的 vanilla JS 方法来解决这个问题:stackoverflow.com/a/67239947/4168960
猜你喜欢
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-04
  • 2023-03-23
  • 2019-05-13
  • 1970-01-01
相关资源
最近更新 更多