简体   繁体   English

如何将对象与DOM元素关联

[英]How to Associate an Object with a DOM Element

I have a master object in my JS setup, ie: 我的JS设置中有一个主对象,即:

var myGarage = {
    cars: [
        {
            make: "Ford",
            model: "Escape",
            color: "Green",
            inuse: false
        },
        {
            make: "Dodge",
            model: "Viper"
            color: "Red",
            inuse: true
        },
        {
            make: "Toyota",
            model: "Camry"
            color: "Blue",
            inuse: false
        }
    ]
}

Now I loop over my cars and put them in a table. 现在我把车停在我的车上并放在桌子上。 In the table I also have a button that lets me toggle the car as "in use" and "not in use". 在表格中,我还有一个按钮,可让我将车辆切换为“使用中”和“未使用中”。

How can I associate the DOM Element of every row with its corresponding car, so that if I toggle the "inuse" flag, I can update the master object? 如何将每行的DOM元素与其对应的汽车相关联,这样如果我切换“inuse”标志,我可以更新主对象?

You can actually attach an object directly to a node: 您实际上可以将对象直接附加到节点:

var n = document.getElementById('green-ford-escape');
n.carObject = myGarage.cars[0];
n.onclick = function() {
  doSomethingWith(this.carObject);
}

For the same of removing ambiguity, in some cases, it's more clear write the above event handler to refer to n instead of this : 对于同消除歧义,在某些情况下,它更明确写入上述事件处理程序指n而不是this

n.onclick = function() {
  doSomethingWith(n.carObject);
}

You can also refer directly to the object from the attached event: 您还可以直接引用附加事件中的对象:

var n = document.getElementById('green-ford-escape');
n.onclick = function() {
    doSomethingWith(myGarage.cars[0]);
}

In the latter case, myGarage does not have to be global. 在后一种情况下, myGarage 不必是全球性的。 You can do this and expect it to work correctly: 您可以执行此操作并期望它正常工作:

(function(){

    var myGarage = { /* ... etc ... */ };

    var n = document.getElementById('green-ford-escape');
    n.onclick = function() {
        doSomethingWith(myGarage.cars[0]);
    }

})();

The node's event function will "hold onto" the local variable correctly, effectively creating a private variable. 节点的事件函数将正确“保持”局部变量,有效地创建私有变量。

You can test this in your Chrome/FF/IE console: 您可以在Chrome / FF / IE控制台中测试:

var o = {a: 1};
var n = document.createElement('div');
n.innerHTML = "click me";
n.data = o;
n.onclick = function() { n.data.a++; console.log(n.data, o); }
document.body.appendChild(n);

You should see the console log two identical objects with each click, each with incrementing a values. 您应该看到控制台在每次单击时记录两个相同的对象,每个对象都递增a值。

Beware that setting n.data to a primitive will not create a reference. 请注意 ,将n.data设置为基元将不会创建引用。 It'll copy the value. 它会复制价值。

I'd suggest considering addEventListener , and a constructor that conforms your objects to the eventListener interface. 我建议考虑addEventListener ,以及一个使你的对象符合eventListener接口的构造函数。

That way you can have a nice association between your object, your element, and its handlers. 这样,您可以在对象,元素和处理程序之间建立良好的关联。

To do this, make a constructor that's specific to your data. 为此,请创建一个特定于您的数据的构造函数。

function Car(props) {
    this.make = props.make;
    this.model = props.model;
   // and so on...

    this.element = document.createElement("div"); // or whatever

    document.body.appendChild(this.element);      // or whatever

    this.element.addEventListener("click", this, false);
}

Then implement the interface: 然后实现界面:

Car.prototype.handleEvent = function(e) {
    switch (e.type) {
        case "click": this.click(e);
        // add other event types if needed
    }
}

Then implement your .click() handler on the prototype. 然后在原型上实现.click()处理程序。

Car.prototype.click = function(e) {
    // do something with this.element...
    this.element.style.color = "#F00";

    // ...and the other properties
    this.inuse = !this.inuse
}

So then you can just loop over the Array, and make a new Car object for each item, and it'll create the new element and add the listener(s). 那么你就可以遍历数组,并为每个项目创建一个新的Car对象,它将创建新元素并添加监听器。

myGarage.cars.forEach(function(obj) {
    new Car(obj)
})

You'll want some sort of ID or distinct row in your information, else you'll have to rely on the array index to do this. 您需要在信息中使用某种ID或不同的行,否则您将不得不依赖数组索引来执行此操作。 Either way you'll want to store the data using data attributes . 无论哪种方式,您都希望使用数据属性存储数据

So when you loop through: 所以当你循环:

for (var i = 0, l = array.length; i < l; i++) {
  var div = '<tr data-car="' + JSON.stringify(array[i]) + '" data-index="' + i + '"><td></td></tr>'
}

And on your click event: 并在您的点击事件:

$('button').click(function() {
    var carIndex = $(this).closest('tr').attr('data-index');
    var carData = $(this).closest('tr').attr('data-car');
    if (carData) carData = JSON.parse(carData);

    myGarage.cars[carIndex].inUse = true;
})

If you bind the data to the DOM, you may not even need to update the actual JS data. 如果将数据绑定到DOM,甚至可能不需要更新实际的JS数据。 Could go over each row in the table and re-create the data-object you created the table from. 可以遍历表中的每一行并重新创建从中创建表的数据对象。

You can use HTML5 data-* attribute to find out which row it is. 您可以使用HTML5 data- *属性找出它是哪一行。 You must be doing something like this 你必须做这样的事情

var table = $('<table>'); // Let's create a new table even if we have an empty table in our DOM. Simple reason: we will achieve single DOM operation (Faster)

for (var i=0; i<myGarbage.cars.length; i++) {
    // Create a new row and append to table
    var tr = $('<tr>').appendTo(table);

    var carObject = myGarbage.cars[i];
    // Traverse the JSON object for each car
    for (var key in carObject) {
        // Create other cells. I am doing the last one
        var td = $('<td>').appendTo(tr);
        var button = $('<button>').attr('data-carId', i).addClass('toggle-inuse').appendTo(td);
    }
}
// If en ampty table awaits me in DOM
$('#tableId').html(table.html());

Now we will add event listener on button :- 现在我们将在按钮上添加事件监听器: -

$('.toggle-inuse').click(function() {
    var i = $(this).data('carId');
    myGarbage.cars[i].inuse = !myGarbage.cars[i].inuse; //Wow done
}

Try this out !! 试试吧!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM