Impostazione di più attributi per un elemento contemporaneamente con JavaScript


90

Come posso impostare più attributi contemporaneamente con JavaScript? Sfortunatamente, non sono in grado di utilizzare un framework come jQuery su questo progetto. Ecco cosa ho adesso:

var elem = document.createElement("img");

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");

1
La risposta di @Quantastical using Object.assign()vale la pena dare un'occhiata a coloro che non vogliono creare una funzione di supporto - funziona per "tutte le proprietà enumerabili e proprie ".
benvc

4
Ho fatto scorrere tutte le risposte, sperando che in 7 anni da quando è stata pubblicata questa domanda ci sarebbe stato una sorta di aggiornamento ES7, in modo da non dover scrivere la nostra funzione come la risposta di @ Ariel
krummens

Risposte:


121

Potresti creare una funzione di supporto:

function setAttributes(el, attrs) {
  for(var key in attrs) {
    el.setAttribute(key, attrs[key]);
  }
}

Chiamalo così:

setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});

1
beh, non è anche subito, quindi non ci sarà alcun effetto sulle prestazioni.
vsync

Non è quello che ha chiesto. Dobbiamo sapere come migliorare la prestazione
jbartolome

19
@jbartolome - La parola "performance" non è menzionata una volta nella domanda. Non so da dove hai preso questa idea. La domanda sembra cercare un modo per non dover chiamare manualmente elem.setAttribute()più volte.
jfriend00

Non sono sicuro di cosa voglia veramente la domanda. Un buon risultato possibile desiderato è chiamare l'attributoChangedCallback "solo una volta". Se ho bisogno di chiamare una funzione che dipende da due attributi, di solito viene chiamato attributeChangedCallback due volte, una per ogni cambio di attributo. Accedere a this.getAttribute ('your-attr') per entrambi gli attributi ed uscire se uno di essi è ancora vuoto è una prima soluzione MA non gestisce il caso in cui è impostato un solo attributo e l'altro ha già un valore precedente . Ma Dio aiuta questa non è la domanda effettivamente oggettiva. Non facile!
Vladimir Brasil

23

Potresti essere in grado di utilizzare Object.assign(...)per applicare le tue proprietà all'elemento creato. Vedere i commenti per ulteriori dettagli.

Tieni presente che heighte gli widthattributi sono definiti in pixel , non in percentuale. Dovrai usare CSS per renderlo fluido.

var elem = document.createElement('img')
Object.assign(elem, {
  className: 'my-image-class',
  src: 'https://dummyimage.com/320x240/ccc/fff.jpg',
  height: 120, // pixels
  width: 160, // pixels
  onclick: function () {
    alert('Clicked!')
  }
})
document.body.appendChild(elem)

// One-liner:
// document.body.appendChild(Object.assign(document.createElement(...), {...}))
.my-image-class {
  height: 100%;
  width: 100%;
  border: solid 5px transparent;
  box-sizing: border-box
}

.my-image-class:hover {
  cursor: pointer;
  border-color: red
}

body { margin:0 }


1
Le proprietà, elem.height e così via, sono di sola lettura, quindi non riesce. Ho esaminato i descrittori e sono accessori con solo un getter (setter non definito).
lukeuser

@lukeuser Grazie per il commento. Non sapevo che quelle proprietà fossero di sola lettura.
utente

2
Alla tua domanda su "non potresti semplicemente ..." l'ho chiesto probabilmente quando in realtà non potresti semplicemente.
JP Silvashy

2
@ JPSilvashy Non intendevo che il mio "non potresti semplicemente" sembrare sminuito o mostrare un segno di superiorità. Scusa se lo ha fatto. Onestamente non ero sicuro che questa sarebbe stata una risposta adeguata perché non sono un ninja JavaScript, quindi speravo che altri come lukeuser potessero intervenire per aiutare a solidificare la logica.
utente

13

Se si desidera una sintassi basata su framework ( Nota: solo supporto IE 8+), è possibile estendere il Elementprototipo e aggiungere la propria setAttributesfunzione:

Element.prototype.setAttributes = function (attrs) {
    for (var idx in attrs) {
        if ((idx === 'styles' || idx === 'style') && typeof attrs[idx] === 'object') {
            for (var prop in attrs[idx]){this.style[prop] = attrs[idx][prop];}
        } else if (idx === 'html') {
            this.innerHTML = attrs[idx];
        } else {
            this.setAttribute(idx, attrs[idx]);
        }
    }
};

