我想寫一些純JavaScript,以便更好地理解它(我知道在這框架,比如jQuery的「真正實踐」是更建議和適用的,但這不是真正關於如何使用框架,更多關於純JavaScript如何工作和最佳實踐)。如何編寫圍繞DOM存儲數據(對象,自定義屬性)節點
反正我寫了一些簡單的javascript代碼。我想創建一組按鈕,每次只有一個狀態從set {on,off}開始,每個狀態都會映射到相應的函數,在進入該狀態時被觸發。主組中的每組按鈕一次只能包含一個處於打開狀態的按鈕。這個概念與單選按鈕的概念相似。 爲什麼不使用單選按鈕呢?在語義上,它只是假設是某些控件元素的按鈕,但是我想我可以擁有任何一種方式,但問題並不在於此。
問題是,爲了解決這個問題,我在我的Javascript中通過id
向特定的button
元素添加了很多自定義屬性。我正在做一些研究,發現這個question和question,關於在DOM節點(對象)上使用自定義屬性。他們似乎主張反對這種做法,甚至可以說這樣做可能導致潛在的內存泄漏,這取決於瀏覽器的實現。
然而,對於每個按鈕創建我需要保持大量的屬性的跟蹤,如果我擴大這個劇本我可能會更增加。那麼將它們存儲在DOM節點上的最好方法是什麼,但是仍然保持跟蹤所有內容,並且能夠在附加函數中使用等。
這是不容易明顯,我如何做到這一點而不在最小存儲井名隔開對象到DOM節點button
元素的引用。
我可以看到,從這個question jQuery有一些方法可以做到這一點,但我想知道這只是純粹的JavaScript如何完成。
下面是完整的示例代碼,我有工作:
<!DOCTYPE html>
<html>
<head>
<title>Button Test Script</title>
<script language="javascript" type="text/javascript">
window.button_groups = {};
function isset(type) {
return !(type==='undefined');
}
function debug(txt) {
if(!isset(typeof console)) {
alert(txt);
} else {
console.log(txt);
}
}
function img(src) {
var t = new Image();
t.src = src;
return t;
}
function turnGroupOff(group) {
if(isset(typeof window.button_groups[group])) {
for(var i = 0; i < window.button_groups[group].length; i++) {
if(window.button_groups[group][i].toggle == 1)
window.button_groups[group][i].click();
}
}
}
/**
* buttonId = id attribute of <button>
* offImg = src of img for off state of button
* onImg = src of img for on state of button
* on = function to be fired when button enters on state
* off = function to be fired when button enters off state
*/
function newButton(buttonId, offImg, onImg, group, on, off) {
var b = document.getElementById(buttonId);
b.offImg = img(offImg);
b.onImg = img(onImg);
b.on = on;
b.off = off;
b.img = document.createElement('img');
b.appendChild(b.img);
b.img.src = b.offImg.src;
b.group = group;
b.toggle = 0;
b.onclick = function() {
switch(this.toggle) {
case 0:
turnGroupOff(this.group);
this.on();
this.toggle = 1;
this.img.src = this.onImg.src;
break;
case 1:
this.off();
this.toggle = 0;
this.img.src = this.offImg.src;
break;
}
}
if(!isset(typeof window.button_groups[group]))
window.button_groups[group] = [];
window.button_groups[group].push(b);
}
function init() {
var on = function() { debug(this.id + " turned on") };
newButton('button1', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group1',
on,
function() { debug(this.id + " turned off"); }
);
newButton('button2', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group1',
on,
function() { debug(this.id + " turned off (diff then usual turn off)"); }
);
newButton('button3', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group2',
on,
function() { debug(this.id + " turned off (diff then usual turn off2)"); }
);
newButton('button4', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group2',
on,
function() { debug(this.id + " turned off (diff then usual turn off3)"); }
);
}
window.onload = init;
</script>
</head>
<body>
<button id="button1" type="button"></button>
<button id="button2" type="button"></button>
<br/>
<button id="button3" type="button"></button>
<button id="button4" type="button"></button>
</body>
</html>
UPDATE
jQuery的事情是,我的目的有點大材小用。我不需要擴展任意元素。我對jQuery的具體做法有個很好的想法(隨機命名的屬性存儲緩存索引整數)。
我事先知道哪些主機元素需要擴展,以及如何;我也可以/想在HTML端設置一個id
屬性。
所以,通過了jQuery設置的啓發,我決定也創建一個全局緩存變量,除了我將使用DOM節點的id屬性爲我的緩存鍵。由於它應該是一個唯一的標識符(根據定義),並且我沒有計劃動態改變ID的有史以來,這應該是一個簡單的任務。它將我的Javascript對象從DOM對象中徹底分離出來,但它確實使我的代碼看起來更加醜陋,並且很難通過對data
的多次調用來閱讀。我提出以下修改:
<!DOCTYPE html>
<html>
<head>
<title>Button Test Script</title>
<script language="javascript" type="text/javascript">
window.button_groups = {};
function isset(type) { // For browsers that throw errors for !object syntax
return !(type==='undefined');
}
var c = { // For browsers without console support
log: function(o) {
if(isset(typeof console)) {
console.log(o);
} else {
alert(o);
}
},
dir: function(o) {
if(isset(typeof console)) {
console.dir(o);
}
}
};
function img(src) { // To avoid repeats of setting new Image src
var t = new Image();
t.src = src;
return t;
}
var cache = {};
function data(elemId, key, data) { // retrieve/set data tied to element id
if(isset(typeof data)) {// setting data
if(!isset(typeof cache[elemId]))
cache[elemId] = {};
cache[elemId][key] = data;
} else { // retreiving data
return cache[elemId][key];
}
}
var button_groups = {}; // set of groups of buttons
function turnGroupOff(group) { // turn off all buttons within a group
if(isset(typeof window.button_groups[group])) {
for(var i = 0; i < window.button_groups[group].length; i++) {
if(data(window.button_groups[group][i].id, 'toggle') == 1)
window.button_groups[group][i].click();
}
}
}
/**
* buttonId = id attribute of <button>
* offImg = src of img for off state of button
* onImg = src of img for on state of button
* on = function to be fired when button enters on state
* off = function to be fired when button enters off state
*/
function newButton(buttonId, offImg, onImg, group, on, off) {
var b = document.getElementById(buttonId);
data(b.id, 'offImg', img(offImg));
data(b.id, 'onImg', img(onImg));
data(b.id, 'on', on);
data(b.id, 'off', off);
var btnImg = document.createElement('img');
btnImg.src = data(b.id, 'offImg').src;
data(b.id, 'img', btnImg );
b.appendChild(btnImg);
data(b.id, 'group', group);
data(b.id, 'toggle', 0);
var click = function() {
switch(data(this.id,'toggle')) {
case 0:
turnGroupOff(data(this.id,'group'));
(data(this.id,'on'))();
data(this.id,'toggle',1);
data(this.id,'img').src = data(this.id,'onImg').src;
break;
case 1:
(data(this.id,'off'))();
data(this.id,'toggle',0);
data(this.id,'img').src = data(this.id,'offImg').src;
break;
}
}
b.onclick = click;
if(!isset(typeof window.button_groups[group]))
window.button_groups[group] = [];
window.button_groups[group].push(b);
}
function init() {
var on = function() { c.log(this.id + " turned on") };
newButton('button1', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group1',
on,
function() { c.log(this.id + " turned off"); }
);
newButton('button2', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group1',
on,
function() { c.log(this.id + " turned off (diff then usual turn off)"); }
);
newButton('button3', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group2',
on,
function() { c.log(this.id + " turned off (diff then usual turn off2)"); }
);
newButton('button4', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group2',
on,
function() { c.log(this.id + " turned off (diff then usual turn off3)"); }
);
}
window.onload = init;
</script>
</head>
<body>
<button id="button1" type="button"></button>
<button id="button2" type="button"></button>
<br/>
<button id="button3" type="button"></button>
<button id="button4" type="button"></button>
</body>
</html>
UPDATE 2
我發現,通過使用閉合的功率I真正只需要存儲一個「特殊」屬性,即該組的按鈕曾經屬於。
我改變了newButton
功能;下面,通過關閉,消除了需要存儲很多其他的事情我是:
function newButton(buttonId, offImg, onImg, group, on, off) {
var b = document.getElementById(buttonId);
offImg = img(offImg);
onImg = img(onImg);
var btnImg = document.createElement('img');
btnImg.src = offImg.src;
b.appendChild(btnImg);
data(b.id, 'group', group);
var toggle = 0;
var click = function(event) {
switch(toggle) {
case 0:
turnGroupOff(data(this.id,'group'));
if(on(event)) {
toggle = 1;
btnImg.src = onImg.src;
}
break;
case 1:
if(off(event)) {
toggle = 0;
btnImg.src = offImg.src;
}
break;
}
}
b.onclick = click;
if(!isset(typeof window.button_groups[group]))
window.button_groups[group] = [];
window.button_groups[group].push(b);
b = null;
}
jQuery在JavaScript中是_written_。看看[他們是怎麼做的](https://github.com/jquery/jquery/blob/master/src/data.js),特別是看看'data()'函數。 – voithos 2012-03-16 16:41:21