Javascript 单击事件的jQuery开/关方法从外部脚本失败

Javascript 单击事件的jQuery开/关方法从外部脚本失败,javascript,jquery,Javascript,Jquery,这在嵌入脚本时起作用。为什么当代码在外部脚本中时,它只对两次单击有效 嵌入式机箱: <html> <head> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> </head> <body> <h1 id="title" onclick="sayGoodbye();"> Hello </h1>

这在嵌入脚本时起作用。为什么当代码在外部脚本中时,它只对两次单击有效

嵌入式机箱:

<html>    
<head>
  <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>    
<body>
  <h1 id="title" onclick="sayGoodbye();"> Hello </h1>
</body>    
<script type="text/javascript">
  function sayGoodbye() {
    console.log("goodbye");
    $("#title").html("Goodbye");
    $("#title").click(function() {
      $("#title").html("Hello");
      $("#title").off("click");
    });
  };
</script>    
</html>

传递函数引用的语法不正确

$('#title').on('click',sayGoodbye());
由于
()
,将立即调用该函数

改为:

$('#title').on('click',sayGoodbye);

问题与文件是外部的或嵌入的无关

您更改了代码,这就是它停止工作的原因。您可以保持HTML代码与原始代码相同
Hello

既然你变了,这就是它不再工作的原因

通过Javascript的
addEventListener
或jQuery的
on
添加事件监听器时,必须始终传递函数引用,而不能传递函数执行。如果使用
()
,将立即调用该函数,并将其返回值传递给正在调用的另一个函数

例如,如果我这样做:

function num() {
  return 5;
}

console.log(num);   // it will log 'function num()'
console.log(num()); // it will log 5
由于您的
saybye
函数不返回任何内容,因此传递给jQuery的
on
的值将是
未定义的

function num() {
   var y = 5;
   y = y + 10;
}

console.log(num);   // it will log 'function num() '
console.log(num()); // it will log 'undefined'
当你输入HTML
onclick=“saybye();”
时,你实际上是在说:

Element.onclick = function() {
  sayGoodbye();
}
它会自动将代码包装到匿名函数中,并将其作为事件的引用传递


Tl;dr

您的代码不起作用,因为您正在使用:

$('#title').on('click', sayGoodbye());
它立即计算/调用函数,因为括号存在

相反,您应该按名称提供回调函数:

$('#title').on('click', sayGoodbye);
或者作为匿名函数:

$('#title').on('click', function() {
  sayGoodbye();
});

更新

在你改变问题之后,这似乎是另一个简单的问题

您在哪里定义您的

您应该将其放置在嵌入的位置。如果您已将其放入
head
标记中,则即使在加载
h1#test
之前也会对其进行评估,然后,它将找不到元素,也不会向其添加事件侦听器

但是,如果您确实想/需要将其放入
head
标记中,则必须将代码包装到
load
事件侦听器中。如果使用香草Javascript,它将是:

document.addEventListener('DOMContentLoaded', function() {
  // your code
});
但是因为您使用的是jQuery,所以可以使用
$(document)。ready

$(document).ready(function() {
  // your code
});
这里有一个缩写,就是用
$()来表示


注意:我刚刚意识到,这里最大的问题是您不理解执行
Hello
和通过jQuery添加事件处理程序之间的区别

您的第一个示例按照您预期的方式工作,因为当您这样做时:

$("#title").html("Goodbye");
$("#title").click(function() {
  $("#title").html("Hello");
  $("#title").off("click");
});
你是说:

  • 将id为
    title
    的元素的
    innerHTML
    属性更改为“再见”
  • 添加一个
    单击
    事件处理程序:

    2.1将id为
    title
    的元素的
    innerHTML
    属性更改为“Hello”

    2.2删除事件的所有jQuery事件处理程序
    单击

  • 那么,接下来会发生什么:

  • 当您第一次单击时

    1.1您的
    h1
    将更改为“再见”

    1.2将有一个新的
    点击
    事件处理程序

  • 当您第二次单击时

    2.1它将首先再次触发同一事件,因此您的
    h1
    将更改为“再见”

    2.2它将有一个新的
    点击
    事件处理程序

    2.3将触发先前在
    1.2
    上添加的事件处理程序

    2.4然后,您的
    h1
    将变回
    Hello

    2.5,然后删除它的所有jQuery
    click
    事件处理程序

  • 因此,当您第三次单击时,与加载页面时一样,因为放入HTML代码中的事件处理程序仍将保留,但附加到
    h1
    的所有jQuery事件处理程序都已删除

    也就是说,第三个将与第一个相同,第四个将与第二个相同,依此类推


    当您停止将事件处理程序附加到HTML代码中,并开始通过jQuery附加它时,您的代码将停止工作,因为:

  • 当您第一次单击时

    1.1您的
    h1
    将更改为“再见”

    1.2将有一个新的
    点击
    事件处理程序

  • 当您第二次单击时

    2.1它将首先再次触发同一事件,因此您的
    h1
    将更改为“再见”

    2.2它将有一个新的
    点击
    事件处理程序

    2.3将触发先前在
    1.2
    上添加的事件处理程序

    2.4然后,您的
    h1
    将变回
    Hello

    2.5并删除它的所有
    单击
    事件处理程序

  • 如您所见,与上面的示例非常相似。但是有一个很大的区别:当发生
    2.5
    时,您不再有任何
    click
    事件处理程序附加到
    h1
    ,因为您已经将它们全部删除

    这种情况会发生,因为当您只将一个参数传递给jQuery的
    off
    方法时,您说的是“删除该类型事件的所有jQuery事件处理程序”(在这种情况下,
    单击
    )。因此,它将同时删除附加到
    saybye
    的事件处理程序和您使用匿名函数创建的事件处理程序

    在第一个示例中,它没有发生,因为jQuery不知道您通过HTML代码附加的事件,所以它永远不会删除它,并且您的代码按照您期望的方式工作

    因此,如果您只想使用jQuery,那么您的代码应该是:

    $(function(){
      function sayGoodbye() {
        $('#title')
          .html('Goodbye')
          .off('click', sayGoodbye)
          .on('click', sayHello);
      }
    
      function sayHello() {
        $('#title')
          .html('Hello')
          .off('click', sayHello)
          .on('click', sayGoodbye);
      }
    
      $('#title').on('click', sayGoodbye);
    });
    

    JavaScript中没有引用(除非讨论引用规范类型,但是..)。将其称为函数对象要整洁得多。那就没有了
    $(function() {
      // your code
    });
    
    $("#title").html("Goodbye");
    $("#title").click(function() {
      $("#title").html("Hello");
      $("#title").off("click");
    });
    
    $(function(){
      function sayGoodbye() {
        $('#title')
          .html('Goodbye')
          .off('click', sayGoodbye)
          .on('click', sayHello);
      }
    
      function sayHello() {
        $('#title')
          .html('Hello')
          .off('click', sayHello)
          .on('click', sayGoodbye);
      }
    
      $('#title').on('click', sayGoodbye);
    });