Establecer múltiples atributos para un elemento a la vez con JavaScript

88

¿Cómo puedo configurar varios atributos a la vez con JavaScript? Desafortunadamente, no puedo usar un marco como jQuery en este proyecto. Esto es lo que tengo ahora:

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

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");
JP Silvashy
fuente
1
Vale la Object.assign()pena mirar la respuesta de @Quantastical para aquellos que no quieren crear una función auxiliar; funciona para "todas las propiedades enumerables y propias ".
Benvc
4
Revisé todas las respuestas, con la esperanza de que en 7 años desde que se publicó esta pregunta, habría algún tipo de actualización de ES7, para que no tengamos que escribir nuestra propia función como la respuesta de @ Ariel
krummens

Respuestas:

119

Podrías hacer una función de ayuda:

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

Llámalo así:

setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});
Ariel
fuente
1
bueno, tampoco lo es a la vez, por lo que no afectará el rendimiento.
vsync
Esto no es lo que pidió. Necesitamos saber cómo mejorar el rendimiento
jbartolome
19
@jbartolome: la palabra "rendimiento" no se menciona ni una vez en la pregunta. No sé de dónde sacaste esa idea. La pregunta parece buscar una forma de no tener que llamar manualmente elem.setAttribute()varias veces.
jfriend00
No estoy seguro de lo que realmente quiere la pregunta. Un buen resultado deseado posible es llamar a attributeChangedCallback "solo una vez". Si necesito llamar a una función que depende de dos atributos, normalmente se llama a attributeChangedCallback dos veces, una por cada cambio de atributo. Acceder a this.getAttribute ('your-attr') para ambos atributos y salir si uno de ellos todavía está vacío es una primera solución, PERO no maneja el caso en el que solo se establece un atributo y el otro ya tiene un valor anterior . Pero dios ayuda, esta no es la pregunta realmente objetiva. ¡No es fácil!
Vladimir Brasil
21

Es posible que pueda utilizar Object.assign(...)para aplicar sus propiedades al elemento creado. Consulte los comentarios para obtener detalles adicionales.

Tenga en cuenta que los atributos heighty widthse definen en píxeles , no en porcentajes. Tendrás que usar CSS para hacerlo 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 }

usuario
fuente
1
Las propiedades, elem.height, etc., son de solo lectura, por lo que esto falla. Miré los descriptores y son accesos con solo un captador (setter indefinido).
Lukeuser
@lukeuser Gracias por el comentario. No sabía que esas propiedades eran de solo lectura.
usuario
2
A tu pregunta sobre "no podrías simplemente ...", le pregunté esto probablemente cuando en realidad no podrías simplemente.
JP Silvashy
2
@JPSilvashy No tenía la intención de que mi "no podrías simplemente" parecer menospreciador o mostrar un signo de superioridad. Lo siento si lo hizo. Honestamente, no estaba seguro de si esta hubiera sido una respuesta adecuada ya que no soy un ninja de JavaScript, así que esperaba que otros como lukeuser pudieran intervenir para ayudar a solidificar la lógica.
usuario
13

Si desea una sintaxis framework-esq ( Nota: solo soporte IE 8+), puede extender el Elementprototipo y agregar su propia setAttributesfunción:

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]);
        }
    }
};

Esto le permite usar una sintaxis como esta:

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

Pruébelo: http://jsfiddle.net/ywrXX/1/

Si no le gusta extender un objeto host ( algunos se oponen ) o necesita ser compatible con IE7, simplemente utilícelo como una función

Tenga en cuenta que setAttributeno funcionará styleen IE ni en los controladores de eventos (de todos modos, no debería hacerlo). El código anterior maneja style, pero no eventos.

Documentación

