在跨度上添加“onmouseover”事件时遇到问题

时间:2016-11-27 03:00:18

标签: javascript closures

有人能告诉我我做错了什么吗?我花了整整一天来排除故障,但我无处可去......我想将事件“onmouseover”添加到我的span元素中。但是当我实现下面的代码时,没有任何反应。我做了一些谷歌搜索,我认为这可能是一个变量范围的问题?我不太确定......感谢任何帮助!

<!DOCTYPE html>
<html>
    <head>
        <title>Fixing bugs in JS</title>
        <script src="question1.js" type="text/javascript"></script>
    <head>
    <body>
        <div id="output"></div>
    </body>
<html>

var NUMBERS = 100;

function go() 
{
  var out = document.getElementById("output");
  for (var i = 1; i < NUMBERS+1; i++) {
    var span_one = document.createElement("span");
      span_one.id = "span" + i;
      span_one.innerHTML = "" + i;
      out.appendChild(span_one);

    if (isPrime(i) === true) { // where i is a prime number (3, 5, 7..etc)
      span_one.style.backgroundColor = "red";
      span_one.onmouseover = function() {
        hover("span"+i, "yellow", "150%")
      };
      span_one.onmouseout = function() { 
        hover("span"+i, "red", "100%") // whatever color in this line always overrides previous set color...
      };
}

function hover(id, color, size) {
    var span = document.getElementById(id);
    span.style.backgroundColor = color;
    span.style.fontSize = size;
}


function etc() {
    ...
}

window.onload=go;

4 个答案:

答案 0 :(得分:1)

实际上没有必要(a)给元素一个id(b)来使用i计数器来创建它们以外的任何东西。 这是另一种选择。

function newEl(tag){return document.createElement(tag)}
function byId(id){return document.getElementById(id)}

window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt)
{
	var i, n = 100;
	var outputContainer = byId('output');
	
	for (i=1; i<=n; i++)
	{
		var span = newEl('span');
		//span.id = 'span_' + i;
		span.textContent = i;
		outputContainer.appendChild(span);
		
		if ( i%2 == 1)	//	isOdd
		{
			span.addEventListener('mouseover', onSpanMouseOver, false);
			span.addEventListener('mouseout', onSpanMouseOut, false);
		}
	}
}

function onSpanMouseOver(evt)
{
	this.style.backgroundColor = 'yellow';
	this.style.fontSize = '150%';
}
function onSpanMouseOut(evt)
{
	this.style.backgroundColor = 'red';
	this.style.fontSize = '100%';
}
<div id='output'></div>

答案 1 :(得分:0)

这是一个有效的例子:

http://jsbin.com/zixeno/edit?js,console,output

问题正是enhzflep所说的。一种解决方案是将“addSpan”逻辑移出for循环并进入函数。

var NUMBERS = 100;

function go() {
  var out = document.getElementById("output");
  for (var i = 1; i < NUMBERS+1; i++) {
    addSpan(i);
  }

  function hover(id, color, size) {
    var span = document.getElementById(id);
    span.style.backgroundColor = color;
    span.style.fontSize = size;
  }

  function addSpan(i) {
    var span_one = document.createElement("span");
    span_one.id = "span" + i;
    span_one.innerHTML = "" + i;
    out.appendChild(span_one);

    if (isPrime(i) === true) {
      span_one.style.backgroundColor = "red";
      span_one.onmouseover = function() {
        hover("span"+i, "yellow", "150%")
      };
      span_one.onmouseout = function() { 
        hover("span"+i, "red", "100%");
      };
    }
  }
}

答案 2 :(得分:0)

问题在于变量-Dsonar.analysis.mode= ,它是闭包的常见问题。有关详细信息,请查看Simplify并转到i部分。要解决此问题,请将Creating closures in loops: A common mistake for for循环更改为var。这将有助于您保留范围,从而解决问题。

let
var NUMBERS = 100;

function go() {
  var out = document.getElementById("output");
  for (let i = 1; i < NUMBERS+1; i++) {
      let span_one = document.createElement("span");
      span_one.id = "span" + i;
      span_one.innerHTML = "" + i;
      out.appendChild(span_one);

    if (isPrime(i) === true) { // if a number is a prime then run this func
      span_one.style.backgroundColor = "red";
      span_one.onmouseover = function() {
        hover("span"+i, "yellow", "150%")
      };
      span_one.onmouseout = function() { 
        hover("span"+i, "red", "100%") // whatever color in this line always overrides previous set color...
      };
    }
    
    function hover(id, color, size) {
        var span = document.getElementById(id);
        span.style.backgroundColor = color;
        span.style.fontSize = size;
    }
    
    //Added my custom function as it was not provided
    function isPrime(i){
      return i%2 != 0;
    }
  }
}

window.onload = go;

答案 3 :(得分:0)

  

您的问题是您的i变量周围有闭包。

只要将函数嵌套在另一个函数中,就会发生闭包。 代码运行不可预测的地方是嵌套函数使用祖先函数中的变量,而嵌套函数的寿命比相关祖先的寿命长。

此处,您的mouseovermouseout函数依赖于父函数i中的go。由于mouseovermouseout函数被附加到DOM元素,并且那些DOM元素将在页面被卸载之前保留在内存中,因此这些函数的生命周期将长于go。这意味着i声明的go变量在go完成时不会超出范围,并且两个鼠标函数将共享{{1}的相同值}。人类出现并移动鼠标时i所具有的值是循环结束时的最后一个值。

一开始闭包可能很有挑战性,但您可以阅读更多关于它们here的内容。

在循环上将i更改为var i解决了这个问题,因为let i为循环的每次迭代引入了块范围。

另外,我看到你错过了两个导致错误的大括号。我添加了自己的let函数。查看地点评论:

&#13;
&#13;
isPrime()
&#13;
window.onload=go;

const NUMBERS = 100;

function go(){

    
  var out = document.getElementById("output");
  
  // Using let instead of var avoids a closure by making sure
  // that each looping number exists in the block scope of the
  // loop and upon each iteration a new variable is created.
  for (let i = 1; i < NUMBERS+1; i++) {
    
    var span = document.createElement("span");
    span.id = "span" + i;

    span.innerHTML = i + "<br>"; 
    out.appendChild(span);

    if (isPrime(i)) { // where i is a prime number (2, 3, 5, 7..etc)
      span.style.backgroundColor = "red";
      
      // If you use the i variable in nested functions, you will create a
      // closure around it and both the mouseover and mouseout functions will
      // share the last known value of i. Each function must get its own copy
      // of i.
      span.onmouseover = function() {
          hover("span" + i, "yellow", "150%")
      };
      
      span.onmouseout = function() { 
        // whatever color in this line always overrides previous set color...
        hover("span" + i, "red", "100%") 
      };
      
    }  // <-- Missing
  }    // <-- Missing
  
}
  
function isPrime(value) {
    for(var i = 2; i < value; i++) {
        if(value % i === 0) {
            return false;
        }
    }
    return value > 1;
}

function hover(id, color, size) {
    var span = document.getElementById(id);
    span.style.backgroundColor = color;
    span.style.fontSize = size;
    console.log(id, span);
}
&#13;
&#13;
&#13;