【问题标题】:How to convert jQuery .data() to Vanilla JS?如何将 jQuery .data() 转换为 Vanilla JS?
【发布时间】:2017-08-08 20:16:24
【问题描述】:

在将我现有的一些项目从 jQuery 转换为纯 JS 时,我遇到了 jQuery 的 .data() 实用程序的一些问题。到目前为止,我还没有找到一种简单的 JS 方法,可以让我获取和检查 navGlobal 对象中的所有数据属性。

var navGlobal = document.querySelector('.nav-global');

if (navGlobal !== null &&
    navGlobal.data() &&
    navGlobal.data().account &&
    navGlobal.data().account.accountData &&
    navGlobal.data().account.accountData.address &&
    navGlobal.data().account.accountData.address.zip) {

    // do something

}

我的尝试

最初,我想我会使用 .getAttribute() 和 .hasAttribute() 检查这些数据属性是否存在。但这只会增加混乱 - 我不确定我将如何使用 vanilla JS 深入到嵌套属性(即 navGlobal.data().account.accountData.address)。 链接 .getAttribute() 并没有真正起作用,因为这些数据属性中的大多数都附加到 navGlobal 的子元素,而不是 navGlobal 元素本身

最好的方法是什么?

【问题讨论】:

  • 我同意问题相似,但回答者给出的示例是人为的,也没有解决存在嵌套属性的场景。
  • 在 SO 上搜索,您会发现更多相同的问题,看看它们是否适用。
  • 您发现$().data() 不仅检索data-attributes,而且从不设置它。相反,它会构建一个字典并使用您调用的 jquery 元素 data() 来存储传递的值。这允许存储任何类型的值,而数据属性只能存储 DOMStrings(因此没有对象)。要自己实现它,您必须创建自己的地图。或者如果你很懒,你也可以简单地将这些值附加到一些任意的 DOMElement 自定义属性(例如elem._myOwn_data.account = {acccountData: { address: { zip: 'someVal' } } })。

标签: javascript jquery custom-data-attribute


【解决方案1】:

jQuery 的数据函数做了两件截然不同的事情:它提供了一个访问数据属性的接口,它提供了一个在页面加载后将数据与 DOM 节点关联的接口。关于前一个用例:

递归收集数据属性看起来像这样。

var navGlobal = document.getElementsByClassName('nav-global')[0];
var data = Object.assign({}, navGlobal.dataset);
var children = navGlobal.getElementsByTagName("*");

Array.from(children).forEach(function (el) {
  Object.assign(data, el.dataset)
})

console.log(data)
<div class="nav-global" data-foo="bar">
  <div data-bar="baz">
    <div data-baz="quux"></div>
  </div>
</div>

如果不查看更多代码,无法更具体,但我建议使用更好的方法来选择包含类名等数据的元素。

如果您需要嵌套数据结构,并且需要将它们实现为数据属性,则必须做一些额外的工作才能实现。

如果您查看我的old jQuery plugin 的源代码,您会看到一种简单的方法,即采用平面数据结构并将其转换为嵌套数据结构,反之亦然。这大致类似于 PHP 和 Ruby 如何在查询字符串中编码嵌套参数。

{
  "account[accountData][address][zip]": "12345"
}

变成

{
  "account": {
    "accountData": {
      "address": {
        "zip": "1234"
      }
    }
  }
}

我的库旨在用于表单输入,但您可以将相同的原则应用于数据属性。

坦率地说,我不明白您为什么不直接在页面上放置 JSON 有效负载。

【讨论】:

  • HTMLElement.dataset 返回一个 DOMStrings 的映射,根据他们的代码,他们想要存储 Objects,这是通过 dataset 无法实现的。
  • @Kaiido 确实如此,尽管可以以类似于嵌套查询参数的方式支持嵌套结构。我已经更新了更多信息。
  • 你的 lib 比 window.JSON API 有什么优势?您不是在存储对象,而是对这些对象进行字符串化。您将如何存储活动节点?
  • 好吧,就像我在编辑中说的那样,我认为在页面上放置一个 JSON 有效负载是这里最简单的解决方案。我的 lib 的目的是采用 HTML 表单并将其转换为 JavaScript 中的嵌套对象,与在后端解析它的方式一致。有点像数据绑定解决方案的一半。
  • 我正在阅读的问题是关于 1. 将嵌套数据结构编码为数据属性,以及 2. 从父节点和所有子节点中提取数据。我认为这些数据不需要是可变的。
【解决方案2】:

正如安东尼所说,使用DOMElement.dataset 对象:

var div = document.querySelector('div');
var p = document.querySelector('p');

p.innerHTML = div.dataset.myattribute;
<div data-myattribute="3"></div>
<p></p><!-- Output element -->

【讨论】:

    【解决方案3】:

    尝试使用navGlobal.dataset 而不是navGlobal.data()

    此外,如果您想检查嵌套属性是否存在,您可以使用lodash has 函数来检查嵌套属性。例如

    if (has(navGlobal.dataset, 'account.accountData.address.zip')) {
      ....
    }
    

    【讨论】:

    • 谢谢。如果可以选择使用 Lodash,这将是理想的解决方案。没有它,.dataset 不会像 .data() 那样返回子元素的数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-24
    • 2016-10-30
    • 1970-01-01
    • 2020-07-21
    • 2020-07-12
    • 2021-03-11
    • 2021-12-11
    相关资源
    最近更新 更多