vue2.x学习笔记(十)
接着前面的内容:https://www.cnblogs.com/yanggb/p/12584237.html。
事件处理
使用javascript当然少不了事件处理,即使是vue也不会例外。
监听事件
在vue中可以使用【v-on】指令监听dom事件,并在触发的时候运行一些javascript代码。
<div id="example-1"> <button v-on:click="counter += 1">Add 1</button> <p>The button above has been clicked {{ counter }} times.</p> </div>
var example1 = new Vue({ el: '#example-1', data: { counter: 0 } })
在上面的例子中,给button绑定了一个点击的事件,点击该按钮就会触发counter+1的处理逻辑。
事件处理方法
实际的事件处理逻辑当然是比上面的简单例子要复杂得多,这种情况下如果直接把javascript代码写在【v-on】指令中是不可行的,因为该指令中只支持单表达式。因此【v-on】指令还支持接收一个需要调用的方法名称。
<div id="example-2"> <!-- greet是在下面定义的方法名 --> <button v-on:click="greet">Greet</button> </div>
var example2 = new Vue({ el: '#example-2', data: { name: 'Vue.js' }, // 在methods对象中定义方法 methods: { greet: function (event) { // this在方法里指向当前Vue实例 alert('Hello ' + this.name + '!') // event是原生DOM事件 if (event) { alert(event.target.tagName) } } } }) // 也可以用JavaScript直接调用方法(不通过事件绑定触发) example2.greet() // 'Hello Vue.js!'
这样,点击按钮之后就会依次弹出提示内容是【Hello Vue.js!】和【BUTTON】的提示框。
此外,这里要特别注意代码中的注释内容,注意事项可以分为以下的几点。
1.如果方法有入参的话,在模板中可以这样编写:
<button v-on:click="greet('yanggb')">Greet</button>
2.如果方法有入参,但是模板中没有传递参数的话,方法在调用的时候的第一个默认实参会是事件(event)本身,因此这个时候如果你单单用if条件去判断该参数是否存在是不行的,结果总是会返回true,因此如果方法有入参但是你调用方法的时候却不需要传参,而在方法中的判断却依赖了该入参的时候,最好是给一个0值,确保不会出现意料之外的问题,比如点击事件不生效。
<button v-on:click="greet(0)">Greet</button>
3.在method对象中定义的方法,方法体中的this如果没有特殊情况都是指向的当前vm实例。
内联处理器中的方法
除了直接绑定到一个方法,也可以在内联javascript语句中调用方法。
<div id="example-3"> <button v-on:click="say('hi')">Say hi</button> <button v-on:click="say('what')">Say what</button> </div>
new Vue({ el: '#example-3', methods: { say: function (message) { alert(message) } } })
这种方式在需要传递参数的场景中会用到,在前面的注意事项中已经说过了。这里要特别说明的是,有一些场景可能会需要在内联语句处理器中访问原始的dom事件,这种情况下可以使用特殊变量【$event】并将它传入方法中。
<button v-on:click="warn('Form cannot be submitted yet.', $event)"> Submit </button>
// ... methods: { warn: function (message, event) { // 现在我们可以访问原生事件对象 if (event) { event.preventDefault() } alert(message) } }
这个参数实际上也就是当前触发的事件本身,vue将其赋值给了一个全局属性【$event】,以方便我们使用。事实上,当我们不传递参数的时候,方法的第一个参数就会默认赋值为event,而当我们需要传递参数且需要使用事件本身的时候,【$event】也就派上了大用场。
事件修饰符
在事件处理程序中调用【event.preventDefault()】或者【event.stopPropagation()】使非常常见的需求。虽然我们可以在方法中轻松实现这一点(需要借助event),但是vue提供了一种更好的方式,可以使我们免去处理dom事件的细节,而只关注方法的数据逻辑,使方法变得纯粹,不揉杂其他与数据没有直接关联的逻辑。这种更好的方法,就是【v-on】指令的【事件修饰符】,这种修饰符以【.】开头的指令后缀来表示。
.stop
.prevent
.capture
.self
.once
.passive
<!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符可以串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修饰符 --> <form v-on:submit.prevent></form> <!-- 添加事件监听器时使用事件捕获模式 --> <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 --> <div v-on:click.capture="doThis">...</div> <!-- 只当在event.target是当前元素自身时触发处理函数 --> <!-- 即事件不是从内部元素触发的 --> <div v-on:click.self="doThat">...</div>
使用修饰符要注意修饰符的顺序,因为相应的代码会以同样的顺序产生。比如,使用【v-on:click.prevent.self】会阻止所有的点击,而使用【v-on:click.self.prevent】只会阻止对元素自身的点击(元素的爸爸,爷爷或太爷爷都能点击)。
【.once】修饰符是2.1.4中新增的事件修饰符。
<!-- 点击事件将只会触发一次 --> <a v-on:click.once="doThis"></a>
不像其它只能对原生的 DOM 事件起作用的修饰符,【.once】修饰符还能被用到自定义的组件事件上。
【.passive】修饰符是2.3.0中新增的事件修饰符,是vue为了对应addEventListener中的passive选项专门提供的。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 --> <!-- 而不会等待onScroll完成 --> <!-- 这其中包含event.preventDefault()的情况 --> <div v-on:scroll.passive="onScroll">...</div>
因为其设计特性,这个【.passive】修饰符尤其能够提升移动端的性能。但是要注意的是,不要把【.passive】和【.pervent】修饰符一起使用,因为这种情况下【.pervent】修饰符会被忽略,同时浏览器还会展示一个警告。请记住,【.passive】的作用是告诉浏览器不要阻止事件的默认行为,【.passive】的作用是告诉浏览器不要阻止事件的默认行为,【.passive】的作用是告诉浏览器不要阻止事件的默认行为。
按键修饰符
在监听键盘事件的时候,我们经常会需要检查详细的按键,因此vue允许为【v-on】指令在监听键盘事件的时候添加相关的按键修饰符。
<!-- 只有在key是Enter时调用vm.submit() --> <input v-on:keyup.enter="submit">
按键修饰符的语法是,你可以直接将【KeybordEvent.key】暴露的任意有效按键名转换为kebab-case(横线分隔命名)来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
比如在上面这个例子中,处理函数只会在$event.key等于PageDown的时候被调用。
按键码
所谓的按键码,就是用数字去代替按键名,比如13表示的是enter按键。
虽然说keyCode(按键码)的事件用法已经被废弃了,并且可能不会被最新的浏览器支持,但是在vue中使用按键码作为按键修饰符还是允许的。
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧的浏览器,vue提供了绝大多数常用的按键码的别名。
.enter .tab .delete (捕获删除键和退格键) .esc .space .up .down .left .right
而有一些按键(比如.esc和所有的方向键)在ie9中却有着不同的key值,因此如果你想要支持ie9的话,这些内置的别名应该是首选。简单来说,为了避免不必要的麻烦,请使用vue内置的按键别名。
此外,vue还支持通过全局的【config.keyCodes】对象自定义按键修饰符别名。
// 可以使用v-on:keyup.f1 Vue.config.keyCodes.f1 = 112
这样,就可以使用112来表示f1按键名,而且原来的f1按键名依然能使用。
系统修饰键
vue在2.1.0中新增了一些系统修饰符(组合按键),来实现仅在按下相应的按键的时候才去触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
<!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
要注意的第一点是,在不同的操作系统下,这些修饰符对应的系统键盘的按键是不一样的,在开发的时候要将这些客观条件考虑进逻辑处理中。
要注意的第二点是,修饰键与常规的按键是不同的,在和keyup事件一起使用的时候,事件触发的时候修饰键必须是处于按下状态。换句话来说就是,只有在按住ctrl按键的情况下释放其他的按键才会去触发keyup.ctrl事件,而单单释放ctrl是不会触发事件的。但是如果你想要这样的行为也是可以的,请为ctrl申请别名或使用keyCode,即keyup.17,这时候就能达到单按键触发keyup事件的效果了。
更多的,vue在2.5.0中还新增了一个【.exact】修饰符,用于允许开发者控制由精确的系统修饰符组合触发的事件。
<!-- 即使Alt或Shift被一同按下时也会触发 --> <button @click.ctrl="onClick">A</button> <!-- 有且只有Ctrl单独被按下的时候才触发 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 没有任何系统修饰符被按下的时候才触发 --> <button @click.exact="onClick">A</button>
在上面的三个例子中,很清楚的表示了【.exact】在一些需要精准控制组合按键事件触发的特殊场景中十分有用。
鼠标按键修饰符
vue在2.2.0中新增了几个鼠标按键修饰符。
.left
.right
.middle
这些修饰符会限制处理函数仅相应特定的鼠标按钮。
为什么需要在html(模板)中监听事件的思考
你可能注意到了,这种事件监听的方式违背了关注点分离(separation of concern)这个长期依赖的优良传统。但是在vue中,所有的事件处理方法和表达式都是被严格地通过【v-on】指令绑定在当前视图的ViewModel上,并不会导致任何维护上的困难。
这里总结出一些在html(模板)中使用【v-on】绑定事件处理的好处:
1.扫一眼html模板,便能轻松定位在javascript代码中定义的对应方法。
2.因为你无需在JavaScript里面手动绑定事件,因此你的ViewModel代码可以是非常纯粹的逻辑,和dom完全解耦(不需要写dom操作的相关逻辑),更易于测试。
3.当一个ViewModel被销毁的时候,所有的事件处理器都会被自动删除,无需开发者担心如何去清理它们。
"我还是很喜欢你,像仲夏流萤四起,弦月沉西。"