将DOM元素包装在JavaScript对象中

时间:2011-01-20 05:13:47

标签: javascript dom constructor javascript-objects

我已经注意到我一直在编写的JavaScript中的一个常见模式,并且想知道是否已经存在一种类似于最佳实践的模式?本质上,它是如何获取DOM元素并将其包装在内部/与JavaScript对象关联。以此示例为例,您需要在Web应用中使用过滤器。您的页面如下所示:

<html>
<head></head>
<body>
    <div id="filter"></div>
</body>
</html>

然后你就像这样包装元素:

var myFilter = new Filter({
    elem: document.getElementById('filter'),
    prop: 'stacks-test',
    someCallback: function() {
        // specify a callback
    }
});

JavaScript(其中spec是传递给构造函数的对象):

var Filter = function(spec) {
    this.elem = spec.elem;
    this.prop = spec.prop;
    this.callback = spec.someCallback;
    this.bindEvents();
};

Filter.prototype.bindEvents = function() {
    var self = this;
    $(this.elem).click(function(e) {
        self.updateFeed();
    };
};

Filter.prototype.updateFeed = function() {
    this.prop; // 'stacks-test'
    this.callback();
    // ...
    // code to interact with other JavaScript objects
    // who in turn, update the document
};

这种方法叫做什么,最佳做法和注意事项是什么?

2 个答案:

答案 0 :(得分:2)

你可能对Dojo的小部件库Dijit感兴趣 - 如果我正确理解你的问题,它基本上就是你所要求的,还有更多。

在Dijit中,一个小部件本质上封装了一个DOM节点,它的内容,定义其行为的任何JavaScript,以及(单独导入)CSS来设置其外观的样式。

窗口小部件有自己的生命周期,注册表和事件(包括许多只是映射到窗口小部件节点上的DOM事件的事件,例如myWidget.onClick可以有效地调用myWidget.domNode.onclick)。

窗口小部件可以(但不必)在单独的HTML模板文件中定义其初始内容,通过它们还可以将模板中节点上的事件绑定到窗口小部件方法,以及在窗口小部件上设置属性引用模板中的特定节点。

我在这里几乎没有抓到表面。如果您想了解更多信息,可以从这些参考页面开始:

所有人都说,我不知道你最终的目标是什么,也许这对你的目的来说有点多了(考虑到我要把一整个其他图书馆扔给你),但是想到它可能会让你大吃一惊至少感兴趣。

答案 1 :(得分:1)

继续我对这个问题的评论,jQuery是一个潜在的工具,因为它已经为你所追求的目标提供了一些基础。然而,话虽如此,它确实引入了它自己的复杂性,而且,并非所有“jQuery方式”都是平等的。我建议使用jQuery作为“对象模型”的一种方法,但它可能适合或不适合您的需求。


首先要做的事情。 jQuery的理念是通过首先使用$()或等效jQuery()选择元素来启动所有内容。所有操作在概念上都以此开头。与创建包装元素并保持对该包装器的引用的对象相比,这是一种略微不同的思维方式,但实质上这就是jQuery为您所做的事情。对$('#some-id')的调用会获取id为“some-id”的元素并将其包装在jQuery对象中。


单向:编写“过滤器”插件。

initFilter() jQuery方法替换构造函数。您可以通过修改jQuery原型并使用jQuery对象作为包装器来完成此操作。 jQuery的原型由jQuery.fn引用,所以:

jQuery.fn.initFilter = function (prop, callback) {
    // Save prop and callback
    this.data('filter-prop', prop);
    this.data('filter-callback', callback);

    // Bind events (makes sense to do this during init)
    this.click(function () {
        $(this).updateFeed();
    });
};

然后为updateFeed()执行类似的操作:

jQuery.fn.updateFeed = function () {
    this.data('filter-prop');
    this.data('filter-callback')();
});

并像这样使用它:

$('#filter').initFilter(prop, callback);

请注意,updateFeed可以简单地嵌入到单击处理程序中,以防止对jQuery名称空间造成不必要的污染。但是,使用这样的jQuery的一个优点是,如果需要稍后调用某个函数,则不需要保留对该对象的引用,因为jQuery将所有引用绑定到实际元素。如果您想以编程方式拨打updateFeed,那么:

$('#filter').updateFeed();
然后将在正确的对象上调用


需要考虑的一些事项

这种方法肯定有缺点。一个是我们使用.data()针对元素保存的所有属性在作用于该元素的所有jQuery函数之间共享。我试图通过在属性名称前添加“filter-”来减轻这种情况,但是根据对象的复杂程度,这可能不合适。

此外,这种精确的方法可能不适合需要大量操作的对象(即具有许多功能的对象),因为所有这些函数对所有jQuery对象都是通用的。有一些方法可以封装所有这些,我不会在这里进行,但是jQuery-ui用它们的小部件来做这个,我正在尝试在我正在创建的库中的另一个替代方案。

然而,稍微退一步,我建议首先使用jQuery的唯一原因是你的Filter对象似乎与DOM密切相关。它将事件绑定到DOM,它根据用户交互修改DOM,基本上它似乎存在于DOM中,因此使用基于DOM的东西,即jQuery。