Définition de plusieurs attributs pour un élément à la fois avec JavaScript

88

Comment puis-je définir plusieurs attributs à la fois avec JavaScript? Malheureusement, je ne suis pas en mesure d'utiliser un framework comme jQuery sur ce projet. Voici ce que j'ai maintenant:

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

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");
JP Silvashy
la source
1
La réponse de @Quantastical en utilisant Object.assign()vaut le coup d'œil pour ceux qui ne veulent pas créer de fonction d'assistance - fonctionne pour "toutes les propriétés énumérables et propres ".
benvc
4
J'ai fait défiler toutes les réponses, en espérant que dans 7 ans après la publication de cette question, il y aurait une sorte de mise à jour ES7, ce qui nous
évitera d'

Réponses:

119

Vous pouvez créer une fonction d'assistance:

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

Appelez ça comme ça:

setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});
Ariel
la source
1
eh bien ce n'est pas tout de suite aussi, donc il n'y aura aucun effet sur les performances.
vsync
Ce n'est pas ce qu'il a demandé. Nous devons savoir comment améliorer les performances
jbartolome
19
@jbartolome - Le mot "performance" n'est pas mentionné une seule fois dans la question. Je ne sais pas d'où tu viens cette idée. La question semble chercher un moyen de ne pas avoir à appeler manuellement elem.setAttribute()plusieurs fois.
jfriend00
Je ne suis pas sûr de ce que veut vraiment la question. Un bon résultat souhaité possible est d'appeler attributeChangedCallback "une seule fois". Si j'ai besoin d'appeler une fonction qui dépend de deux attributs, attributChangedCallback est généralement appelé deux fois, un pour chaque changement d'attribut. Accéder à this.getAttribute ('your-attr') pour les deux attributs et quitter si l'un d'entre eux est toujours vide est une première solution MAIS cela ne gère pas le cas où un seul attribut est défini, et l'autre a déjà une valeur précédente . Mais Dieu aide ce n'est pas la question réellement objective. Pas facile!
Vladimir Brasil
21

Vous pourrez peut-être utiliser Object.assign(...)pour appliquer vos propriétés à l'élément créé. Voir les commentaires pour plus de détails.

Gardez à l'esprit que les attributs heightet widthsont définis en pixels et non en pourcentages. Vous devrez utiliser CSS pour le rendre fluide.

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 }

utilisateur
la source
1
Les propriétés, elem.height etc., sont en lecture seule, donc cela échoue. J'ai regardé les descripteurs, et ce sont des accesseurs avec seulement un getter (setter non défini).
lukeuser
@lukeuser Merci pour le commentaire. Je ne savais pas que ces propriétés étaient en lecture seule.
utilisateur
2
À votre question sur "ne pourrais-tu pas juste ..." je l'ai probablement posée alors que tu ne pouvais pas vraiment.
JP Silvashy
2
@JPSilvashy Je n'avais pas l'intention que mon "tu ne pourrais pas juste" paraisse comme dépréciant ou pour montrer un signe de supériorité. Désolé si c'est le cas. Honnêtement, je n'étais pas sûr que cela aurait été une réponse appropriée car je ne suis pas un ninja de JavaScript, alors j'espérais que d'autres comme lukeuser pourraient intervenir pour aider à solidifier la logique.
utilisateur
13