Ciò ti consente di utilizzare la sintassi come questa:

var d = document.createElement('div');
d.setAttributes({
    'id':'my_div',
    'class':'my_class',
    'styles':{
        'backgroundColor':'blue',
        'color':'red'
    },
    'html':'lol'
});

Provalo: http://jsfiddle.net/ywrXX/1/

Se non ti piace estendere un oggetto host ( alcuni sono opposti ) o hai bisogno di supportare IE7-, usalo come funzione

Nota che setAttributenon funzionerà per styleIE o per i gestori di eventi (non dovresti comunque). Il codice sopra gestisce style, ma non gli eventi.

Documentazione


Per la cronaca: IE7 ->'Element' is undefined
KooiInc

Sì, abbastanza giusto. Hai dimenticato IE7 e i loro oggetti COM. Puoi sovraccaricare document.createElemente document.getElementByIdshim questo ... o semplicemente racchiudere la funzionalità in una funzione. Risposta modificata per includere quella nota
Chris Baker,

2
versione ricorsiva più semplificata: jsfiddle include uno shim di IE
Keleko

Mi piace molto la versione semplificata di Keleko! L'unica cosa è che, nella tua versione, non c'è un innerText nel tuo JSFiddle. Ho provato ad aggiungere else if (su [prop] === html) {this.innerHTML = set [prop]; } e non ha funzionato. Ottengo un errore. Come posso aggiungere un'impostazione di innerText?
Jessica

Questa risposta ti consente di utilizzare un singolo oggetto che contiene attributi dell'elemento, proprietà CSS (potenzialmente in un oggetto nidificato) e innerHTML. Mostra anche come usare questo modificare il prototipo dell'elemento (hmmm) o usarlo come una normale funzione (ahhh). Bel lavoro!
Andrew Willems,

12

Puoi creare una funzione che accetta un numero variabile di argomenti:

function setAttributes(elem /* attribute, value pairs go here */) {
    for (var i = 1; i < arguments.length; i+=2) {
        elem.setAttribute(arguments[i], arguments[i+1]);
    }
}

setAttributes(elem, 
    "src", "http://example.com/something.jpeg",
    "height", "100%",
    "width", "100%");

Oppure, trasferisci le coppie attributo / valore su un oggetto:

 function setAttributes(elem, obj) {
     for (var prop in obj) {
         if (obj.hasOwnProperty(prop)) {
             elem[prop] = obj[prop];
         }
     }
 }

setAttributes(elem, {
    src: "http://example.com/something.jpeg",
    height: "100%",
    width: "100%"
});

Puoi anche creare il tuo wrapper / metodo di oggetti concatenabili:

function $$(elem) {
    return(new $$.init(elem));
}

$$.init = function(elem) {
    if (typeof elem === "string") {
        elem = document.getElementById(elem);
    }
    this.elem = elem;
}

$$.init.prototype = {
    set: function(prop, value) {
        this.elem[prop] = value;
        return(this);
    }
};

$$(elem).set("src", "http://example.com/something.jpeg").set("height", "100%").set("width", "100%");

Esempio funzionante: http://jsfiddle.net/jfriend00/qncEz/


12

Puoi codificare una funzione di supporto ES5.1:

function setAttributes(el, attrs) {
    Object.keys(attrs).forEach(key => el.setAttribute(key, attrs[key]));
}

Chiamalo così:

setAttributes(elem, { src: 'http://example.com/something.jpeg', height: '100%' });

5
const setAttributes = (el, attrs) =>
  Object.entries(attrs)
    .forEach(args =>
      el.setAttribute(...args))

4

Oppure crea una funzione che crei un elemento che includa attributi dai parametri

function elemCreate(elType){
  var element = document.createElement(elType);
  if (arguments.length>1){
    var props = [].slice.call(arguments,1), key = props.shift();
    while (key){ 
      element.setAttribute(key,props.shift());
      key = props.shift();
    }
  }
  return element;
}
// usage
var img = elemCreate('img',
            'width','100',
            'height','100',
            'src','http://example.com/something.jpeg');

FYI: height/width='100%'non funzionerebbe utilizzando gli attributi. Per un'altezza / larghezza del 100% sono necessari gli elementistyle.height/style.width


