Definir vários atributos para um elemento de uma vez com JavaScript

88

Como posso definir vários atributos de uma vez com JavaScript? Infelizmente, não consigo usar uma estrutura como a jQuery neste projeto. Aqui está o que tenho agora:

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

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");
JP Silvashy
fonte
1
A resposta de @Quantastical using Object.assign()vale uma olhada para aqueles que não querem criar uma função helper - funciona para "todas as propriedades enumeráveis e próprias ".
benvc de
4
Eu rolei por todas as respostas, esperando que em 7 anos desde que esta questão foi postada, haveria algum tipo de atualização ES7, fazendo com que não tenhamos que escrever nossa própria função como a resposta de
@Ariel

Respostas:

119

Você pode fazer uma função auxiliar:

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

Chame assim:

setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});
Ariel
fonte
1
bem, não é de uma vez também, então não haverá nenhum efeito sobre o desempenho.
vsync
Não foi isso que ele perguntou. Precisamos saber como melhorar o desempenho
jbartolome
19
@jbartolome - A palavra "performance" não é mencionada nenhuma vez na pergunta. Não sei de onde você tirou essa noção. A questão parece estar procurando uma maneira de não ter que ligar manualmente elem.setAttribute()várias vezes.
jfriend00
Não tenho certeza do que a pergunta realmente deseja. Um bom resultado desejado possível é chamar attributeChangedCallback "apenas uma vez". Se eu precisar chamar uma função que depende de dois atributos, geralmente attributeChangedCallback é chamado duas vezes, uma para cada alteração de atributo. Acessar this.getAttribute ('your-attr') para ambos os atributos e sair se um deles ainda estiver vazio é uma primeira solução, MAS não trata o caso em que apenas um atributo é definido e o outro já tem um valor anterior . Mas Deus ajuda, essa não é a questão realmente objetiva. Díficil!
Vladimir Brasil
21

Você pode usar Object.assign(...)para aplicar suas propriedades ao elemento criado. Veja comentários para detalhes adicionais.

Lembre-se de que os atributos heighte widthsão definidos em pixels , não em porcentagens. Você terá que usar CSS para torná-lo 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 }

do utilizador
fonte
1
As propriedades, elem.height etc., são somente leitura, portanto, isso falha. Eu olhei para os descritores e eles são acessadores com apenas um getter (setter indefinido).
lukeuser
@lukeuser Obrigado pelo comentário. Eu não sabia que essas propriedades eram somente leitura.
usuário
2
À sua pergunta sobre "você não poderia simplesmente ..." Eu perguntei isso provavelmente quando você na verdade não poderia simplesmente.
JP Silvashy
2
@JPSilvashy Não pretendia que meu "não poderia simplesmente" soar como depreciativo ou mostrar um sinal de superioridade. Desculpe se isso aconteceu. Sinceramente, não tinha certeza se essa seria uma resposta adequada, pois não sou nenhum ninja do JavaScript, então esperava que outros como lukeuser pudessem intervir para ajudar a solidificar a lógica.
usuário
13

Se você quisesse uma sintaxe framework-esq ( Observação: suporte para IE 8+ apenas), você poderia estender o Elementprotótipo e adicionar sua própria setAttributesfunção:

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

Isso permite que você use uma sintaxe como esta:

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

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

Se você não gosta de estender um objeto host ( alguns se opõem ) ou precisa oferecer suporte ao IE7-, basta usá-lo como uma função

Observe que setAttributeisso não funcionará styleno IE ou em manipuladores de eventos (de qualquer maneira, você não deveria). O código acima tratastyle , mas não eventos.

Documentação

