javascript - Varför har HTMLInputElements `list`-fält bara en getter och ingen setter?


Jag skapar ett HTMLInputElement i Typescript, som jag avser att använda som en "slider" genom att sätta input-elementets type-fält till "range".

Enligt MDN Web Docs kan jag göra den här reglaget mer avancerad genom att skapa en instans av ett HTMLDatalistElement, ge datalistan ett id och referera till datalistans id via reglagets list-fält. Detta kommer inte bara ge mitt reglage några markeringar för att ange var reglagets markör för närvarande är placerad, utan jag kan sedan ställa in datalistans HTMLOptionElements label-fält för att införa märktade markeringar.

Källa: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range#adding_labels

Men Deno/TS-Node klagar med detta fel:

error: TS2540 [ERROR]: Cannot assign to 'list' because it is a read-only property.
      inputElement.list = datalistId;

och Google Chrome klagar med detta felmeddelande:

Uncaught TypeError: Cannot set property list of #<HTMLInputElement> which has only a getter

Eftersom MDN Web Docs tydligt visar att detta fält är avsett att användas, försökte jag tysta Deno/TS-Node-felet genom att ignorera det via:

// @ts-ignore

Denna lösning fungerade inte och resulterade i ovanstående Google Chrome-körtidsfel.

Jag förstår inte varför detta fält tillåts sättas när man skapar ett HTMLInputElement via en .html-fil, men att använda det när man skapar en instans av ett HTMLInputElement dynamiskt via Javascript/Typescript inte är tillåtet. Att kunna dynamiskt ställa in en sliders tick-märkesetiketter vore mycket trevligt.

Svar #1

Enligt HTML-specifikationen är list content attributet faktiskt specificerat att innehålla ID:t för ett motsvarande datalist element:

Attributet list används för att identifiera ett element som listar fördefinierade alternativ som föreslås för användaren.
Om det finns måste dess värde vara ID för ett datalist-element i samma träd.

Men input-elementets list IDL-attribut (som specificerat i DOM-gränssnittet) är skrivskyddat och returnerar den faktiska HTMLDataListElement istället för dess ID:

interface HTMLInputElement : HTMLElement {
  // ...
  readonly attribute HTMLDataListElement? list;
  // ...
}

Du kan däremot manipulera list-content-attributet med setAttribute()-funktionen och sätta datalist-ID på input-elementet på det sättet:

document.querySelector('#input').setAttribute('list', 'values');
<input id="input" type="range">
<datalist id="values">
  <option value="0" label="0"></option>
  <option value="50" label="50"></option>
  <option value="100" label="100"></option>
</datalist>

Svar #2

Det finns en skillnad mellan ett attribut i HTML <tagg attribut="värde">, och ett attribut hos ett Element.

De attribut som hämtas från HTML lagras i NamedNodeMap attributes; och kan kontrolleras med t.ex. setAttribute och getAttribute.

Attributet som ett DOM-element (som ärver från Element) har behöver inte (även om de har samma namn) ha samma värde, deras värde härleds från Attr som lagras i attributes.

Om du tittar på detta exempel kan du se att det finns en skillnad i beteende beroende på vilken du manipulerar och hämtar:

document.getElementById('test1').setAttribute('value','html-value')

document.getElementById('test2').setAttribute('value','html-value')
document.getElementById('test2').value = 'js-value'

document.getElementById('test3').value = 'js-value'
console.log(document.getElementById('test3').getAttribute('value'))
[value="html-value"] {
  color: red;
}

[value="js-value"] {
  color: green;
}
Test1:
<input id="test1">
Test2:
<input id="test2">
Test3:
<input id="test3">

Så för list skapas attributet för DOM-elementet baserat på vad som är inställt för attributet Node med namnet list (vilket är ett ID).

Attributet list för DOM-elementet är förmodligen inställt på skrivskyddat och innehåller en lista över element, eftersom den listan inte kunde mappas tillbaka till ett ID.

Relaterade artiklar