【问题标题】:jQuery .data() does not work, but .attr() doesjQuery .data() 不起作用,但 .attr() 可以
【发布时间】:2012-02-01 04:41:00
【问题描述】:

请原谅我没有更具体地说明这一点。我有这样一个奇怪的错误。加载文档后,我循环了一些最初具有data-itemname="" 的元素,并使用.attr("data-itemname", "someValue") 设置这些值。

问题:当我稍后循环遍历这些元素时,如果我执行elem.data().itemname,我会得到"",但如果我执行elem.attr("data-itemname"),我会得到"someValue"。就像 jQuery 的 .data() getter 只获取最初设置为包含某个值的元素,但如果它们最初为空,然后设置,则 .data() 稍后不会获取该值。

我一直在尝试重新创建此错误,但未能成功。

编辑

我已经重新创建了这个错误! http://jsbin.com/ihuhep/edit#javascript,html,live

另外,上面链接的sn-ps...

JS:

var theaters = [
    { name: "theater A", theaterId: 5 },
    { name: "theater B", theaterId: 17 }
];

$("#theaters").html(
    $("#theaterTmpl").render(theaters)
);

// DOES NOT WORK - .data("name", "val") does NOT set the val
var theaterA = $("[data-theaterid='5']");
theaterA.find(".someLink").data("tofilllater", "theater5link"); // this does NOT set data-tofilllater
$(".someLink[data-tofilllater='theater5link']").html("changed link text"); // never gets changed

// WORKS - .attr("data-name", "val") DOES set val
var theaterB = $("[data-theaterid='17']");
theaterB.find(".someLink").attr("data-tofilllater", "theater17link"); // this does set data-tofilllater
$(".someLink[data-tofilllater='theater17link']").html("changed link text");

HTML:

<body>
    <div id="theaters"></div>
</body>

<script id="theaterTmpl" type="text/x-jquery-tmpl">
    <div class="theater" data-theaterid="{{=theaterId}}">
        <h2>{{=name}}</h2>
        <a href="#" class="someLink" data-tofilllater="">need to change this text</a>
    </div>
</script>

【问题讨论】:

  • 努力重现错误:-)
  • 不是elem.data("itemname")不是elem.data().itemname吗?
  • 虽然 elem.data().itemname 会让您读取值,但不会让您设置值。 (因此elem.data().itemname = somevalue; 不会更改基础数据。)
  • @dkamins - 我已经重新创建了错误,请查看编辑后的版本。

标签: jquery


【解决方案1】:

几天前,我在使用.data().attr('data-name') 处理HTML5 数据属性时遇到了类似的“错误”。

您描述的行为不是错误,而是设计使然。

.data() 调用很特殊 - 它不仅检索 HTML5 数据属性,还尝试评估/解析属性。因此,使用data-myjson='{"hello":"world"}' 之类的属性,当通过.data() 检索时将返回Object,而通过.attr() 检索将返回一个字符串。 See jsfiddle example.

由于.data() 做了额外的处理,jQuery 将属性评估的结果存储在$.cache 中——毕竟,一旦数据属性被评估,每次.data() 调用都重新评估是浪费的——尤其是因为数据变量可以包含复杂的 JSON 字符串。

我说了这么多是为了说以下内容:通过.data() 检索属性后,.attr('data-myvar', '') 所做的任何更改都不会被后续的.data() 调用看到。 Test this out on jsfiddle. p>

为了避免这个问题不要混用 .data.attr() 调用。使用一个或另一个。

【讨论】:

  • 将此标记为答案。请参阅此测试以了解 .data() 与 .attr() 的所有可能场景,其中包括使用每个获取和设置,以及在设置选择器后输出选择器的长度,jsbin.com/acegef/edit#javascript,html,live
  • 至少这解释了明显不直观的行为......虽然这可能会在使用 3rd 方库时引起一些较小的头痛,其中一些仅使用 data(),而其他库则更改实际属性.
  • @leepowers, "通过 .data() 检索属性后 .attr('data-myvar', '') 所做的任何更改都不会被后续的 .data() 调用看到",如果那真的是因为缓存($.cache),那么它似乎不好!与其盲目依赖缓存,后续的 .data() 调用可以做一些基本的检查(),比如现在值是否为空或字符串长度是否改变(将缓存与当前值匹配)
  • 需要注意的是,如果之前没有检索到该值,尝试设置 data('id', val) 也会失败...... Jquery 对 data() 函数的出色设计。
  • 所以,是 data() 缓存让我呆了几个小时。难怪无论我如何改变它的值,它仍然返回相同的值。谢谢你。
【解决方案2】:

这是误解的结果:data 不是data-* 属性的访问器。既多又少。

data 是元素上 jQuery 数据缓存的访问器。该缓存是从data-* 属性初始化,如果有的话,但是data 永远不会写入 到属性,在初始化后更改属性也不会改变数据缓存:

