vue 点击第一下没有触发事件_Vue.js从零开始——入门(5)

06a83354ae7e26287d06a4dc2f21060b.png

Vue 的事件处理器又是个什么样子的,今天的章节内容主要就是这一部分了。


1 监听器

前面其实提及了监听器,v-on (以及简写 @),尽管并不详细,但是也已经说明了用法,这里可以再看一个例子(来自官网,不过我按照自己的习惯稍稍改了一下):

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>hello</title>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="count++">Count +</button>
      <p>Please notice the button clicked {{count}} times</p>
    </div>
    <script>
      let app = new Vue({
        el: '#app',
        data: {
          count: 0
        }
      });
    </script>
  </body>
</html>

91359f12888e7b6c8d994f64b5f5bf27.gif

可以看到上面的代码中,监听器处理了点击事件,这里直接把逻辑写在了监听器当中,是因为增加点击数量的逻辑非常短小好理解;可如果是非常复杂的逻辑,难道直接写 JavaScript 到这里么?结论当然是不,我们还需要事件处理方法的配合来做这件事。

2 事件处理方法

这个其实入门(1)里面也有个比较直观的例子,不过这里可以就用上面这个例子来看,稍稍改动一下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>hello</title>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="addCount">Count +</button>
      <p>Please notice the button clicked {{count}} times</p>
    </div>
    <script>
      let app = new Vue({
        el: '#app',
        data: {
          count: 0
        },
        // 增加 methods 对象,并定义方法
        methods: {
          // 使用上面监听处理事件的名称作为方法名
          addCount: function() {
            // this 指向当前 Vue 实例
            this.count++;
          }
        }
      });
    </script>
  </body>
</html>

由于页面表现和上面例子一样,参考上面的 gif 即可,不过这里可以留意到,因为定义了方法,所以我们也可以通过 app.addCount() 来调用,效果一样的:

fbdaff09503198250dd5b43f7f5a2f16.gif

3 内联处理方法

除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法,下面是个例子:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>hello</title>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="say('hi')">Say Hi</button>
      <button @click="say('OMG')">Say OMG</button>
    </div>
    <script>
      let app = new Vue({
        el: '#app',
        methods: {
          say: function(msg) {
            alert(msg);
            console.log(`Say: ${msg}`);
          }
        }
      });
    </script>
  </body>
</html>

cafc03a5c9ea0f629d16d2fca3ceb93e.gif

如果需要在内联语句处理器中访问原始的 DOM 事件,可以用特殊变量 $event (这是个预定义变量,指代当前 DOM 事件)把它传入方法,下面是个例子:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>hello</title>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="warn('Form cannot be submitted yet.', $event)">
        Submit
      </button>
    </div>
    <script>
      let app = new Vue({
        el: '#app',
        methods: {
          warn: function(msg, e) {
            if (e) {
              e.preventDefault();
            }
            alert(msg);
          }
        }
      });
    </script>
  </body>
</html>

997f9d4eb7f8f52d41c494ca0280c45d.png

上面的代码,就是把原始的事件传入了 Vue 实例,并通过事件处理方法 warn 进行处理,一旦检测到了原始事件存在,就阻止原有的点击事件,并弹出信息 msg

4 事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求(如上例),尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.jsv-on 提供了事件修饰符,之前(入门(2),尽管只有很小的一小节)有提到过,修饰符是由点开头的指令后缀来表示的,事件修饰符包括:

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
<!-- 阻止单击事件继续传播 -->
<a @click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form @submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>

<!-- 点击事件将只会触发一次 -->
<a @click.once="doThis"></a>

<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发,而不会等待 onScroll 完成 -->
<!-- 这其中包含 event.preventDefault() 的情况 -->
<div @scroll.passive="onScroll">...</div>
要留意:使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生;因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
不要把 .passive .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会展示一个警告,请记住, .passive 会告诉浏览器我们不想阻止事件的默认行为。

5 按键修饰符

在监听键盘事件时,我们经常需要检查详细的按键,Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

<!-- 只有在 key 是 Enter 时调用 vm.submit() -->
<input @keyup.enter="submit">

这里我们可以直接将KeyboardEvent.key 暴露的任意有效按键名(点击链接查看 MDN),转换为 kebab-case 来作为修饰符,如下:

<input @keyup.page-down="onPageDown">

在上述示例中,处理函数只会在 $event.key 等于 PageDown 时被调用。

Vue 也可以支持如下修饰符,来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器:

  • .ctrl
  • .alt
  • .shift
  • .meta
注意:在 Mac 系统键盘上, meta 对应 command 键 ( )。在 Windows 系统键盘 meta 对应 Windows 徽标键 ( )。在 Sun 操作系统键盘上, meta 对应实心宝石键 ( )。在其他特定键盘上,尤其在 MIT Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、 space-cadet 键盘, meta 被标记为 META。在 Symbolics 键盘上, meta 被标记为 META 或者 Meta

例如:

<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。

如果我们需要使用按键组合来实现一些事件,可以使用 .exact 修饰符,它允许我们控制由精确的系统修饰符组合触发的事件,例如:

<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

6 鼠标按钮修饰符

如果只希望处理函数仅仅相应特定的鼠标按钮,Vue 也提供了对应的修饰符,如下:

  • .left
  • .right
  • .middle

这三个修饰符很明显分别对应了鼠标左、右、中键,就不举例了。

7 官方对 HTML 当中监听事件的解释

这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:

  1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
  2. 因为无须在 JavaScript 里手动绑定事件,ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
  3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。无须担心如何清理它们。

也正因为如此,Vue.js 成为了非常好入门的一个框架(咱们不在这里讨论它是库还是框架好不?),绝大部分的常用事件都有了对应的修饰符从而减少我们另外编写代码的工作,使得 addEventListener() 的编写工作很大程度的减少了,让我们可以把更多的精力集中在逻辑(业务流程)的实现上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值