一、事件处理
1.1 监听事件
我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler"
或 @click="handler"
。
事件处理器 (handler) 的值可以是:
- 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似)。
- 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
这两种在前面的博客已经有体现
1.2 事件修饰符
在处理事件时调用 event.preventDefault() 或 event.stopPropagation() 是很常见的。尽管我们可以直接在方法内调用,但如果方法能更专注于数据逻辑而不用去处理 DOM 事件的细节会更好。
为解决这一问题,Vue 为 v-on 提供了事件修饰符。修饰符是用 .
表示的指令后缀,包含以下这些:
- .stop
- .prevent
- .self
- .capture
- .once
- .passive
<!-- 单击事件将停止传递 --> <a @click.stop="doThis"></a> <!-- 提交事件将不再重新加载页面 --> <form @submit.prevent="onSubmit"></form> <!-- 修饰语可以使用链式书写 --> <a @click.stop.prevent="doThat"></a> <!-- 也可以只有修饰符 --> <form @submit.prevent></form> <!-- 仅当 event.target 是元素本身时才会触发事件处理器 --> <!-- 例如:事件处理器不来自子元素 --> <div @click.self="doThat">...</div>
使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此使用@click.prevent.self会阻止元素及其子元素的所有点击事件的默认行为,而@click.self.prevent 则只会阻止对元素本身的点击事件的默认行为。
<!-- 添加事件监听器时,使用 `capture` 捕获模式 --> <!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 --> <div @click.capture="doThis">...</div> <!-- 点击事件最多被触发一次 --> <a @click.once="doThis"></a> <!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 --> <!-- 以防其中包含 `event.preventDefault()` --> <div @scroll.passive="onScroll">...</div>
.capture、.once 和 .passive 修饰符与原生 addEventListener 事件相对应
请勿同时使用 .passive 和 .prevent,因为 .passive 已经向浏览器表明了你不想阻止事件的默认行为。如果你这么做了,则.prevent 会被忽略,并且浏览器会抛出警告。
1.3 按键修饰符
在监听键盘事件时,我们经常需要检查特定的按键。Vue 允许在 v-on 或 @ 监听按键事件时添加按键修饰符。
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` --> <input @keyup.enter="submit" />
你可以直接使用 KeyboardEvent.key 暴露的按键名称作为修饰符,但需要转为 kebab-case 形式。
<input @keyup.page-down="onPageDown" />
在上面的例子中,仅会在 $event.key 为 ‘PageDown’ 时调用事件处理。
按鍵別名
Vue 为一些常用的按键提供了别名:
- .enter
- .tab
- .delete (捕获“Delete”和“Backspace”两个按键)
- .esc
- .space
- .up
- .down
- .left
- .right
1.4 实例
事件冒泡
是指在计算机编程中的一种事件传递机制。
在事件驱动的编程模型中,当用户与程序交互时,例如点击鼠标或按下键盘,这些操作会触发相应的事件。事件冒泡是指当一个元素上的事件被触发时,它会向上级元素传递,直到根元素,这个过程就像气泡从底部冒到顶部一样。
那有时候我们不需要这种情况发生,该怎么解决呢?用咱们的事件修饰符
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script> <style> .red{ width: 400px; height: 400px; background-color: red; } .orange{ width: 300px; height: 300px; background-color: orange; } .blue{ width: 200px; height: 200px; background-color: blue; } .black{ width: 100px; height: 100px; background-color: black; } </style> </head> <body> <!-- 定义边界 --> <div id="app"> <p>冒泡事件</p> <div class="red" @click="red"> <div class="orange" @click="orange"> <div class="blue" @click="blue"> <!-- 添加stop修饰符阻止冒泡 --> <div class="black" @click.stop="black"></div> </div> </div> </div> <p>提交答案</p> <!-- 只能点一次 --> <button @click.once="dosub">提交</button> <p>按键修饰符</p> <input v-on:keyup.enter="dosub" /> </div> </body> <script type="text/javascript"> // 绑定边界 ES6具体体现 new Vue({ el: '#app', data() { return { f200: 'f200' }; }, methods: { red() { alert("red"); }, orange() { alert("orange"); }, blue() { alert("blue"); }, black() { alert("black"); }, dosub(){ alert("提交"); } } }) </script> </html>
二、表单综合案例
在前端处理表单时,我们常常需要将表单输入框的内容同步给 JavaScript 中相应的变量。手动连接值绑定和更改事件监听器可能会很麻烦:
<input :value="text" @input="event => text = event.target.value">
v-model 指令帮我们简化了这一步骤:
<input v-model="text">
另外,v-model 还可以用于各种不同类型的输入,<textarea>、<select>
元素。它会根据所使用的元素自动使用对应的 DOM 属性和事件组合:
- 文本类型的
<input>
和<textarea>
元素会绑定 value property 并侦听 input 事件; <input type="checkbox">
和<input type="radio">
会绑定 checked property 并侦听 change 事件;<select>
会绑定 value property 并侦听 change 事件。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script> <title>表单</title> </head> <body> <div id="app"> <h1>vue表单</h1> <label>姓名:</label><input v-model="uname" /><br /> <label>密码:</label><input v-model="upwd" type="password" /><br /> <!-- 将用户的输入值转为 Number 类型 --> <label>年龄:</label><input v-model.number="age" /><br /> <label>性别:</label> <input type="radio" v-model="sex" name="sex" value="1" />男 <input type="radio" v-model="sex" name="sex" value="0" />女<br /> <label>爱好:</label> <div v-for="h in hobby"> <input type="checkbox" v-model="hobbies" v-bind:value="h.id" />{{h.name}} </div> <label>类别:</label> <select v-model="type"> <option value="-1">===请选择===</option> <option v-for="t in types" v-bind:value="t.id">{{t.name}}</option> </select><br /> <label>备注:</label> <textarea v-bind:value="mark"></textarea><br /> 确认<input type="checkbox" v-model="flag" /> <input type="submit" v-bind:disabled="show" v-on:click="doSubmit" /> </div> </body> <script type="text/javascript"> new Vue({ el: '#app', data() { return { uname: null, upwd: null, age: 10, sex: 1, hobby: [{ id: 1, name: '唱' }, { id: 2, name: '跳' }, { id: 3, name: 'rap' }, { id: 4, name: '篮球' }], hobbies: [], types: [{ id: 1, name: '天帝' }, { id: 2, name: '仙王' }, { id: 3, name: '人皇' }], type: null, mark: '学生备注', flag: false } }, computed: { show: function() { return !this.flag; } }, methods: { doSubmit: function() { console.log('doSubmit') var obj = { uname: this.uname, upwd: this.upwd, age:this.age+10, sex: this.sex, hobbies:this.hobbies, type: this.type, mark: this.mark, } console.log(obj); } } }) </script> </html>
三、自定义组件
Props
Props是一种特别的 attributes,你可以在组件上声明注册。当一个值被传递给 prop 时,它将成为该组件实例上的一个属性。该属性的值可以像其他组件属性一样,在模板和组件的 this 上下文中访问。
一个组件可以有任意多的 props,默认情况下,所有 prop 都接受任意类型的值。
父传子
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script> </head> <body> <div id="app"> <h1>{{msg}}</h1> <!-- 使用自定义组件my-button的时候进行传值(相当于jsp标签往助手类中传值的概念) --> <my-button m="荒 "@click="nb"></my-button> </div> </body> <script> // 定义全局组件的方式 Vue.component('my-button', { props: ['m'], template: '<button v-on:click="doClickMyButton">我是一个自定义组件,被{{m}}点了{{n}}次</button>', data: function() { return { n: 0 }; }, methods: { doClickMyButton: function() { console.log('doClickMyButton方法被调用'); this.n++; } } }), new Vue({ el: "#app", data(){ return{ msg:'自定义组件' }; } }); </script> </html>
子传父
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script> </head> <body> <div id="app"> <h1>{{msg}}</h1> <!-- 使用自定义组件my-button的时候进行传值(相当于jsp标签往助手类中传值的概念) --> <my-button m="荒 " @click='nb'></my-button> </div> </body> <script> // 定义全局组件的方式 Vue.component('my-button', { props: ['m'], template: '<button v-on:click="doClickMyButton">我是一个自定义组件,被{{m}}点了{{n}}次</button>', data: function() { return { n: 0 }; }, methods: { doClickMyButton: function() { console.log('doClickMyButton方法被调用'); this.n++; this.$emit('click', this.n, '荒', '石昊'); } } }), new Vue({ el: "#app", data() { return { msg: '自定义组件' }; }, methods: { nb: function(a, b, c) { console.log('方法被调用'); console.log(a, b, c); } } }); </script> </html>