Chris Baker
fuente
Para el registro: IE7 ->'Element' is undefined
KooiInc
Sí, bastante justo. Olvidé IE7 y sus objetos COM. Puede sobrecargar document.createElementy document.getElementByIdajustar esto ... o simplemente envolver la funcionalidad en una función. Respuesta editada para incluir esa nota
Chris Baker
2
versión recursiva más simplificada: jsfiddle incluye una corrección de IE
Keleko
¡Me gusta mucho la versión simplificada de Keleko! Lo único es que, en su versión, no hay un innerText en su JSFiddle. Intenté agregar más if (en [prop] === html) {this.innerHTML = set [prop]; } y no funcionó. Me sale un error. ¿Cómo puedo agregar una configuración de innerText?
Jessica
Esta respuesta le permite usar un solo objeto que contiene atributos de elemento, propiedades css (potencialmente en un objeto anidado) e innerHTML. También muestra cómo usar esto para modificar el prototipo del elemento (hmmm) o usarlo como una función normal (ahhh). ¡Buen trabajo!
Andrew Willems
12

Puede crear una función que tome un número variable de argumentos:

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%");

O pasa los pares de atributo / valor en un objeto:

 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%"
});

También puede crear su propio método / contenedor de objetos encadenables:

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%");

Ejemplo de trabajo: http://jsfiddle.net/jfriend00/qncEz/

jfriend00
fuente
11

Puede codificar una función auxiliar de ES5.1:

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

Llámalo así:

setAttributes(elem, { src: 'http://example.com/something.jpeg', height: '100%' });
danactive
fuente
5
const setAttributes = (el, attrs) =>
  Object.entries(attrs)
    .forEach(args =>
      el.setAttribute(...args))
Geek Devigner
fuente
4

O cree una función que cree un elemento que incluya atributos de parámetros

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%'no funcionaría usando atributos. Para una altura / ancho del 100% necesitas los elementosstyle.height/style.width

KooiInc
fuente
@vsync Si bien aprecio su voto negativo e insulto al azar, hay poca diferencia fundamental entre esta y cualquier otra respuesta aquí. Cálmese.
Chris Baker
@Chris: fue aleatorio, sí, porque quería promover esta respuesta en su lugar, así que tuve que rechazar la respuesta anterior. y sí, si tiene 1000 elementos y debe cambiar 5 atributos para cada uno, sería mejor volver a crearlos con los nuevos atributos que acceder al DOM 5000 veces, ¿no está de acuerdo?
vsync
@vsync si está utilizando una función de copiar / pegar aleatoria que encontró en StackOverflow sin considerar el rendimiento especial en cuestión heredado de su caso de uso, entonces probablemente tenga un problema mayor. Además, en la respuesta que votó negativamente, no se accedería al DOM 5000 veces, no más que esta respuesta; en ambos casos, el elemento en cuestión no se ha insertado en el árbol DOM. Esta respuesta y la mía hacen lo mismo, simplemente iteramos las propiedades de manera diferente.
Chris Baker
@Chris - Esta pregunta no me concierne. por que hablas de mi y que hago o no? es irrelevante. Su respuesta no es muy buena si uno necesita cambiar los atributos de muchos nodos en el DOM mismo, mientras que esta respuesta es un poco mejor porque promueve una buena forma de pensar, donde recrea el nodo con todos sus atributos y vuelve a instalarlo en el DOM. Este tampoco es el ideal, porque clonesería preferible utilizar el método. No es necesario crear todo el nodo desde cero. De todos modos, es de máxima prioridad minimizar el acceso al DOM, el caso de uso más común.
vsync
@vsync La palabra "usted" se usa en un sentido abstracto, no se refiere a usted como individuo (que estoy bastante seguro de que usted, vsynch, conoce) sino al hipotético consumidor futuro de estas respuestas. Una vez más, las dos respuestas son idénticas en función. Eres libre de votar como quieras, incluso si tu razonamiento es defectuoso (verifica los puntos de referencia), pero mantén tus comentarios condescendientes para ti.
Chris Baker
3

Prueba esto

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: AQUÍ

Slawe
fuente
1

use esta función para crear y establecer atributos al mismo tiempo

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

úsalo así

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

fuente
1

Supongo que es la mejor manera de establecer atributos a la vez para cualquier elemento de esta clase.

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);
Dr. JavaB
fuente
1

simplemente puede agregar un método (setAttributes, con "s" al final) al prototipo de "Elemento" como:

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

puedes definirlo en una línea:

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

y puede llamarlo normalmente como llama a los otros métodos. Los atributos se dan como un objeto:

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

puede agregar una instrucción if para generar un error si el argumento dado no es un objeto.

Soufyane Hedidi
fuente