การตั้งค่าแอตทริบิวต์หลายรายการสำหรับองค์ประกอบพร้อมกันด้วย JavaScript


90

ฉันจะตั้งค่าหลายแอตทริบิวต์พร้อมกันด้วย JavaScript ได้อย่างไร? ขออภัยฉันไม่สามารถใช้เฟรมเวิร์กเช่น jQuery ในโปรเจ็กต์นี้ได้ นี่คือสิ่งที่ฉันมีตอนนี้:

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

elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");

1
คำตอบจากการใช้ @Quantastical Object.assign()นั้นคุ้มค่ากับการมองหาผู้ที่ไม่ต้องการสร้างฟังก์ชันตัวช่วย - ใช้ได้กับ "คุณสมบัติที่ระบุได้และเป็นของตัวเองทั้งหมด "
benvc

4
ฉันเลื่อนดูคำตอบทั้งหมดโดยหวังว่าใน 7 ปีนับตั้งแต่มีการโพสต์คำถามนี้ว่าจะมีการอัปเดต ES7 บางอย่างทำให้เราไม่ต้องเขียนฟังก์ชันของเราเองเช่นคำตอบของ @ Ariel
krummens

คำตอบ:


122

คุณสามารถสร้างฟังก์ชันตัวช่วย:

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

เรียกแบบนี้ว่า

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

1
มันก็ไม่พร้อมกันด้วยดังนั้นจะไม่มีผลต่อประสิทธิภาพ
vsync

นี่ไม่ใช่สิ่งที่เขาถาม เราจำเป็นต้องรู้วิธีการปรับปรุงประสิทธิภาพ
jbartolome

19
@jbartolome - ไม่มีการพูดถึงคำว่า "ประสิทธิภาพ" สักครั้งในคำถาม ฉันไม่รู้ว่าคุณได้แนวคิดนั้นมาจากไหน ดูเหมือนคำถามจะหาวิธีที่จะไม่ต้องโทรelem.setAttribute()หลายครั้งด้วยตนเอง
jfriend00

ฉันไม่แน่ใจว่าคำถามต้องการอะไรจริงๆ ผลลัพธ์ที่ต้องการที่เป็นไปได้ที่ดีคือการเรียกใช้ attributeChangedCallback "เพียงครั้งเดียว" ถ้าฉันต้องการเรียกใช้ฟังก์ชันที่ขึ้นอยู่กับแอตทริบิวต์สองรายการโดยปกติจะเรียก attributeChangedCallback สองครั้งหนึ่งรายการสำหรับการเปลี่ยนแปลงแต่ละแอตทริบิวต์ การเข้าถึง this.getAttribute ('your-attr') สำหรับแอตทริบิวต์ทั้งสองและการออกหากหนึ่งในนั้นยังคงว่างเปล่าเป็นวิธีแก้ปัญหาแรก แต่ไม่ได้จัดการกรณีที่มีการตั้งค่าแอตทริบิวต์เพียงรายการเดียวและอีกรายการหนึ่งมีค่าก่อนหน้านี้แล้ว . แต่พระเจ้าช่วยนี่ไม่ใช่คำถามที่มีวัตถุประสงค์จริงๆ ไม่ใช่เรื่องง่าย!
Vladimir Brasil

23

คุณอาจสามารถใช้ Object.assign(...)เพื่อใช้คุณสมบัติของคุณกับองค์ประกอบที่สร้างขึ้น ดูความคิดเห็นสำหรับรายละเอียดเพิ่มเติม

โปรดทราบว่าheightและwidthแอตทริบิวต์ถูกกำหนดเป็นพิกเซลไม่ใช่เปอร์เซ็นต์ คุณจะต้องใช้ CSS เพื่อทำให้ลื่นไหล

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
คุณสมบัติ elem.height เป็นต้นเป็นแบบอ่านอย่างเดียวดังนั้นจึงล้มเหลว ฉันมองไปที่ตัวอธิบายและพวกเขาเป็นผู้เข้าถึงที่มีเพียง getter (ตัวตั้งค่าที่ไม่ได้กำหนด)
lukeuser

@lukeuser ขอบคุณสำหรับความคิดเห็น ฉันไม่รู้ว่าคุณสมบัติเหล่านั้นเป็นแบบอ่านอย่างเดียว
ผู้ใช้

2
สำหรับคำถามของคุณเกี่ยวกับ "คุณทำไม่ได้แค่ ... " ฉันอาจถามสิ่งนี้เมื่อคุณทำไม่ได้
JP Silvashy

