jQuery使用对象作为过滤器

14

有没有办法通过对象使DOM元素可选择?

例如,我想能够将对象与DOM元素关联起来,就像这样:

var obj = { a: 1, b:2 };
$('a').click(function() { this.selectThing = obj });

后来...

$.something(obj);

或者更好的方式:

$('a|selectThing?=', obj);

类似这样。您可以看到我想以这种方式将对象与DOM元素关联起来,以便我可以用对象获取该元素。

我知道可以使用filter()方法来完成此操作,我的问题是是否有一种更优雅的方法,不使用filter()来实现。

编辑:

澄清一下,我希望能够像使用选择器一样使用对象,这样我就可以执行类似于$(obj)的操作,显然这样做行不通,但是你应该明白我的意思(希望如此)

编辑 #2:

我想要执行类似于以下操作:

var obj = { prop: 'prop' };
$('a').bindTo(obj);
$.retreive(obj) // should equal $('a')

然而我不希望它以任何方式修改objobj应该仍然只是{prop:'prop'})。


你能否添加一个使用过滤方法来实现这个的例子吗?否则我不知道你在尝试做什么。 - Esailija
你有没有检查我建议的答案 https://dev59.com/kHE85IYBdhLWcg3wNgrk#2895933? - Meligy
@MohamedMeligy:是的,但再次强调,这并不是在选择器中使用对象,而是选择与DOM元素相关联的数据。 - qwertymk
我想知道为什么“obj”不能被更改。对我来说,创建一个“obj”的原型似乎更有意义,其中包含一个bindTo()函数,该函数接受jQuery对象或CSS选择器。然后在obj或obj.data中存储任何数据,并使用obj.bindTo(...)和$.retrieve(obj),其中retrieve检查“obj”的某个数据成员引用DOM元素。如果您执行$('a').bindTo(obj),那么是否需要另一个对象来关联绑定(因为'obj'不知道其绑定的内容)? $.retieve()会检查什么?它会查找“obj”以查找元素吗?还是会问“obj”? - Kasapo
7个回答

8

demo

var $div1 = $('.box1');
var $div2 = $('.box2');
var obj = { a: $div1, b: $div2 };


obj.a.css({background:'red'});


或者简单的方式:var obj = { a: $('.box1'), b: $('.box2') };


演示 jsBin 2

var obj = $('.box1, .box2'); // store objects
obj.css({background:'red'}); // access collection

@tobyodavies:我正在寻找一种使用对象获取元素的方法,而不是将元素保存在对象上。我的需求类似于拥有一个可以是对象的选择器。 - qwertymk
这个解决方案难道不就是这样吗?该对象并没有真正地在自身内部“保存”元素,而是包含了两个引用DOM元素的jQuery对象。如果你想要使用$(obj),那么obj必须是一个带有jQuery选择器的字符串。我猜“obj”对象的本质是什么?你可以重写对象的“toString”函数来打印出一个选择器...我仍然不确定你想做什么。也许需要稍微详细一些的说明? - Kasapo
@Kasapo:请看问题的编辑,我不需要将一个对象传递到主jQuery函数中,这是你假设的。我想要像实用函数一样,根据匹配DOM对象来检索一些元素。想象一下我做了这样的事情 var obj {}; $('a').bindTo(obj); 我希望能够通过这样的方式获取 a$.retreive(obj); 但我不希望在此过程中改变 obj - qwertymk

2
您需要使用$.data方法。这个方法可以将任何JavaScript对象或原始值与DOM元素关联起来。在幕后,它不会将数据作为扩展添加到DOM元素中,而是jQuery维护其自己的DOM元素和数据哈希的对象缓存。但这是在幕后的事情;重要的是,我认为这正是您所需要的。
$('#example').data('foo', { bar: 'quux' }); // returns the jquery object containing '#example', like most jQuery methods

然后,稍后:
console.log($('#example').data('foo')); // returns {bar: 'quux'}

2
这并没有回答问题。 - qwertymk

