视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
利用原生JS实现data方法示例代码
2020-11-27 21:56:08 责编:小采
文档


前言

在开发中经常会在DOM上存储一些自定义数据,我们可以通过setAttribute方法来实现。但是当数据为引用类型时,存储后的数据却无效。这里将用原生的JS对data方法进行实现。

使用setAttribute:

<div id="test-data"></div>
<p class="test-data-list"></p>
<p class="test-data-list"></p>
<p class="test-data-list"></p>
<p class="test-data-list"></p>
var testData = document.querySeletor('#test-data');
testData.setAttribute('baukh', {a:1,b:2})// 执行后DOM节点变化为<div baukh="[object Object]"></div>
testData.getAttribute('baukh'); // => "[object Object]"

可以从上面的代码中看出,存进去的是个Object,取出来的是Object.toString()所产出的字符串。

分析

在JS经典类库-jQuery中存在data方法是通过jQuery.cache的方式进行数据存储,那么还有没有其它方法可以实现?

由于使用场景不同,我想实现的方式是将数据直接存储到DOM节点上,以达到使用时更方便简捷的目的。

那如何存储? 变量testData存储的是通过document.querySeletor('#test-data')获取到的Element,而Element是Object的一个实例。通过[testData instanceof Object]可以进行验证。

那么一切都简易了,即然是Object类型,那么就可以随意的增删自定义属性。

通过在Element的原型上增加data方法来实现DOM扩展

Element.prototype.data = function(key, value){
 var _this = this,
 _dataName = 'testData', // 存储至DOM上的对象标记, 这里只是测试用名
 _data = {};
 // 未指定参数,返回全部
 if(typeof key === 'undefined' && typeof value === 'undefined'){
 return _this[_dataName];
 }
 // setter
 if(typeof(value) !== 'undefined'){
 // 存储值类型为字符或数字时, 使用attr执行
 var _type = typeof(value);
 if(_type === 'string' || _type === 'number'){
 _this.setAttribute(key, value);
 }
 _data = _this[_dataName] || {};
 _data[key] = value;
 _this[_dataName] = _data;
 return this;
 }
 // getter
 else{
 _data = _this[_dataName] || {};
 return _data[key] || _this.getAttribute(key);
 }
};

这里来试一下:

var testData = document.querySelector('#test-data');
// 字符串类型测试
testData.data('name', 'baukh');
console.log(testData.data('name')); // => 'baukh'
// 对象类型测试
testData.data('info', {'name': 'baukh', 'age': 27});
console.log(testData.data('info')); // => Object {name: "baukh", age: 27}

解决NodeList存储

现在还有一个问题, 通过Element.prototype绑定的方法只支持Element类生效,而对NodeList类并无效果.

可以通过下面这些代码进行效果测试:

var testDataList = document.querySelectorAll('.test-data-list'); // 获取的为NodeList 而非 Element
testDataList.data('name', 'baukh'); // Uncaught TypeError: testDataList.data is not a function

这肯定不是想要的结果, 那么NodeList类就需要如下处理:

NodeList.prototype.data = function (key, value) {
 // setter
 if(typeof(value) !== 'undefined'){
 [].forEach.call(this, function (element, index) {
 element.data(key, value);
 });
 return this;
 }
 // getter
 else{
 return this[0].data(key, value); // getter 将返回第一个
 }
};

来测试下NodeList类的data实现:

var testDataList = document.querySelectorAll('.test-data-list'); // 获取的为NodeList 而非 Element
testDataList.data('name', 'baukh'); // Uncaught TypeError: testDataList.data is not a function
// 字符串类型测试
testDataList.data('name', 'baukh');
console.log(testDataList.data('name')); // => 'baukh'
// 对象类型测试
testDataList.data('info', {'name': 'baukh', 'age': 27});
console.log(testDataList.data('info')); // => Object {name: "baukh", age: 27}

这样就功能上就完成了.

当然也可以将NodeList与Element进行互换, 具体情况具体考虑.

很简单不是吗?

顺带说一下,Array类型的数据,也可以增加自定义属性。

var ar = [1,2,3];
console.log(ar instanceof Object); //true 能添加自定义属性的原因就在这里,Array也是Object的实例。
ar.test1 = {a:1,b:2};
console.log(ar); //[1, 2, 3, test1: Object]
console.log(ar.test1); //Object {a: 1, b: 2}

随笔一行

这是前端最好的时代, 这也是前端最坏的时代。 众多前端框架满天飞,随着 jQuery 在前端行业的慢慢弱化,总是会有一种斯人远去,何者慰籍的感觉。互勉吧,各位。

另推荐个表格组件gridManager

总结

下载本文
显示全文
专题