2
@JPSilvashy ฉันไม่ได้ตั้งใจให้ "คุณไม่ได้แค่" ของฉันที่จะถูกมองว่าเป็นการดูแคลนหรือแสดงให้เห็นถึงความเหนือกว่า ขออภัยหากเป็นเช่นนั้น ฉันไม่แน่ใจจริงๆว่านี่จะเป็นคำตอบที่เหมาะสมหรือไม่เพราะฉันไม่ใช่นินจา JavaScript ดังนั้นฉันจึงหวังว่าคนอื่น ๆ เช่น lukeuser อาจส่งเสียงเข้ามาเพื่อช่วยเสริมสร้างตรรกะ
ผู้ใช้

13

หากคุณต้องการไวยากรณ์ framework-esq ( หมายเหตุ:รองรับ IE 8+ เท่านั้น) คุณสามารถขยายElementต้นแบบและเพิ่มsetAttributesฟังก์ชันของคุณเองได้:

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

สิ่งนี้ช่วยให้คุณใช้ไวยากรณ์ดังนี้:

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

ลองใช้: http://jsfiddle.net/ywrXX/1/

หากคุณไม่ชอบการขยายโฮสต์อ็อบเจ็กต์ ( บางตัวไม่เห็นด้วย ) หรือต้องการรองรับ IE7- เพียงแค่ใช้เป็นฟังก์ชัน

โปรดทราบว่าsetAttributeจะใช้ไม่ได้กับstyleใน IE หรือตัวจัดการเหตุการณ์ (คุณไม่ควรอยู่แล้ว) รหัสด้านบนจัดการstyleแต่ไม่ใช่เหตุการณ์

เอกสารประกอบ


สำหรับบันทึก: IE7 ->'Element' is undefined
KooiInc

ใช่ยุติธรรมพอ ลืม IE7 และวัตถุ COM คุณสามารถโอเวอร์โหลดdocument.createElementและdocument.getElementByIdใช้สิ่งนี้ .... หรือเพียงแค่ปิดฟังก์ชันการทำงานในฟังก์ชัน แก้ไขคำตอบเพื่อรวมบันทึกนั้น
Chris Baker

2
เวอร์ชันเรียกซ้ำที่ง่ายขึ้น: jsfiddleมี IE shim
Keleko

ฉันชอบ Keleko เวอร์ชั่นที่เรียบง่ายมาก! สิ่งเดียวคือในเวอร์ชันของคุณไม่มี innerText ใน JSFiddle ของคุณ ฉันลองเพิ่มอื่น ๆ if (ที่ [prop] === html) {this.innerHTML = set [prop]; } และไม่ได้ผล ฉันได้รับข้อผิดพลาด ฉันจะเพิ่มการตั้งค่า innerText ได้อย่างไร?
Jessica

คำตอบนี้ช่วยให้คุณสามารถใช้อ็อบเจ็กต์เดียวที่มีแอตทริบิวต์องค์ประกอบคุณสมบัติ css (อาจอยู่ในอ็อบเจ็กต์ที่ซ้อนกัน) และ innerHTML นอกจากนี้ยังแสดงวิธีการใช้สิ่งนี้แก้ไขต้นแบบองค์ประกอบ (อืมม) หรือใช้เป็นฟังก์ชันปกติ (อ๊ะ) งานที่ดี!
Andrew Willems

12

คุณสามารถสร้างฟังก์ชันที่รับอาร์กิวเมนต์จำนวนตัวแปร:

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

หรือคุณส่งคู่แอตทริบิวต์ / ค่าในวัตถุ:

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

คุณยังสามารถสร้าง / วิธีการห่ออ็อบเจ็กต์ chainable ของคุณเอง:

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

ตัวอย่างการทำงาน: http://jsfiddle.net/jfriend00/qncEz/


12

คุณสามารถเขียนโค้ดฟังก์ชันตัวช่วย ES5.1:

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

เรียกแบบนี้ว่า

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


4

หรือสร้างฟังก์ชันที่สร้างองค์ประกอบรวมถึงแอตทริบิวต์จากพารามิเตอร์

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%'จะไม่ทำงานโดยใช้แอตทริบิวต์ สำหรับความสูง / ความกว้าง 100% คุณต้องมีองค์ประกอบstyle.height/style.width


@vsync ในขณะที่ฉันชื่นชมการลงคะแนนแบบสุ่มและการดูถูกของคุณมีความแตกต่างพื้นฐานเล็กน้อยระหว่างสิ่งนี้กับคำตอบอื่น ๆ ที่นี่ ใจเย็น ๆ.
Chris Baker