2
我不认为这是容易实现的。让我澄清一下:
要实现你想要的功能,你需要一个允许对象作为键的哈希表。然而,JavaScript目前还不支持将对象作为哈希表的键。因此,例如以下代码是无法工作的:
var key = {value: 'key'};
var data {value: 'data'};
var map = {};

map[key] = data;

在当前的JavaScript实现中,有其他解决方案可以实现这一点,例如双重查找:

var key = {value: 'key'};
var data {value: 'data'};
var map = { keys: [], data: [], get: function (key) {
  var k = this.keys.indexOf(key);
  if (k >= 0) {
    return this.data[k];
  } else return undefined;
}, set: function (key, val) {
  var k = this.keys.indexOf(key);
  if (k < 0) {
    k = this.keys.push(k) - 1;
  }
  this.data[k] = val;
} };

map.set(key, data);
map.get(key).value;

然而,此实现性能极差。在JavaScript Harmony中有一个所谓的WeakMap建议。我相信Firefox目前是唯一实现它们的浏览器。由于所需功能不广泛可用且解决方法性能较差,我建议尝试找到其他实现目标的方式。


1

据我所知,您正在寻找一种简单的方法来在DOM上运行多个命名搜索,并将结果过滤到命名空间对象中。

如果是这样,我想下面的jQuery扩展可能对您有帮助:

$.fn.seek = function (selectors) {
  var container = this,
    found = {};

  $.each(selectors, function (name) {
    if ($.isPlainObject(selectors[name])) {
      found[name] = $(container).seek(selectors[name]);
    }
    else if ($.type(selectors[name]) === 'string') {
      found[name] = $(container).find(selectors[name]);
    }
  });

  return found;
}

下面是一个示例,说明上述扩展如何适用于您的情况:

var res = $('body').seek({
  links: 'a',
  headers: 'h1,h2,h3,h4,h5,h6'
});

$(res.links).css({ color: 'green' });
$(res.headers).css({ color: 'red' });

希望这能对您有所帮助。


1

不确定这是否符合您的要求。也许您可以基于jQuery选择器编写自定义选择器,以您喜欢的方式处理具有选择器属性的对象。可选择的对象将如下所示:

var objSelector = {'selector' : '#select-me', 'a' : 'somestring', 'b' : 1243}; 

所以您可以像使用任何其他对象一样自由地使用它,但是您必须添加选择器属性。然后您可以添加您的自定义选择器:

$$ = (function($) {
    return function(el, tag) {
        if (typeof el === 'object' && el.selector !== undefined) {
            return $(el.selector);                  
        }
        return $(el);
    }
}($));

现在你可以做这样的事情

$$(objSelector).css({'border':'1px solid red'});

请查看http://jsfiddle.net/JXcnJ/上的实现。


1
如果我理解正确的话,您需要定义一个属性并将其设置为enumerable为false。请参见以下内容,
注意:以下仅是示例,仅用于演示,并不是确切的操作。

DEMO

$(function() {

    $.fn.bindTo = function(o) {
        var _that = this;

        Object.defineProperty(o, 'myFx', {
            value: function() { return $(_that); },
            writable: true,
            enumerable: false,
            configurable: true
        });
    }

    $.retrieve = function(obj) {
        return obj.myFx();
    }

    var obj = {
        prop: 'prop'
    };

    $('#test').bindTo(obj);

    $($.retrieve(obj)).html('Test');

   //below is for proof
    for (i in obj) {
        alert(obj[i]);
    }
});

参考:http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/


1

使用三种方法扩展jQuery:

jQuery.bindObj(data)
jQuery.unbindObj(data)
$.retrieve(data)

您的代码看起来像:

$('a').bindObj({blorg: 'shmorg'});
console.log($.retrieve({blorg: 'shmorg'})); // logs live result of $('a');

完整源代码:http://jsfiddle.net/nUUSV/6/
这个解决方案的诀窍是将基于jQuery构造函数的选择器/标识符存储在一个数组中,将绑定到这些选择器/标识符的对象存储在另一个数组中,然后使用$.inArray来获取对象的索引以便检索,并使用该索引来获取绑定的jQuery集合。

请注意,这种方法的性能明显比简单的哈希查找要差。 - Daniel Baulig

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