构造DOMTokenList / DOMSettableTokenList实例 [英] Constructing a DOMTokenList/DOMSettableTokenList instance
问题描述
DOMTokenList和DOMSettableTokenList接口( MDN , WHATWG )提供了用于操作由空格分隔的字符串表示的字符串令牌的有序集的方法。它们通常以Element.prototype.classList属性的形式使用,DOMTokenList反映相关元素的类
属性。
var div = document.createElement('div'); div.setAttribute('class','hello world goodnight moon'); var list = div.classList; console。 assert(list.length === 4); console.assert(list [0] ==='hello'); console.assert(list.item(1)==='world'); console.assert(list .contain('moon')=== true); console.assert(list.contains('mars')=== false); list.remove('world','earth','dirt','sand' ); list.add('hello','mars'); list.toggle('goodnight'); console.assert(div.getAttribute('class')==='hello moon mars');
我正在使用自定义元素( HTML5Rocks , W3C Draft ),其中显示了指定Stack Overflow用户的活动的实时提要。该用户列表在 ids
属性中指定,可以随时更新。
< so-users ids =1114 22656 106224>< / so-users>
document.querySelector('所以用户')。setAttribute('ids','23354 115866');
而不是要求用户直接操作这个属性,我想要一个 .ids
属性提供一个可以使用的DOMTokenList。理想情况下,这将直接与属性相关联,但是我必须手动绑定的未绑定的DOMSettableTokenList实例也是可以的。
document.querySelector( '所以用户')ids.add( '17174');
不幸的是,我一直无法找到创建DOMTokenList实例的任何方法。定义不是一个构造函数,当我调用任何关联的方法时,使用它的原型直接创建一个对象会导致错误:
new DOMTokenList; // TypeError:非法构造函数
new DOMSettableTokenList; // TypeError:非法构造函数
var list = Object.create(DOMSettableTokenList.prototype,{
value:{value:'hello world'}
});
console.assert(list instanceof DOMTokenList);
console.assert(list instanceof DOMSettableTokenList);
list.item(0); // TypeError:非法调用
function TokenListConstructor(){
this.value ='hello world';
}
TokenListConstructor.prototype = DOMSettableTokenList.prototype;
var list = new TokenListConstructor;
console.assert(list instanceof DOMTokenList);
console.assert(list instanceof DOMSettableTokenList);
list.add('moon'); // TypeError:非法调用
如何构建一个新的 DOMTokenList
或
DOMSettableTokenList
实例?
一个DOMTokenList或一个DOMSettableTokenList直接。相反,您应该使用class属性来存储和检索您的数据,也可能将DOM元素的ids属性映射到classList属性。
var element = document.querySelector('so-users');
element.ids = element.classList;
您可以根据文档使用relList,但是更多支持classList,唯一的缺点是你可能遇到问题,如果其中一个ids匹配一个类名称,那么设置一个内联样式来隐藏元素以防万一。
对于定制组件的兼容性应该是一个问题classList存在于IE> = 10,Firefox 3.6,Chrome 8,Opera 11.5和Safari 5.1中,请参阅 http:/ /caniuse.com/#feat=classlist ),所以如果兼容性符合您的要求,请使用下面发布的另一个解决方案。
如果不能使用clases或classList和/或必须使用ids属性,您应该根据规范实现一个自定义函数,具有以下属性作为函数。
- item()
- contains()
- add()
- remove()
- toggle()
这是一个示例引用这样的功能。
var TokenList = function(ids){
'use strict'
var idsArray = [],
self = this,
parse = function(id,functionName,cb){
var search = id.toString();
if(search.split('').length> 1){
throw new Error(Failed to execute'+ functionName +'on'TokenList':提供的令牌(' + search +')包含HTML空格字符,这些字符在令牌中无效。););
} else {
cb(search);
}
};
函数triggerAttributeChange(){
if(self.tokenChanged&&&&" self.tokenChanged ==='function'){
self.tokenChanged(idsArray.toString( ));
}
}
if(ids&& typeof ids ==='string'){
idsArray = ids.split('');
}
self.item = function(index){
return idsArray [index];
};
self.contains = function(id){
parse(id,'contains',function(search){
return idsArray.indexOf(search)!== ;
});
};
self.add = function(id){
parse(id,'add',function(search){
if(idsArray.indexOf(search)=== 1){
idsArray.push(search);
}
triggerAttributeChange();
});
};
self.remove = function(id){
parse(id,'remove',function(search){
idsArray = idsArray.filter(function(item){
return item!== id;
});
triggerAttributeChange();
});
};
self.toggle = function(id){
parse(id,'toggle',function(search){
if(!self.contains(search)){
self.add(search);
} else {
self.remove(search);
}
});
};
self.tokenChanged = null;
self.toString = function(){
var tokens ='',
i;
if(idsArray.length> 0){
for(i = 0; i tokens = tokens + idsArray [i] +''
}
tokens = tokens.slice(0,tokens.length - 1);
}
返回令牌;
};
};
使用此函数的新实例在元素中设置ids属性,最后必须绑定对属性的目标属性监听元素的更改并更新属性o反向。你可以用突变观察器来做到这一点。
请参阅在DOM上启动事件属性更改和 https://developer.mozilla.org / en-US / docs / Web / API / MutationObserver
var attachTokenList = function(element,prop,initialValues ){
'use strict';
var initValues = initialValues || element.getAttribute(prop),
MutationObserver = window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
observer,
config,
cancelMutation = false;
函数createTokenList(values){
var tList = new TokenList(values);
tList.tokenChanged = function(){
element.setAttribute(prop,element [prop] .toString());
cancelMutation = true;
};
元素[prop] = tList;
}
createTokenList(initValues);
observer = new MutationObserver(function(mutation){
var i,
mutationrec,
newAttr;
if(mutation.length> 0& ;&!cancelMutation){
for(i = 0; i< mutation.length; i = i + 1){
mutationrec = mutation [i];
if(mutationrec。 attributeName === prop&& element [prop]){
newAttr = element.getAttribute(prop);
createTokenList(newAttr);
}
}
}
cancelMutation = false;
});
config = {
属性:true
};
observer.observe(element,config);
};
测试看是否可行
< so-users ids =1234 5678>< / so-users>
< button onclick =clickButton1()>添加7890< / button>
< button onclick =clickButton2()>设置为3456< / button>
< button onclick =clickButton3()>添加9876< / button>
脚本标签内
var elem = document.querySelector('so-users');
attachTokenList(elem,'ids')
function clickButton1(){
elem.ids.add('7890');
}
function clickButton2(){
elem.setAttribute('ids','3456');
}
功能clickButton3(){
elem.ids.add('9876');
}
按顺序单击按钮将ids属性设置为'3456 9876' p>
The DOMTokenList and DOMSettableTokenList interfaces (MDN, WHATWG) provide methods for manipulating ordered sets of string tokens represented by space-delimited strings. They are most commonly used in the form of the Element.prototype.classList property, a DOMTokenList which reflects the class
attribute of an associated element.
var div = document.createElement('div');
div.setAttribute('class', 'hello world goodnight moon');
var list = div.classList;
console.assert(list.length === 4);
console.assert(list[0] === 'hello');
console.assert(list.item(1) === 'world');
console.assert(list.contains('moon') === true);
console.assert(list.contains('mars') === false);
list.remove('world', 'earth', 'dirt', 'sand');
list.add('hello', 'mars');
list.toggle('goodnight');
console.assert(div.getAttribute('class') === 'hello moon mars');
I'm working on a custom element (HTML5Rocks, W3C Draft) which displays a real-time feed of the activity of specified Stack Overflow users. This list of users is specified in an ids
attribute, and may be updated at any time.
<so-users ids="1114 22656 106224"></so-users>
document.querySelector('so-users').setAttribute('ids', '23354 115866');
Instead of requiring users to manipulate this attribute directly, I would like to have an .ids
property providing a DOMTokenList that they can use instead. Ideally this would be directly associated with the attribute, but an unbound DOMSettableTokenList instance that I have to manually bind would also be fine.
document.querySelector('so-users').ids.add('17174');
Unfortunately, I have been unable to find any way to create a DOMTokenList instance. The definition is not a constructor, and directly creating an object using its prototype results in errors when I call any associated methods:
new DOMTokenList; // TypeError: Illegal constructor
new DOMSettableTokenList; // TypeError: Illegal constructor
var list = Object.create(DOMSettableTokenList.prototype, {
value: { value: 'hello world' }
});
console.assert(list instanceof DOMTokenList);
console.assert(list instanceof DOMSettableTokenList);
list.item(0); // TypeError: Illegal invocation
function TokenListConstructor() {
this.value = 'hello world';
}
TokenListConstructor.prototype = DOMSettableTokenList.prototype;
var list = new TokenListConstructor;
console.assert(list instanceof DOMTokenList);
console.assert(list instanceof DOMSettableTokenList);
list.add('moon'); // TypeError: Illegal invocation
How can I construct a new DOMTokenList
or DOMSettableTokenList
instance?
You cannot create an DOMTokenList or an DOMSettableTokenList directly. Instead you should use the class attribute to store and retrieve your data and perhaps map an ids attribute of your DOM element to the classList property.
var element = document.querySelector('so-users');
element.ids = element.classList;
You can use relList according to the documentation but classList is more supported, the only drawback is that you might run into issues if one of your ids matches a class name so set an inline style to hide the element just in case.
For a custom component compatibility should be a concern (classList is present in IE>=10, Firefox 3.6, Chrome 8, Opera 11.5 and Safari 5.1, see http://caniuse.com/#feat=classlist) so if compatibility is in your requirements use the another solution posted below.
If you cannot use clases or classList and/or must use the ids attribute you should implement a custom function according to the spec with the following properties as functions.
- item()
- contains()
- add()
- remove()
- toggle()
This is an example implementation of such functionality.
var TokenList = function (ids) {
'use strict';
var idsArray = [],
self = this,
parse = function (id, functionName, cb) {
var search = id.toString();
if (search.split(' ').length > 1) {
throw new Error("Failed to execute '" + functionName + "' on 'TokenList': The token provided ('" + search + "') contains HTML space characters, which are not valid in tokens.');");
} else {
cb(search);
}
};
function triggerAttributeChange() {
if (self.tokenChanged && typeof self.tokenChanged === 'function') {
self.tokenChanged(idsArray.toString());
}
}
if (ids && typeof ids === 'string') {
idsArray = ids.split(' ');
}
self.item = function (index) {
return idsArray[index];
};
self.contains = function (id) {
parse(id, 'contains', function (search) {
return idsArray.indexOf(search) !== -1;
});
};
self.add = function (id) {
parse(id, 'add', function (search) {
if (idsArray.indexOf(search) === -1) {
idsArray.push(search);
}
triggerAttributeChange();
});
};
self.remove = function (id) {
parse(id, 'remove', function (search) {
idsArray = idsArray.filter(function (item) {
return item !== id;
});
triggerAttributeChange();
});
};
self.toggle = function (id) {
parse(id, 'toggle', function (search) {
if (!self.contains(search)) {
self.add(search);
} else {
self.remove(search);
}
});
};
self.tokenChanged = null;
self.toString = function () {
var tokens = '',
i;
if (idsArray.length > 0) {
for (i = 0; i < idsArray.length; i = i + 1) {
tokens = tokens + idsArray[i] + ' ';
}
tokens = tokens.slice(0, tokens.length - 1);
}
return tokens;
};
};
Set an 'ids' property in your element with a new instance of this function and finally you must bound the targeted attribute to the property listening to changes to the element and updating the property o viceversa. You can do that with a mutation observer.
See firing event on DOM attribute change and https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
var attachTokenList = function (element, prop, initialValues) {
'use strict';
var initValues = initialValues || element.getAttribute(prop),
MutationObserver = window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
observer,
config,
cancelMutation = false;
function createTokenList(values) {
var tList = new TokenList(values);
tList.tokenChanged = function () {
element.setAttribute(prop, element[prop].toString());
cancelMutation = true;
};
element[prop] = tList;
}
createTokenList(initValues);
observer = new MutationObserver(function (mutation) {
var i,
mutationrec,
newAttr;
if (mutation.length > 0 && !cancelMutation) {
for (i = 0; i < mutation.length; i = i + 1) {
mutationrec = mutation[i];
if (mutationrec.attributeName === prop && element[prop]) {
newAttr = element.getAttribute(prop);
createTokenList(newAttr);
}
}
}
cancelMutation = false;
});
config = {
attributes: true
};
observer.observe(element, config);
};
Testing to see if it works
<so-users ids="1234 5678"></so-users>
<button onclick="clickButton1()">Add 7890</button>
<button onclick="clickButton2()">Set to 3456</button>
<button onclick="clickButton3()">Add 9876</button>
Inside a script tag
var elem = document.querySelector('so-users');
attachTokenList(elem, 'ids')
function clickButton1 () {
elem.ids.add('7890');
}
function clickButton2 () {
elem.setAttribute('ids', '3456');
}
function clickButton3 () {
elem.ids.add('9876');
}
Clicking the buttons in sequence set the ids attribute to '3456 9876'
这篇关于构造DOMTokenList / DOMSettableTokenList实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!