Chris Baker
fonte
Para registro: IE7 ->'Element' is undefined
KooiInc
Sim, é justo. Esqueci o IE7 e seus objetos COM. Você pode sobrecarregar document.createElemente document.getElementByIdcorrigir isso .... ou apenas envolver a funcionalidade em uma função. Resposta editada para incluir essa nota
Chris Baker
2
versão recursiva mais simplificada: jsfiddle inclui um shim de IE
Keleko
Gosto muito da versão simplificada do Keleko! A única coisa é que, em sua versão, não há um innerText em seu JSFiddle. Tentei adicionar else if (em [prop] === html) {this.innerHTML = set [prop]; } e não funcionou. Recebo um erro. Como posso adicionar uma configuração innerText?
Jessica
Essa resposta permite que você use um único objeto que contém atributos de elemento, propriedades css (potencialmente em um objeto aninhado) e innerHTML. Ele também mostra como usar isso para modificar o protótipo do elemento (hmmm) ou usá-lo como uma função normal (ahhh). Bom trabalho!
Andrew Willems
12

Você pode criar uma função que leva um número variável 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%");

Ou você passa os pares atributo / valor em um 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%"
});

Você também pode fazer seu próprio wrapper / método de objeto encadeado:

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

Exemplo de trabalho: http://jsfiddle.net/jfriend00/qncEz/

jfriend00
fonte
11

Você pode codificar uma função auxiliar ES5.1:

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

Chame assim:

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

Ou crie uma função que crie um elemento incluindo 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%'não funcionaria usando atributos. Para uma altura / largura de 100% você precisa dos elementosstyle.height/style.width

KooiInc
fonte
@vsync Embora eu aprecie sua opinião negativa aleatória e insulto, há pouca diferença fundamental entre esta e qualquer outra resposta aqui. Acalme-se.
Chris Baker
@Chris - foi aleatório sim, porque eu queria promover essa resposta, então tive que votar contra a resposta acima dela. e sim, se você tem 1000 itens e deve alterar 5 atributos para cada um, seria melhor recriá-los com os novos atributos do que acessar o DOM 5000 vezes, não concorda?
vsync
@vsync se você estiver usando uma função de copiar / colar aleatória encontrada no StackOverflow sem considerar o desempenho especial relacionado ao seu caso de uso, provavelmente terá um problema maior. Além disso, na resposta que você votou negativamente, o DOM não seria acessado 5.000 vezes, não mais do que esta resposta - em ambos os casos, o elemento em questão não foi inserido na árvore DOM. Esta resposta e a minha fazem a mesma coisa, simplesmente iteramos as propriedades de maneira diferente.
Chris Baker
@Chris - Essa questão não me preocupa. porque você está falando sobre mim e o que eu faço ou não? é irrelevante. Sua resposta não é muito boa se for necessário alterar os atributos de muitos nós no próprio DOM, enquanto esta resposta é um pouco melhor porque promove uma boa maneira de pensar, onde você recria o nó com todos os seus atributos e recria instale-o no DOM. Este também não é o ideal, porque usar o clonemétodo seria preferível. Não há necessidade de criar o nó inteiro do zero. De qualquer forma, é prioridade minimizar o acesso ao DOM, o caso de uso mais comum.
vsync
@vsync A palavra "você" é usada em um sentido abstrato, não significando você como um indivíduo (o que tenho certeza que você, vsynch, conhece), mas para o futuro consumidor hipotético dessas respostas. Mais uma vez, as duas respostas são idênticas em função. Você é livre para votar como quiser, mesmo que seu raciocínio seja errado (verifique os benchmarks), mas guarde seus comentários condescendentes para si mesmo.
Chris Baker
3

Tente isto

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: AQUI

Slawe
fonte
1

use esta função para criar e definir atributos ao mesmo tempo

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

use assim

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

fonte
1

Eu acho que é a melhor maneira de definir atributos de uma vez para qualquer elemento desta 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);
Dr. JavaB
fonte
1

você pode simplesmente adicionar um método (setAttributes, com "s" no final) ao protótipo de "Elemento" como:

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

você pode defini-lo em uma linha:

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

e você pode chamá-lo normalmente como chama os outros métodos. Os atributos são fornecidos como um objeto:

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

você pode adicionar uma instrução if para lançar um erro se o argumento fornecido não for um objeto.

Soufyane Hedidi
fonte