#javascript #html #object #clone
#javascript #HTML #объект #клонировать
Вопрос:
У меня есть массив объектов JavaScript, где объекты называются text, где каждый элемент объекта содержит информацию об элементе HTML, который выглядит следующим образом, используя область просмотра inspect Source браузера 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
Примечание: Хотя элемент атрибутов текстового объекта (выше) содержит только информацию для атрибута label, он также может содержать другие элементы атрибутов, такие как стиль и / или класс, которые были скопированы из набора <li>
тегов на моей веб-странице, и в этом случае будут дополнительные записи в элементе текстовый объект и атрибуты для элементов этих атрибутов.
Когда информационные <li>
теги собраны, атрибуты тега копируются в текстовый объект с помощью функции copyAttributes, показанной ниже, которая работает нормально.
Однако, когда позже я попытаюсь использовать ту же функцию copyAttributes для копирования text.attributes в переменную 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 );
Проблема, по-видимому, заключается в том, что to
параметр функции copyAttributes не является типом NamedNodeMap, поэтому он не поддерживает setNamedItem
метод.
Как я могу создать пустую переменную атрибутов этого типа?
Или есть лучший / более простой способ заполнить переменную attributes информацией test.attributes?
Спасибо.
Комментарии:
1. Это звучит как проблема XY . Какова ваша цель? Забудьте о копировании атрибутов и расскажите нам, чего вы пытаетесь достичь.
2. Моя веб-страница использует теги <li>, чтобы указать возможные варианты выбора для пользователя в скрытом списке тегов <ul>, а атрибуты этих тегов <li> копируются в массив объектов. Затем, когда пользователь вводит значения, разделенные запятыми, в текстовое поле, чтобы найти подмножество исходных <li>, отдельные значения, разделенные запятыми, сравниваются со значениями в объектах массива, и совпадения используются для создания новых тегов <li> в другом списке <ul>. Разница между этими двумя списками заключается в том, что второй добавляет дополнительную информацию и атрибуты форматирования к тому, что было найдено в исходных тегах <li>.
3. Я затронул тему копирования атрибутов, потому что я использую библиотеку awesomplete, которая создает выпадающий список с возможностью поиска, из которого пользователь может выбирать значения, вводя значения, разделенные запятыми, в элемент textarea или щелкая по соответствующим значениям в выпадающем списке. Он создает массив из списка тегов <li>, выполняет поиск в них и создает новый список тегов <li>. Однако я хочу изменить эти теги <li>, объединив дополнительную информацию и атрибуты форматирования с тем, что было найдено в исходных тегах <li> .
4. Я вряд ли смогу убедить вас, но ваш подход ошибочен по разным причинам. Например,
var attribute = {}
вы никогда не создадите NamedNodeMap с помощью метода с именемsetNameId
, в вашем вызовеObject.assign()
вы устанавливаете add avalue
, в то время как вы уже клонировали его для объекта attributes, который вы только что создали. Было бы намного проще создаватьli
теги в заводской функции. Почему?namedNodeMap
Для начала два из нихLI
практически идентичны.5. True для ‘var attribute = {}’ . Именно поэтому я спросил о создании такого объекта. Что касается value, это атрибут, который awesomplete ищет для поиска совпадений, но клонированное значение может быть не тем, которое я хочу, поэтому я устанавливаю для него нужное мне значение. Что касается NamedNodeMap двух <li>, которые почти идентичны, это возможно, но не обязательно в каждом <li> . Некоторые добавили информацию и форматирование, которых не будет у других, также у каждого <li> есть уникальное значение и значение метки, из которых пользователь может выбирать. Кстати, как вы выделяете серым свои примеры кода в своих комментариях? фабричная функция?
Ответ №1:
Вот 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;
};
Это мой модифицированный код, который вызывает указанную выше функцию create и присваивает атрибуты.
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;