Jednoczesne ustawienie wielu atrybutów dla elementu za pomocą JavaScript

88

Jak mogę ustawić wiele atrybutów jednocześnie za pomocą JavaScript? Niestety nie jestem w stanie użyć frameworka takiego jak jQuery w tym projekcie. Oto, co mam teraz:

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

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");
JP Silvashy
źródło
1
Odpowiedź od @Quantastical Object.assign()jest warta poszukania dla tych, którzy nie chcą tworzyć funkcji pomocniczej - działa dla „wszystkich wyliczalnych i własnych właściwości”.
benvc
4
Przewinąłem wszystkie odpowiedzi, mając nadzieję, że za 7 lat od opublikowania tego pytania będzie jakaś aktualizacja ES7, dzięki czemu nie będziemy musieli pisać własnej funkcji, takiej jak odpowiedź @ Ariel
krummens

Odpowiedzi:

119

Możesz zrobić funkcję pomocniczą:

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

Nazwij to tak:

setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});
Ariel
źródło
1
cóż, nie jest to również od razu, więc nie będzie to miało wpływu na wydajność.
vsync
Nie o to prosił. Musimy wiedzieć, jak poprawić wydajność
jbartolome
19
@jbartolome - Słowo „wydajność” nie pojawia się ani razu w pytaniu. Nie wiem, skąd wziął się ten pomysł. Wydaje się, że pytanie dotyczy sposobu, aby nie musieć ręcznie dzwonić elem.setAttribute()wiele razy.
jfriend00
Nie jestem pewien, czego naprawdę chce to pytanie. Dobrym możliwym pożądanym wynikiem jest wywołanie atrybutu attributeChangedCallback „tylko raz”. Jeśli muszę wywołać funkcję, która zależy od dwóch atrybutów, zwykle atrybut attributeChangedCallback jest wywoływany dwukrotnie, po jednym dla każdej zmiany atrybutu. Uzyskanie dostępu do this.getAttribute ('your-attr') dla obu atrybutów i wyjście, jeśli jeden z nich jest nadal pusty, jest pierwszym rozwiązaniem, ALE nie obsługuje przypadku, w którym ustawiony jest tylko jeden atrybut, a drugi ma już poprzednią wartość . Ale Bóg pomaga, to nie jest pytanie w rzeczywistości obiektywne. Niełatwe!
Vladimir Brasil
21

Możesz użyć, Object.assign(...)aby zastosować swoje właściwości do utworzonego elementu. Dodatkowe informacje można znaleźć w komentarzach.

Pamiętaj, że atrybuty heighti widthdefiniowane w pikselach , a nie w procentach. Będziesz musiał użyć CSS, aby uczynić go płynnym.

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 }

użytkownik
źródło
1
Właściwości, elem.height itp. Są tylko do odczytu, więc to się nie powiedzie. Przyjrzałem się deskryptorom i są to metody dostępu z tylko funkcją pobierającą (ustawiającą niezdefiniowaną).
lukeuser
@lukeuser Dziękuję za komentarz. Nie wiedziałem, że te właściwości są tylko do odczytu.
użytkownik
2
Na twoje pytanie „czy nie mógłbyś po prostu ...” Zadałem to prawdopodobnie wtedy, gdy tak naprawdę nie mogłeś po prostu.
JP Silvashy,
2
@JPSilvashy Nie chciałem, aby moje „nie mógłbyś po prostu” wydawać się poniżające lub okazywać oznakę wyższości. Przepraszam, jeśli tak. Szczerze mówiąc, nie byłem pewien, czy to byłaby odpowiednia odpowiedź, ponieważ nie jestem ninja JavaScript, więc miałem nadzieję, że inni, tacy jak lukeuser, mogą wtrącić się, aby pomóc utrwalić logikę.
użytkownik
13

Jeśli chcesz mieć składnię framework-esq ( Uwaga: tylko obsługa IE 8+), możesz rozszerzyć Elementprototyp i dodać własną setAttributesfunkcję:

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

Pozwala to na użycie następującej składni:

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

Wypróbuj: http://jsfiddle.net/ywrXX/1/

Jeśli nie lubisz rozszerzać obiektu hosta ( niektórzy są przeciwni ) lub potrzebujesz obsługi IE7-, po prostu użyj go jako funkcji

Zauważ, że setAttributenie będzie działać stylew IE ani w obsłudze zdarzeń (i tak nie powinieneś). Powyższy kod obsługuje style, ale nie zdarzenia.

Dokumentacja

