如何在扩展DIV元素时创建多个元素?

3
我正在尝试通过使用新创建的div作为对象的原型,通过Javascript“扩展”DIV。
据我了解,当通过“new”创建我的对象的新实例时,原型对象被复制,分配给“this”,然后执行函数(作为构造函数)。
一切似乎都很顺利,除了每当我创建另一个对象并将其添加到DOM时,它就会“替换”原始的div。更确切地说:构造函数总是更改同一个div。
使用MyTest.prototype = document.createElement("div");会给我描述的行为,我的代码示例中之后的两行已注释掉,但没有效果。
我知道尝试扩展DOM是不受欢迎的,但我想要理解这种行为,因为我认为我知道原型如何工作,而这根本不符合我的想法。
以下是我正在尝试做的最小示例:
<!DOCTYPE html>
<html>
<head>
<title>Div-Prototype-Test</title>
<script type="text/javascript">

var height = 20;
var top = 0;

function MyTest() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);

    this.style.backgroundColor = "rgb("+ r +","+ g +","+ b +")";
    this.style.position        = "absolute";
    this.style.width           = "500px";
    this.style.height          = height + "px";
    this.style.top             = top + "px";

    top += height;

    document.getElementsByTagName("body")[0].appendChild(this);
}

MyTest.prototype = document.createElement("div");
// MyTest.prototype = document.createElement("div").cloneNode(true);
// MyTest.prototype = new Element();

window.addEventListener(
    "load", 
    function() {
        var a = new MyTest();
        var b = new MyTest();
        var c = new MyTest();
        var d = new MyTest();
    }
);

</script>
</head>
<body>
</body>
</html>

PS:由于某些Javascript框架的原因,我搜索任何能够改变Javascript原型的东西总是得到数百个与我的问题无关的结果 - 请告诉我是否错过了已经讨论此问题的问题。

编辑:

为了使我的问题更清晰:

这里有一个示例,我使用对象作为原型 - 它的属性会被复制。

function A() {
}

A.prototype = { property: 4 };

A.prototype.set = function(num) {
    this.property = num;
}

window.addEventListener(
    "load", 
    function() {
        var message = "";

        var x1 = new A();
        message += "A1 : "+ x1.property +"\n";

        x1.set(15);
        message += "A1 : "+ x1.property +"\n";

        var x2 = new A();
        message += "A2 : "+ x2.property +"\n";

        alert(message);
    }
);

警告随后说:
A1 : 4
A1 : 15
A2 : 4

然而,我第一个示例中的 Div 似乎没有被复制,它的行为类似于 Singleton 或 Monostate。难道不应该像这样吗?

  1. 原型对象被复制到一个新对象中
  2. 将新对象分配给“this”
  3. 将此对象传递给构造函数
  4. 构造函数返回此对象(如果没有指定返回语句)
3个回答

2
MyTest.prototype = document.createElement("div");

这行代码只会被执行一次。它创建了一个MyTest.prototype对象,该对象也是一个DOM元素<div>每个MyTest 对象将接收到相同的原型对象。因此,您创建的每个MyTest 对象都会与此单个<div>相关联,而该<div>只会被创建一次。您需要为每个MyTest 创建一个新的<div>

尝试以下模式:

MyTest = function() {
    var myDiv = document.createElement("div");

    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);

    myDiv.style.backgroundColor = "rgb("+ r +","+ g +","+ b +")";
    myDiv.style.position        = "absolute";
    myDiv.style.width           = "500px";
    myDiv.style.height          = height + "px";
    myDiv.style.top             = top + "px";

    top += height;

    document.getElementsByTagName("body")[0].appendChild(myDiv);

    return myDiv;
}

这个函数使用createElement()方法创建一个新的<div>,然后设置您想要的所有属性。最后,它将返回您的新<div>。因此,您可以像下面这样调用它:

var myNewDiv = MyTest();
var myNewDiv = new MyTest();

两种方法都可以使用。在第二种情况下,通过 new 关键字创建了一个虚拟的新对象,但这并不重要,因为函数内部创建的新的<div> 实际上是返回的。