@vsync Mentre apprezzo il tuo voto negativo e insulto casuale, c'è poca differenza fondamentale tra questa e qualsiasi altra risposta qui. Calmati.
Chris Baker

@ Chris - è stato casuale sì, perché invece volevo promuovere questa risposta, quindi ho dovuto votare la risposta sopra di essa. e sì, se hai 1000 elementi e devi modificare 5 attributi per ciascuno, sarebbe meglio ricrearli con i nuovi attributi piuttosto che accedere al DOM 5000 volte, non sei d'accordo?
vsync

@vsync se stai utilizzando una funzione copia / incolla casuale che hai trovato su StackOverflow senza considerare le prestazioni speciali in questione ereditate dal tuo caso d'uso, allora probabilmente hai un problema più grande. Inoltre, nella risposta che hai downvotato, il DOM non sarebbe stato acceduto 5000 volte, non più di questa risposta - in entrambi i casi, l'elemento in questione non è stato inserito nell'albero DOM. Questa e la mia risposta fanno la stessa cosa, semplicemente iteriamo le proprietà in modo diverso.
Chris Baker

@ Chris - Questa domanda non mi riguarda. perché parli di me e di cosa faccio o no? è irrilevante. La tua risposta non è molto buona se è necessario modificare gli attributi di molti nodi sul DOM stesso, mentre questa risposta è leggermente migliore perché promuove un buon modo di pensare, dove si ricrea il nodo con tutti i suoi attributi e si ricrea installalo nel DOM. Anche questo non è l'ideale, perché clonesarebbe preferibile utilizzare il metodo. Non è necessario creare l'intero nodo da zero. Ad ogni modo, è priorità assoluta ridurre al minimo l'accesso al DOM, il caso d'uso più comune.
vsync

@vsync La parola "tu" è usata in senso astratto, non significa te come individuo (che sono abbastanza sicuro che tu, vsynch, conosci) ma per l'ipotetico consumatore futuro di queste risposte. Ancora una volta, le due risposte hanno funzione identica. Sei libero di votare come vuoi, anche se il tuo ragionamento è difettoso (controlla i benchmark), ma tieni per te le tue osservazioni condiscendenti.
Chris Baker

3

Prova questo

function setAttribs(elm, ob) {
    //var r = [];
    //var i = 0;
    for (var z in ob) {
        if (ob.hasOwnProperty(z)) {
            try {
                elm[z] = ob[z];
            }
            catch (er) {
                elm.setAttribute(z, ob[z]);
            }
        }
    }
    return elm;
}

DEMO: QUI


2

puoi semplicemente aggiungere un metodo (setAttributes, con "s" alla fine) al prototipo "Element" come:

Element.prototype.setAttributes = function(obj){
  for(var prop in obj) {
    this.setAttribute(prop, obj[prop])
  }
}

puoi definirlo in una riga:

Element.prototype.setAttributes = function(obj){ for(var prop in obj) this.setAttribute(prop, obj[prop]) }

e puoi chiamarlo normalmente come chiami gli altri metodi. Gli attributi sono dati come oggetto:

elem.setAttributes({"src": "http://example.com/something.jpeg", "height": "100%", "width": "100%"})

puoi aggiungere un'istruzione if per generare un errore se l'argomento dato non è un oggetto.


Adesso ha senso. Mi chiedevo come fare questo tipo di modifica a una funzione predefinita. Grazie!
testing_22

1

utilizzare questa funzione per creare e impostare attributi allo stesso tempo

function createNode(node, attributes){
    const el = document.createElement(node);
    for(let key in attributes){
        el.setAttribute(key, attributes[key]);
    }
    return el;
}

usalo così

const input = createNode('input', {
    name: 'test',
    type: 'text',
    placeholder: 'Test'
});
document.body.appendChild(input);

1

Immagino che sia il modo migliore per impostare gli attributi contemporaneamente per qualsiasi elemento in questa classe.

function SetAtt(elements, attributes) {
    for (var element = 0; element < elements.length; element++) {
        for (var attribute = 0; attribute < attributes.length; attribute += 2) {
            elements[element].setAttribute(attributes[attribute], attributes[attribute + 1]);
        }
    }
}
var Class = document.getElementsByClassName("ClassName"); // class array list
var Data = ['att1', 'val1', 'att2', 'val2', 'att3', 'val3']; //attributes array list
SetAtt(Class, Data);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.