appendChild 不会两次附加相同的元素

appendChild doesn't append the same element twice

我有一个 valuesArray 和一个 transcribedPoems 数组。如果它们都存在一个键,我想在 TranscribedAll 子组中向我的 select 元素添加一个 option。如果没有,那么我希望该选项仅在 All 子组中可用。这是我的代码:

let valuesArray = [   
    ["1", "a manuscript"], ["2", "another one"]
]

const transcribedPoems =['2']

let optGroupTranscribed = document.createElement("optgroup");
optGroupTranscribed.setAttribute("label", "Transcribed")

let optGroupAll = document.createElement("optgroup");
optGroupAll.setAttribute("label", "All")

let select = document.createElement("select");

valuesArray.forEach(function(element) {
        
        let option = document.createElement("option");
        option.value = element[0];
        option.text = element[1];
        
        if (transcribedPoems.includes(element[0])) {

            optGroupTranscribed.appendChild(option);
            optGroupAll.appendChild(option);
            
        }  else {
        
            optGroupAll.appendChild(option);
        }
        
    });

select.appendChild(optGroupTranscribed);
select.appendChild(optGroupAll);
    
document.getElementById("manifests").appendChild(select);

虽然上面的代码没有向 optGroupTranscribed 添加任何内容。我注意到,如果我从条件中取出 optGroupAll.appendChild(option);,那么我确实在 transcribed 子组(而不是 All 子组中)有转录的诗歌。不过,我希望转录的诗歌也属于 All 子组。我错过了什么?

我得到的:

<select>
  <optgroup label="Transcribed">
    <option value="2">another one</option>
  </optgroup>
  <optgroup label="All">    
    <option value="1">a manuscript</option>
  </optgroup>
</select>

预期结果:

<select>
  <optgroup label="Transcribed">
    <option value="2">another one</option>
  </optgroup>
  <optgroup label="All">    
    <option value="1">a manuscript</option>
    <option value="2">another one</option>
  </optgroup>
</select>

one 循环的 forEach 迭代中,您只创建 one option 元素,依此类推你不能指望结果有两个。

第二次调用 appendChild 实际上 移动到 option 那里,将其从第一个选项组中取出。

您可以致电 option.cloneNode(true) 来解决这个问题。

这里有一个有趣的微妙之处。当您使用 createElement 时,它会创建一个 HTMLElement 实例(对于子类 option)。当您 appendChild 那个元素到另一个元素时,它被放置在那个元素的 DOM 树中。

如果您将同一个元素放置在另一个元素的 DOM 树中,它会使整个树(包含 optGroupTranscribedoptGroupAll ) 不是一棵树,因为会有一个 child option 由两个元素共享。

相反,您可以调用 option.cloneNode() 来制作元素的副本。因此,尝试将其更改为:

optGroupTranscribed.appendChild(option.cloneNode());

这样做...

文档:
optionElement = new Option(text, value, defaultSelected, selected)

const
  newElm = (tag, props={}) => Object.assign(document.createElement(tag), props)
, transcribedPoems = ['2']
, valuesArray =
    [ ['1', 'a manuscript']
    , ['2', 'another one' ]
    ]
, mySelect = document
      .querySelector('#manifests')
      .appendChild( newElm('select',{name:'select',id:'objectAssign'})) 
  ;
let optGroupTranscribed = mySelect.appendChild(newElm('optgroup',{label:'Transcribed'}))
  , optGroupAll         = mySelect.appendChild(newElm('optgroup',{label:'All'}))
  , doSelect            = true
  ;
valuesArray.forEach(([val,lib]) => 
  {
  if ( transcribedPoems.includes(val))
    {
    optGroupTranscribed.appendChild( new Option(lib,val,doSelect,doSelect) )
    doSelect = false
    }
  optGroupAll.appendChild( new Option(lib,val) )
  })
<div id="manifests"></div>