如何将元素的 NamedNodeMap 克隆到空对象?

How do you clone an element's NamedNodeMap to an empty object?

我有一个 javaScript 对象数组,其中对象称为 text,其中每个对象元素包含有关 HTML 元素的信息使用 Chrome 浏览器的检查源监视区域如下所示:

text:
  attributes: NamedNodeMap
                0: baseURI: "file:.../awesomplete_textarea.html"
                   childNodes: NodeList []
                   firstChild: null
                   isConnected: false
                   lastChild: null
                   localName: "label"
                   name: "label"
                   namespaceURI: null
                   nextSibling: null
                   nodeName: "label"
                   nodeType: 2
                   nodeValue: "Alternative Rock"
                   ownerDocument: document
                   ownerElement: li
                   parentElement: null
                   parentNode: null
                   prefix: null
                   previousSibling: null
                   specified: true
                   textContent: "Alternative Rock"
                   value: "Alternative Rock"
                   __proto__: Attr }
              length: 1
              label: { same content as 0, above }
              __proto__: NamedNodeMap }
  label: "Alternative Rock"
  tagName: "LI"
  value: "Alternative Rock (Alternative)"
  length: 16
  __proto__: String

注意:虽然 attributes 成员 text 对象(以上)仅包含label 属性的信息,它还可以包含其他属性项,例如样式 and/or class,它们是从一组 <li> 标记在我的网页中,在这种情况下,text 对象和 attributes[=59 中会有其他条目=] 那些属性项的成员。

收集信息 <li> 标签后,使用如下所示的 copyAttributes 函数将标签的属性复制到 text 对象中,效果很好。

不过,以后尝试使用相同的copyAttributes函数复制text.attributes[=59时=] 到 attr 变量然后创建一个新的 HTML 元素,我得到这个错误:

mycode.js:98 Uncaught TypeError: to.setNamedItem is not a function
  at copyAttributes (mycode.js:98)
  at Function._.ITEM (mycode.js:940)
  at _.item (mycode_textarea.html:625)
  at mycode.js:826
  at Array.forEach (<anonymous>)
  at _.evaluate (mycode.js:825)

下面的代码显示了这个调用是如何进行的,以及我试图将信息复制到 attr 对象变量中。

function copyAttributes( from, to ) {
  var attr;

  for( const [ key, value ] of Object.entries( from ) ) {

    if( !isNaN( key ) ) {  // Only add the named attributes ...

      let name = from[ key ].name;;  // get the attribute's name

      if( to[ name ] === undefined ) {

        attr       = document.createAttribute( name ); // Create the attribute.
        attr.value = value.value;                      // Assign its value.

        to.setNamedItem( attr );                       // Add it to to

      }

    }

  }

}

var tagName = 'li';
var attribute = {};

// Copy the text.attributes from the text object to attributes.

copyAttributes( text.attributes, attributes );

// Add the information in the {...} object to the attributes object ...

Object.assign( attributes,
               attributes,
               { innerHTML: label,             // Add these to those just copied.
                 'role':    'option',
                 'id':      'list_' + this.count +
                            '_item_' + item_id,
                 'value':   value } );

// Create the new `<li>` with the original tag's attributes and those added, above.

$.create( tagName, attributes );

问题好像是copyAttributes函数的to参数不是NamedNodeMap类型,所以不支持setNamedItem 方法。

如何创建一个空的 attributes 这种类型的变量?

或者是否有 better/easier 方法用 test[= 填充 attributes 变量57=].属性信息?

谢谢。

这是一个 codepen 下拉组合框的工作版本,它正确地创建了 li 标签元素并将所需的属性复制到其中。

此创建函数来自 Awesomplete 插件,但已修改为不将焦点设置在新创建的元素上。

$.create = function( tag, o ) {
  var element = document.createElement( tag );

  for( var i in o ) {
    var val = o[ i ];

    if( i === 'inside' ) {
      $( val ).appendChild( element );
    }
    else if( i === 'around' ) {

      var ref = $( val );

      ref.parentNode.insertBefore( element, ref );
      element.appendChild( ref );

      if( ref.getAttribute( 'autofocus' ) != null ) {
        ref.focus();
      }
    }
    else if( i in element ) {
      element[ i ] = val;
    }
    else {
      element.setAttribute( i, val );
    }
  }

  return element;
};

这是我修改后的代码,调用上面的创建函数并分配属性。

if( tagName === 'LI' ) {

  matched = ( inputValue = ( ', ' +
                             me.input.value.trim().toLowerCase() +
                             ',' ) )    // Normalize input.value so that the first item can be found.
                           .includes( ', ' + value.toLowerCase() + ',' ) ||         // Find the normalized value in the normalized input.value ...
                           inputValue.includes( ', ' +
                                                label.toLowerCase() + ',' );        // Find the normalized label in the normalized input.value ...

  Object.assign( attributes,
         attributes,
         { 'role':          'option',
           'id':            'awesomplete_list_' +
                            this.count +
                            '_item_' + item_id,
           'value':         value,                          // Give every option ( li ) a value attribute.
           'aria-selected': matched.toString() } );                 // If a match was found then set aria-selected to 'true'
                                                // else set area-selected to 'false'.

}
else {

  matched = false;

}

newTag = $.create( tagName );

    newTag.innerHTML = label;

if( text.attributes.length ) {

  // Now copy the attributes ...

  copyAttributes( text.attributes, newTag.attributes );

  // Add the rest of the attributes ...

  copyAttributes( attributes, newTag.attributes, true );

}

return newTag;