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

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

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 }


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


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/


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

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

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


@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


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

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

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.