这就是我不理解的地方:当我使用一个不同的对象作为原型时,它和它的属性被复制了。但是当我改变其中一个属性时,它并不会改变原型的属性,对吧? - sirion
1
它们并没有被复制。例如,如果在MyTest.prototype中有一个属性x,并且您有var test = new MyTest(); test.x ='abc';,那么您实际上向test对象添加了一个新的x属性,并隐藏了原型中的x属性。但是,在您的代码中,您不会向每个对象添加新属性。所有实例都引用style属性,该属性仍在原型中,并属于您创建的单个div。 - Imp
已经对问题和答案加了1 - 原型有时非常令人困惑... - Symeon Breen
@sirion 因为当你调用 x1.set(15); 时,它执行了 set() 函数内的代码:this.property = num;,其中 x1this15num,所以它执行了 x1.property = 15;。这在对象 x1 中创建了一个 属性名为 property 的属性。因此发生的情况是:在对象 x1 中找到了值为 15x1.property。在对象 x2 中没有找到 x2.property,因此查找继续进入原型。在那里,它被找到并具有值 4 - Imp
那意味着原型没有被复制。我不理解第二个例子中的 "property" 属性和第一个例子的 "style" 有什么区别:两者都不存在,但在第二种情况下会创建一个副本,而在第一种情况下会使用实际的原型属性 "style"。 - sirion
显示剩余2条评论

0

你把所有的东西都混在一起了。首先,查看我的这个SO问题的答案。其次,扩展Element对象是可行的,但并不被所有浏览器支持。查看这个SO问题

我认为你计划以某种标准化的方式向document添加元素。你的代码可以重写为(我稍微修改了一下):

function appendElement(content,id) {
    var rgb = 'rgb('+ [Math.floor(Math.random() * 256),
               Math.floor(Math.random() * 256),
               Math.floor(Math.random() * 256)].join(',') +')';
    var top  = Math.floor( Math.random() * 300 + 20 );
    var left = Math.floor( Math.random() * 100 + 10 );

    this.style.backgroundColor = rgb;
    this.style.position        = "absolute";
    this.style.width           = "500px";
    this.style.height          = "200px";
    this.style.left            = left+"px";
    this.style.top             = top+"px";
    this.innerHTML             = content || '';
    this.id                    = id || Math.Random*10000+1
    document.getElementsByTagName("body")[0].appendChild(this);
}

现在,您可以使用以下方式将任何元素附加到document中:使用`appendElement`。
appendElement.call(document.createElement('div'),'empty div');
appendElement.call(document.createElement('span'),'new empty span','span1');

这对你的目标来说是一个好主意吗?


其实我的原始想法是向DOM添加具有附加功能的元素(现在我只想了解为什么它不起作用)。像 xxx.appendChild(new FadeDiv(urlList));,其中urlList是图像URL的数组。然后应该在后台加载图像并从一个图像淡入到另一个图像。这个想法是它应该像任何其他div一样可用。 - sirion

0

我找到了一个解决方法,基本上是相反的方式 - 原型是一个空对象,我将新对象的数据复制到构造函数中的一个 div 中:

var height = 20;
var top = 0;

function deepCopy(fromObject, toObject, depth) {
    if(typeof(fromObject) != "object" || typeof(toObject) != "object") {
        // throw "deepCopy only copies objects"
        return;
    }

    if (typeof(depth) == "undefined") {
        depth = 0;
    } else if (depth > 100) {
        // Recursion depth too high. Abort.
        // throw "deepCopy recursion depth cap hit"
        return;
    }

    for (var key in fromObject) {
        if (typeof(fromObject[key]) == "object" && fromObject[key] != null) {
            if (typeof(fromObject[key].nodeType) != "undefined") {
                toObject[key] = fromObject[key].cloneNode(true);
            } else {
                if (typeof(toObject[key]) != "object") {
                    toObject[key] = {};
                }
                deepCopy(fromObject[key], toObject[key], depth + 1);
            }           

        }
        toObject[key] = fromObject[key];
    }
}    

function MyTest() {
    // This is ugly...
    var self = document.createElement("div");
    deepCopy(MyTest.prototype, self);

    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);

    self.style.backgroundColor = "rgb("+ r +","+ g +","+ b +")";
    self.style.position        = "absolute";
    self.style.width           = "500px";
    self.style.height          = height + "px";
    self.style.top             = top + "px";

    top += height;

    document.getElementsByTagName("body")[0].appendChild(self);

    return self;
}

MyTest.prototype = {};
// MyTest.prototype = document.createElement("div").cloneNode(true);
// MyTest.prototype = new Element();

window.addEventListener(
    "load", 
    function() {
        var a = new MyTest();
        var b = new MyTest();
        var c = new MyTest();
        var d = new MyTest();
    }
);

虽然我感觉我的deepCopy函数是一种相当不优雅(可能非常有bug)的方式来执行任务,但使用cloneNode()的另一种方式却行不通。

我的原始问题源于此:当复制原型时,所有标量值都会被复制,而所有对象只是被引用(就像复制指针一样,指针值被复制,但它所指向的数据并没有被复制)。

希望这能帮助到某些人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接