Javascript persistence > logic
Please help me find a solution that uses plain 'ol javascript (I cannot use external frameworks). Also, CSS :hover selector won't work for the real world implementation.
Somethings going on with the registered event sets all calling the last registered events array item.
<body>
<p>When you hover over <div> tags 0-2, that <div> tag should highlight in red. Why do all of the <div> tags o开发者_如何学Gonly affect the last <div>?</p>
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>
<p>The same results for <p> tags.</p>
<p class="test"></p>
<p class="test"></p>
<p class="test"></p>
<script type="text/javascript">
//create arrays
var divArr = new Array();
var pArr = new Array();
//call function to populate arrays
divArr = getElementsByClassName('div','test');
pArr = getElementsByClassName('p','test');
//call function to register arrays elements events
registerArrayElementsEvents(divArr,'div');
registerArrayElementsEvents(pArr,'p');
//retrieve elements that match the passed tag and class
function getElementsByClassName(myTag,myClass) {
//load all elements into array
var elems = document.getElementsByTagName(myTag);
//create new array placeholder
var newArr = new Array();
//iterate through elements array
for (var i = 0; i < elems.length; i++) {
//check to see if element class matches parameter
if (elems[i].className == myClass){
//add matched element to new array
newArr.push(elems[i]);
}
}
//return array of matched elements
return newArr;
}
//register events to every element in the passed array
function registerArrayElementsEvents(arr,type){
//create object placeholder
var currentObj = new Object();
//iterate through the objects array
for (var i = 0; i < arr.length; i++) {
//assign current object corresponding to loop counter
currentObj = arr[i];
//write element index to element
currentObj.innerHTML = 'This is <' + type + '> ' + i;
//add mouseover event to element
addEvent(currentObj,'mouseover',function(){
//set current element color to red
currentObj.style.color = '#f00'
});
//add mouseout event to element
addEvent(currentObj,'mouseout',function(){
//set current element color to black
currentObj.style.color = '#000'
});
}
}
//register functions to events for objects
function addEvent(obj,evt,fn){
//if not IE
if (obj.addEventListener)
obj.addEventListener(evt,fn,false);
//if IE
else if (obj.attachEvent)
obj.attachEvent('on'+evt,fn);
}
</script>
</body>
What's happening is that in currentObj
in registerArrayElementsEvents
is scoped to registerArrayElementsEvents
rather than each event's function. You need to put currentObj
into each function's scope as so:
addEvent(currentObj, 'mouseover', (function (obj) {
return function () {
obj.style.color = '#f00';
};
})(currentObj));
Basically, JavaScript only scopes based on functions, not on blocks. This means that
for (...) { var x = arr[i] }
is exactly the same as:
var x;
for (...) {x = arr[i]}
This means that after the loop is done, x
is set to the last element of the array. If you referenced x
in a function, when it goes to look x
after the loop is done (like after an event) it gets the newest value of x
. To overcome this, you can create a closure each time you loop through by using an anonymous function like I did.
//create arrays var divArr = new Array(); var pArr = new Array(); //call function to populate arrays divArr = getElementsByClassName('div','test'); pArr = getElementsByClassName('p','test');
By assigning new values to divArr
and pArr
you over write the arrays originally assigned. That isn't your issue, it just means the original assignment is useless.
TIkhon has one answer, another way is to avoid the closure with this
:
addEvent(currentObj, 'mouseover', function () {
this.style.color = '#f00';
});
but you will have to modify the addEvent
function for attachEvent
so set this
correctly. I'll add that shortly...
精彩评论