Si vous vouliez une syntaxe framework-esq ( Remarque: prise en charge d' IE 8+ uniquement), vous pouvez étendre le Elementprototype et ajouter votre propre setAttributesfonction:

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

Cela vous permet d'utiliser une syntaxe comme celle-ci:

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

Essayez-le: http://jsfiddle.net/ywrXX/1/

Si vous n'aimez pas étendre un objet hôte ( certains sont opposés ) ou si vous devez prendre en charge IE7-, utilisez-le simplement comme une fonction

Notez que setAttributecela ne fonctionnera pas styledans IE ou dans les gestionnaires d'événements (vous ne devriez pas de toute façon). Le code ci-dessus gère style, mais pas les événements.

Documentation

Chris Baker
la source
Pour mémoire: IE7 ->'Element' is undefined
KooiInc
Ouais, assez bien. J'ai oublié IE7 et leurs objets COM. Vous pouvez surcharger document.createElementet document.getElementByIdcaler ceci ... ou simplement envelopper la fonctionnalité dans une fonction. Réponse modifiée pour inclure cette note
Chris Baker
2
version récursive plus simplifiée: jsfiddle inclut un shim IE
Keleko
J'aime beaucoup la version simplifiée de Keleko! La seule chose est que, dans votre version, il n'y a pas de innerText dans votre JSFiddle. J'ai essayé d'ajouter else if (at [prop] === html) {this.innerHTML = set [prop]; } et cela n'a pas fonctionné. J'obtiens une erreur. Comment puis-je ajouter un paramètre innerText?
Jessica
Cette réponse vous permet d'utiliser un seul objet contenant des attributs d'élément, des propriétés css (potentiellement dans un objet imbriqué) et innerHTML. Il montre également comment utiliser ceci modifier le prototype d'élément (hmmm) ou l'utiliser comme une fonction normale (ahhh). Bon travail!
Andrew Willems
12

Vous pouvez créer une fonction qui prend un nombre variable d'arguments:

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, vous transmettez les paires attribut / valeur sur un objet:

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

Vous pouvez également créer votre propre wrapper / méthode d'objet chaînable:

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

Exemple de travail: http://jsfiddle.net/jfriend00/qncEz/

jfriend00
la source
11

Vous pouvez coder une fonction d'assistance ES5.1:

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

Appelez ça comme ça:

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

Ou créez une fonction qui crée un élément comprenant des attributs à partir de paramètres

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%'ne fonctionnerait pas en utilisant des attributs. Pour une hauteur / largeur de 100%, vous avez besoin des élémentsstyle.height/style.width

KooiInc
la source
@vsync Bien que j'apprécie votre vote défavorable et votre insulte au hasard, il y a peu de différence fondamentale entre cette réponse et toute autre réponse ici. Calmez-vous.
Chris Baker
@Chris - c'était au hasard oui, parce que je voulais promouvoir cette réponse à la place, donc j'ai dû voter contre la réponse au-dessus. et oui, si vous avez 1000 éléments et que vous devez changer 5 attributs pour chacun, il serait préférable de les recréer avec les nouveaux attributs plutôt que d'accéder au DOM 5000 fois, n'est-ce pas?
vsync
@vsync si vous utilisez une fonction de copier / coller aléatoire que vous avez trouvée sur StackOverflow sans tenir compte des performances particulières concernées héritées de votre cas d'utilisation, vous avez probablement un problème plus important. De plus, dans la réponse que vous avez déclinée, le DOM ne serait pas consulté 5000 fois, pas plus que cette réponse - dans les deux cas, l'élément en question n'a pas été inséré dans l'arborescence DOM. Cette réponse et la mienne font la même chose, nous itérons simplement les propriétés différemment.
Chris Baker
@Chris - Cette question ne me concerne pas. pourquoi parles-tu de moi et de ce que je fais ou pas? ce n'est pas pertinent. Votre réponse n'est pas très bonne si l'on a besoin de changer les attributs de nombreux nœuds sur le DOM lui-même, alors que cette réponse est légèrement meilleure car elle favorise une bonne façon de penser, où vous recréez le nœud avec tous ses attributs et re installez-le dans le DOM. Ce n'est pas non plus l'idéal, car l'utilisation de la cloneméthode serait préférable. Pas besoin de créer le nœud entier à partir de zéro. Quoi qu'il en soit, la priorité absolue est de minimiser l'accès au DOM, le cas d'utilisation le plus courant.
vsync
@vsync Le mot "vous" est utilisé dans un sens abstrait, ne signifiant pas vous en tant qu'individu (ce que je suis sûr que vous, vsynch, connaissez) mais pour le futur consommateur hypothétique de ces réponses. Encore une fois, les deux réponses ont une fonction identique. Vous êtes libre de voter comme vous le souhaitez, même si votre raisonnement est erroné (vérifiez les points de repère), mais gardez vos remarques condescendantes pour vous.
Chris Baker
3

Essaye ça

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

Slawe
la source
1

utilisez cette fonction pour créer et définir des attributs en même temps

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

utilisez-le comme ça

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

la source
1

Je suppose que c'est le meilleur moyen de définir des attributs à la fois pour n'importe quel élément de cette 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
la source
1

vous pouvez simplement ajouter une méthode (setAttributes, avec "s" à la fin) au prototype "Element" comme:

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

vous pouvez le définir en une seule ligne:

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

et vous pouvez l'appeler normalement comme vous appelez les autres méthodes. Les attributs sont donnés sous forme d'objet:

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

vous pouvez ajouter une instruction if pour lancer une erreur si l'argument donné n'est pas un objet.

Soufyane Hedidi
la source