const div = $("[data-example]");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
console.log('Using div.data("example", "updated")');
div.data("example", "updated");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
<div data-example="initial value"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

data 还以各种方式对它找到的内容进行按摩,猜测数据类型,将 data("answer") 放在带有 data-answer="42" 的元素上,而不是字符串,或者如果它们看起来像 JSON,甚至将其解析为 JSON:

console.log(typeof $("[data-answer]").data("answer"));
console.log(typeof $("[data-json]").data("json"));
console.log(typeof $("[data-str]").data("str"));
<div data-answer="42"></div>
<div data-json='{"answer":42}'></div>
<div data-str="example"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

如果您想使用属性(读取和设置属性),请使用attr,而不是dataattr 属性访问器。

【讨论】:

    【解决方案3】:

    .attr("data-itemname", "someValue") 修改 DOM。

    .data("itemname", "someValue") 修改 jQuery 缓存。

    要使其在以下 Javascript 和 CSS 中正常工作,您必须同时设置两者。

    theaterA.find(".someLink").attr("data-itemname", "someValue");
    theaterA.find(".someLink").data("itemname", "someValue");
    

    【讨论】:

      【解决方案4】:

      这是因为属性的名称是data-itemname。您不能在简写 obj.attribute 表示法中使用 -(obj.data-itemname 将被解释为“obj.data 减去 itemname”)。

      【讨论】:

      • 说谁?能给个链接吗?
      【解决方案5】:

      你为什么不到处使用.data()

      您还可以在 HTML 中内联声明默认值,这也很好。

      <span data-code="pony">text</span>
      

      $("span").data("code") == "pony" // true
      

      如果你想改变它,你就去做

      $("span").data("code", "not-a-pony");
      

      要完全删除它,您可以调用

      $("span").removeData("code");
      

      你真的应该尽量避免使用.attr("data-*"),我不知道你为什么要这样做。

      【讨论】:

      • s/should/must,使用 .attr('data-*', ...) 不会使数据对 .data() 可见
      • 但是使用 attr() 不是像 没有 jQuery 那样做吗? (与 getAttribute 寿)
      • 如果你没有 jQuery,你可以使用 getAttribute()setAttribute() - 所以这两种方法都会访问实际的属性并且它会再次工作。或者您只需使用现代浏览器提供的 dataSet 属性。
      • 不要选择这样的元素。这是非常低效的,因为它必须遍历文档中的 每一个 元素。请改用class,因为浏览器具有本地函数来获取具有特定类的元素。
      • 但是,“555”是数据,所以我应该使用 data() 逻辑。将该数据放在类名中是将数据与表示混合。我想这样做的方式不同。
      【解决方案6】:

      您必须使用.data('itemname', 'someValue'); 设置数据。使用.attr()设置数据属性不起作用:http://jsfiddle.net/ThiefMaster/YHsKx/

      但是,您可以通过使用例如提供内联值&lt;div data-key="value"&gt; 在标记中。

      【讨论】:

      • 在 jsfiddle 中,get 工作在你完成这两个集合之后。所以,做 attr("data-itemname", "value") 确实有效。我正在使用 Chrome。
      • @Ian 呃,不。 .data() 调用设置属性,而.attr() 调用什么也不做。
      • @IanDavis:点击“set attr”,“get”会给你一个空对象。只有“设置数据”有效。
      • @Nico - 这正是我所做的:(1)单击“设置属性”按钮,然后(2)单击“获取”按钮。这就是发生的事情:它提醒我,“{“test”:“meow”}”。所以, .attr() 设置属性。否则,警报将为空。如果您遵循这些确切的步骤,您会得到不同的结果吗?谢谢。
      • @ThiefMaster - 在我提供的代码中的剧院A 中,我根本没有使用.attr(),只使用.data(),并且选择器的长度$(".someLink[data-tofilllater='theater5link']") 为零。所以就像我必须使用.attr() :/
      【解决方案7】:

      我可以看到这对如何处理数据属性设置产生了一些分歧。

      我也遇到了这个问题,发现问题似乎只是数据属性名称格式

      根据我的经验,您应该避免在数据变量(“data-”之后的变量名)中使用连字符。

      这对我不起作用:

      [标记]

      <div class="list" id="myElement1" data-item-order="some-value"> .... </div>
      

      [jQuery]

      jQuery("#myElement1").data("item-order", "my-new-value");
      

      但以下工作正常! :) :

      (我在需要时使用下划线而不是连字符)

      [标记]

      <div class="list" id="myElement1" data-item_order="some-value"> .... </div>
      

      [jQuery]

      jQuery("#myElement1").data("item_order", "my-new-value");
      

      我希望它有所帮助。 祝大家好运!

      【讨论】:

        猜你喜欢
        • 2016-11-02
        • 2012-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        相关资源
        最近更新 更多