@ คริส - มันสุ่มใช่เพราะฉันต้องการโปรโมตคำตอบนี้แทนดังนั้นฉันจึงต้องลดคะแนนคำตอบด้านบน และใช่ถ้าคุณมี 1,000 รายการและคุณต้องเปลี่ยน 5 แอตทริบิวต์สำหรับแต่ละรายการจะเป็นการดีที่สุดที่จะสร้างใหม่ด้วยแอตทริบิวต์ใหม่แทนที่จะเข้าถึง DOM 5,000 ครั้งคุณจะไม่เห็นด้วยหรือ?
vsync

@vsync หากคุณใช้ฟังก์ชันคัดลอก / วางแบบสุ่มที่คุณพบใน StackOverflow โดยไม่ได้พิจารณาถึงประสิทธิภาพพิเศษที่เกี่ยวข้องกับกรณีการใช้งานของคุณคุณอาจมีปัญหาใหญ่ขึ้น นอกจากนี้ในคำตอบที่คุณลงคะแนน DOM จะไม่สามารถเข้าถึงได้ 5,000 ครั้งไม่มากไปกว่าคำตอบนี้ - ในทั้งสองกรณีองค์ประกอบที่เป็นปัญหายังไม่ได้ถูกแทรกลงในโครงสร้าง DOM คำตอบนี้และของฉันทำในสิ่งเดียวกันเราก็ย้ำคุณสมบัติให้แตกต่างกัน
Chris Baker

@ คริส - คำถามนี้ไม่เกี่ยวกับฉัน ทำไมคุณถึงพูดถึงฉันและฉันทำอะไร? มันไม่เกี่ยวข้อง คำตอบของคุณไม่ดีนักหากจำเป็นต้องเปลี่ยนแอตทริบิวต์ของโหนดจำนวนมากใน DOM เองในขณะที่คำตอบนี้ดีกว่าเล็กน้อยเนื่องจากส่งเสริมวิธีคิดที่ดีโดยที่คุณสร้างโหนดขึ้นมาใหม่ด้วยคุณสมบัติทั้งหมดและสร้างใหม่ ติดตั้งใน DOM นอกจากนี้ยังไม่เหมาะเพราะควรใช้cloneวิธีนี้ ไม่จำเป็นต้องสร้างโหนดทั้งหมดตั้งแต่เริ่มต้น อย่างไรก็ตามสิ่งสำคัญที่สุดคือต้องลดการเข้าถึง DOM ซึ่งเป็นกรณีการใช้งานที่พบบ่อยที่สุด
vsync

@vsync คำว่า "คุณ" ใช้ในความหมายนามธรรมไม่ได้หมายถึงคุณในฐานะปัจเจกบุคคล (ซึ่งผมค่อนข้างมั่นใจว่าคุณ vsynch รู้) แต่ใช้กับผู้บริโภคในอนาคตของคำตอบเหล่านี้ อีกครั้งทั้งสองคำตอบเหมือนกันในฟังก์ชัน คุณมีอิสระที่จะลงคะแนนว่าคุณต้องการทำอย่างไรแม้ว่าเหตุผลของคุณจะมีข้อบกพร่อง (ตรวจสอบเกณฑ์มาตรฐาน) แต่ให้ใช้คำพูดที่เอื้ออาทรกับตัวเอง
Chris Baker

3

ลองทำตามนี้

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

สาธิต: ที่นี่


2

คุณสามารถเพิ่มเมธอด (setAttributes โดยมี "s" ต่อท้าย) ไปยังต้นแบบ "Element" เช่น:

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

คุณสามารถกำหนดได้ในบรรทัดเดียว:

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

และคุณสามารถเรียกมันได้ตามปกติเมื่อคุณเรียกวิธีอื่น ๆ แอตทริบิวต์ถูกกำหนดให้เป็นวัตถุ:

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

คุณสามารถเพิ่มคำสั่ง if เพื่อโยนข้อผิดพลาดหากอาร์กิวเมนต์ที่กำหนดไม่ใช่วัตถุ


ตอนนี้เข้าท่าแล้ว ฉันสงสัยว่าจะทำการเปลี่ยนแปลงประเภทนี้กับฟังก์ชันที่กำหนดไว้ล่วงหน้าได้อย่างไร ขอบคุณ!
testing_22

1

ใช้ฟังก์ชันนี้เพื่อสร้างและตั้งค่าแอตทริบิวต์ในเวลาเดียวกัน

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

ใช้แบบนั้น

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

1

ฉันเดาว่าเป็นวิธีที่ดีที่สุดในการตั้งค่าคุณลักษณะพร้อมกันสำหรับองค์ประกอบใด ๆ ในคลาสนี้

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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.