جاوااسکریپت - تنظیم عرض المان select برابر با عرض محتوای گزینههای آن بهصورت پویا


من تلاش میکنم عرض عنصر select را برابر با عرض متن گزینههای آن در انگولار کنم.

کامپوننت HTML من به سادگی به این شکل است:

<form [formGroup]="profileForm">
  ...
  <select (change)="adjustSelectWidth($event.target)" formControlName="members">
    <option value="1">Me</option>
    <option value="2">Me, my spouse</option>
    <option value="3">Me, my spouse and my kids</option>
  </select>
  ...
</form>

آنچه که من امتحان کردهام:

  • عرض عنصر option را با استفاده از clientWidth به دست آورید و سپس آن را به عنصر select اعمال کنید، اما آن عرض برابر با ۰ است.
export class AppComponent  {
  profileForm = new FormGroup({
    members : new FormControl(''),
  })

  adjustSelectWidth(e){
    const optionValue = this.profileForm.get('members').value;
    const optionWidth = document.querySelector(`option[value="${optionValue}"]`).clientWidth;
    e.style.width= optionWidth + "px"
  }
}
  • طول innerHTML گزینه را دریافت کنید سپس آن را در یک پیکسل ثابت ضرب کنید اما این یک گزینه پویا نیست
export class AppComponent  {
  profileForm = new FormGroup({
    members : new FormControl(''),
  })

  adjustSelectWidth(e){
    const optionValue = this.profileForm.get('members').value;
    const optionTextLength = document.querySelector(`option[value="${optionValue}"]`).innerHTML.length;
    e.style.width= optionTextLength*8 + "px";
  }
}
  • متن innerHTML گزینهها را به یک عنصر span برای اندازهگیری عرض الحاق کنید، اما سپس clientWidth آن span هنگام اعمال آن به عنصر select دقیق نیست.
export class AppComponent  {
  //This temp is bind to a span via string interpolation {{...}}
  temp:string;

  profileForm = new FormGroup({
    members : new FormControl(''),
  })

  adjustSelectWidth(e){
    const optionValue = this.profileForm.get('members').value;
    const optionText = document.querySelector(`option[value="${optionValue}"]`).innerHTML;
    this.temp = optionText;
    const spanWidth = document.querySelector(`.temp`).clientWidth;
    e.style.width = spanWidth + "px";
  }
}

از آنجایی که من از انگولار استفاده میکنم، ترجیح میدهم از JQuery استفاده نکنم. علاوه بر این، چرا به نظر میرسد clientWidth مشکل من را در اینجا حل نمیکند؟

من یک مثال در Stackblitz ایجاد کردم: https://stackblitz.com/edit/angular-bbimkz

پاسخ شماره ۱

راهی برای اندازهگیری عرض متن وجود دارد. فکر میکنم این روش به اندازه کافی قابل اعتماد است، اما ممکن است از نظر عملکرد کمی پرهزینه باشد، بسته به برنامه شما البته. (مثال ساده در استکبلیتز هیچ مشکل عملکردی ندارد.)

روش این است که در واقع یک عنصر مخفی به سند اضافه کنید که شامل متنی است که میخواهید اندازهگیری کنید، clientWidth را بخوانید، و بلافاصله عنصر را حذف کنید.

تابع adjustSelectWidth() را به صورت زیر تغییر دهید:

adjustSelectWidth(e: HTMLSelectElement){
  // assuming something is always selected, please test!
  const displayedText = e.options[e.selectedIndex].innerText;
  const dummy = document.createElement('div');
  dummy.innerText = displayedText;
  dummy.style.position = 'absolute';
  dummy.style.visibility = 'hidden';
  document.body.insertBefore(dummy, document.body.firstChild);
  const measuredWidth = dummy.clientWidth;
  document.body.removeChild(dummy);
  e.style.width = (measuredWidth + 30) + 'px'
}

استکبلیتز اصلاحشده: https://stackblitz.com/edit/angular-mpjxbd?file=src/app/app.component.ts - در آخرین نسخههای فایرفاکس، کروم، اج تست شده است

پاسخ شماره ۲

اچتیامال

<select onchange="resizeSelect">
   <option value="foo">Foo</option>
   <option value="bar">Bar</option>
</select>
<span id="dummy"></span>

JavaScript

const resizeSelect = ({ target: select }) => {
   const dummyEl = document.getElementById('dummy')
   const selectStyle = window.getComputedStyle(select)

   // The element's font style impacts the text width
   dummyEl.style.font = selectStyle.font
   dummyEl.innerText = select.options[select.selectedIndex].innerText

   select.style.width = `${dummyEl.clientWidth}px`
}

CSS

#dummy {
   position: absolute;
   visibility: hidden;
}