Chris Baker
źródło
Dla 'Element' is undefined
przypomnienia
Tak, w porządku. Zapomniałem o IE7 i ich obiektach COM. Możesz to przeciążyć document.createElementi document.getElementByIdpodkręcić ... lub po prostu zawinąć funkcjonalność w funkcję. Zredagowana odpowiedź, aby uwzględnić tę notatkę
Chris Baker
2
bardziej uproszczona wersja rekurencyjna: jsfiddle zawiera podkładkę IE
Keleko
Bardzo podoba mi się uproszczona wersja Keleko! Jedyną rzeczą jest to, że w twojej wersji nie ma wewnętrznego tekstu w twoim JSFiddle. Próbowałem dodać else if (at [prop] === html) {this.innerHTML = set [prop]; } i to nie zadziałało. Otrzymuję błąd. Jak mogę dodać ustawienie innerText?
Jessica
Ta odpowiedź pozwala na użycie pojedynczego obiektu, który zawiera atrybuty elementów, właściwości CSS (potencjalnie w obiekcie zagnieżdżonym) i innerHTML. Pokazuje również, jak użyć tej modyfikacji prototypu elementu (hmmm) lub użyć go jako normalnej funkcji (ahhh). Dobra robota!
Andrew Willems
12

Możesz utworzyć funkcję, która przyjmuje zmienną liczbę argumentów:

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

Lub przekazujesz pary atrybut / wartość w obiekcie:

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

Możesz także stworzyć własne opakowanie / metodę obiektu z możliwością łączenia w łańcuch:

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

Przykład roboczy: http://jsfiddle.net/jfriend00/qncEz/

jfriend00
źródło
11

Możesz zakodować funkcję pomocniczą ES5.1:

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

Nazwij to tak:

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

Lub utwórz funkcję, która tworzy element zawierający atrybuty na podstawie parametrów

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%'nie działa przy użyciu atrybutów. Dla wysokości / szerokości 100% potrzebujesz elementówstyle.height/style.width

KooiInc
źródło
@vsync Chociaż doceniam twoją przypadkową negatywną opinię i zniewagę, istnieje niewielka podstawowa różnica między tą a jakąkolwiek inną odpowiedzią. Uspokój się.
Chris Baker
@Chris - to było przypadkowe, tak, ponieważ zamiast tego chciałem promować tę odpowiedź, więc musiałem obniżyć odpowiedź powyżej. i tak, jeśli masz 1000 elementów i musisz zmienić 5 atrybutów dla każdego, najlepiej byłoby odtworzyć je z nowymi atrybutami niż uzyskać dostęp do DOMu 5000 razy, czy nie zgodziłbyś się?
vsync
@vsync, jeśli używasz losowej funkcji kopiuj / wklej, którą znalazłeś w StackOverflow bez uwzględnienia specjalnej wydajności dziedziczonej w twoim przypadku użycia, prawdopodobnie masz większy problem. Co więcej, w odpowiedzi, którą zagłosowałeś w dół, dostęp do DOM nie byłby możliwy 5000 razy, nie więcej niż ta odpowiedź - w obu przypadkach przedmiotowy element nie został wstawiony do drzewa DOM. Ta odpowiedź i moja robią to samo, po prostu wykonujemy różne iteracje właściwości.
Chris Baker
@Chris - To pytanie mnie nie dotyczy. dlaczego mówisz o mnie i co robię, czy nie? to nie ma znaczenia. Twoja odpowiedź nie jest zbyt dobra, jeśli trzeba zmienić atrybuty wielu węzłów w samym DOM, podczas gdy ta odpowiedź jest nieco lepsza, ponieważ promuje dobry sposób myślenia, w którym ponownie tworzysz węzeł ze wszystkimi jego atrybutami i ponownie zainstaluj go w DOM. To również nie jest idealr, ponieważ clonepreferowane byłoby użycie tej metody. Nie ma potrzeby tworzenia całego węzła od podstaw. W każdym razie priorytetem jest zminimalizowanie dostępu do DOM, najczęstszego przypadku użycia.
vsync
@vsync Słowo „ty” jest używane w sensie abstrakcyjnym, nie oznacza ciebie jako jednostki (co, jestem pewien, że znasz, vsynch), ale do hipotetycznego przyszłego konsumenta tych odpowiedzi. Po raz kolejny obie odpowiedzi mają identyczną funkcję. Możesz głosować, jak chcesz, nawet jeśli twoje rozumowanie jest błędne (sprawdź testy porównawcze), ale zachowaj protekcjonalne uwagi dla siebie.
Chris Baker
3

Spróbuj tego

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

Slawe
źródło
1

użyj tej funkcji do tworzenia i ustawiania atrybutów w tym samym czasie

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

używaj go w ten sposób

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

źródło
1

Myślę, że to najlepszy sposób na jednoczesne ustawienie atrybutów dla dowolnego elementu w tej klasie.

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
źródło
1

możesz po prostu dodać metodę (setAttributes, z „s” na końcu) do prototypu „Element”, na przykład:

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

możesz to zdefiniować w jednej linii:

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

i możesz to wywołać normalnie, tak jak wywołujesz inne metody. Atrybuty podane są jako obiekt:

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

możesz dodać instrukcję if, aby zgłosić błąd, jeśli dany argument nie jest obiektem.

Soufyane Hedidi
źródło