事件处理与组件基础
一、事件处理和表单输入绑定
1.事件处理
(1)概念:在 Vue.js中,你可以使用 v-on 指令监听 DOM 事件,并在事件触发时执行 JavaScript 代码。v-on 可以简写为@
(2)示例:
HTML
<div id="app"><button v-on:click="counter += 1">点击增加1</button><p>{{ counter }}</p><button @click="greet">点我打招呼</button><p>{{ message }}</p>
</div><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>var app = new Vue({el: '#app',data: {counter: 0,message: '欢迎!'},methods: {greet: function (event) {// `this` 在方法中指向 Vue 实例alert('你好,' + this.message + '!')// `event` 是原生 DOM 事件if (event) {event.target.innerHTML = '已打招呼'}}}})
</script>
2.事件修饰符
(1)Vue提供了事件修饰符来处理事件的细节,比如阻止冒泡、阻止默认行为。
(2)常用的修饰符有:.stop 、.prevent 、.capture 、 .self
(3)示例:
HTML
<a @click.stop="doThis"></a><form @submit.prevent="onSubmit"></form>
3.表单输入绑定
(1)概念:v-model 指令用于在表单控件上创建双向数据绑定,它会根据控件 1 类型自动更新数据
(2)示例 :
HTML
<div id="app-form"><p>你的名字:<input v-model="name"></p><p>你输入的名字是: {{ name }}</p><p>你最喜欢的框架:</p><input type="checkbox" id="vue" value="Vue" v-model="checkedNames"><label for="vue">Vue</label><input type="checkbox" id="react" value="React" v-model="checkedNames"><label for="react">React</label><p>你喜欢的框架有: {{ checkedNames }}</p>
</div><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>new Vue({el: '#app-form',data: {name: '',checkedNames: []}})
</script>
二、组件基础:可复用的 vue 实例,它拥有自己的模板、逻辑和样式
1.组件注册:要使用组件,首先需要注册它。可以注册全局组件或局部组件
(1)全局组件示例:
HTML
<div id="app"><my-component></my-component>
</div><script>// 全局注册,可以在任何 Vue 实例的模板中使用Vue.component('my-component', {template: '<div>一个自定义组件!</div>'})new Vue({ el: '#app' })
</script>
(2)局部注册示例
HTML
<div id="app"><my-local-component></my-local-component>
</div><script>var ChildComponent = {template: '<div>一个局部组件!</div>'}new Vue({el: '#app',components: {'my-local-component': ChildComponent}})
</script>
2.组件的 data 必须是一个函数
(1)概念:在组件中,data 必须是一个函数,并且返回一个对象。为了确保每个组件实例都有自己独立的数据副本
(2)示例
JavaScript
Vue.component('button-counter', {data: function () {return {count: 0 // 每个组件实例的 count 都是独立的}},template: '<button @click="count++">你点击了 {{ count }} 次</button>'
})
三、组件通信(props 和 events)
1.概念:组件通信主要分为父组件通信和子组件向父组件通信两种方式
2.父组件向子组件传递数据:使用 props
(1)概念:props 是子组件用来接收父组件传递来的数据的自定义属性。props 是单向的,父组件数据更新时,会传递给子组件,但子组件不能直接修改 props 的值
(2)示例:
HTML
<div id="app"><child-component my-prop-title="来自父组件的标题"></child-component>
</div><script>// 子组件定义var ChildComponent = {props: ['myPropTitle'],template: '<div><h2>{{ myPropTitle }}</h2></div>'};// 父组件实例new Vue({el: '#app',components: {'child-component': ChildComponent}});
</script>
3.子组件向父组件发送消息:使用 events
(1)概念:子组件不能直接修改父组件的数据,但可以通过 $emit 方法触发一个自定义事件,父组件则通过 v-on (或@)监听这个事件,从而做出响应
(2)示例:
HTML
<div id="app-event"><p>父组件计数器: {{ total }}</p><button-counter v-on:increment="incrementTotal"></button-counter><button-counter v-on:increment="incrementTotal"></button-counter>
</div><script>// 子组件定义Vue.component('button-counter', {template: '<button @click="incrementCounter">增加</button>',data: function () {return {counter: 0}},methods: {incrementCounter: function () {this.counter += 1this.$emit('increment') // 子组件触发 `increment` 事件}}});// 父组件实例new Vue({el: '#app-event',data: {total: 0},methods: {incrementTotal: function () {this.total += 1}}});
</script>
四、实践项目:Vue 待办事项应用
1.应用功能:
(1)输入框:用户可以在输入框中输入新的待办事项
(2)添加按钮:点击按钮,将输入框中的事项添加到列表中
(3)列表展示:使用 v-for 将所有待办事项展示出来
(4)删除功能:每个待办事项旁边有一个删除按钮,点击后可以从列表中移除该事项
(5)组件化:将单个待办事项(包含文本和删除按钮)封装成一个独立的组件
2.步骤
(1)创建 Vue 实例:在 data 中定义一个待办事项数组,例如 todos:[{ id:1,text: '学习 Vue'}]
(2)构建组件:创建一个名为 todo-item 的子组件,它通过 props 接收待办事项对象
(3)组件通信:在 todo-item 组件内部,点击删除按钮时,通过 $emit 触发一个自定义事件,将该事项的 ID 传给父组件
(4)父组件处理:父组件监听子组件的事件,并根据传入的 ID 从 todos 数组中移除该事项
3.示例:
HTML
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Vue 待办事项应用</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><style>.todo-item {padding: 8px;border-bottom: 1px solid #eee;display: flex;justify-content: space-between;align-items: center;}.todo-item:last-child {border-bottom: none;}.remove-btn {background-color: #f44336;color: white;border: none;padding: 5px 10px;cursor: pointer;}</style>
</head>
<body><div id="app"><h2>我的待办事项</h2><div><input type="text" v-model="newTodoText" @keyup.enter="addNewTodo"><button @click="addNewTodo">添加</button></div><ul><todo-item v-for="todo in todos":key="todo.id":todo-prop="todo"@remove="removeTodo"></todo-item></ul>
</div><script>// 定义子组件Vue.component('todo-item', {// 使用 props 接收父组件传递过来的数据props: ['todoProp'],template: `<li class="todo-item"><span>{{ todoProp.text }}</span><button class="remove-btn" @click="$emit('remove', todoProp.id)">删除</button></li>`});// 创建 Vue 根实例new Vue({el: '#app',data: {newTodoText: '',todos: [{ id: 1, text: '学习 Vue 基础' },{ id: 2, text: '练习组件通信' },{ id: 3, text: '完成待办事项应用' }],nextTodoId: 4},methods: {addNewTodo: function() {if (this.newTodoText.trim() === '') return;this.todos.push({id: this.nextTodoId++,text: this.newTodoText});this.newTodoText = ''; // 清空输入框},// 父组件的方法:监听子组件的 'remove' 事件,并处理删除逻辑removeTodo: function(idToRemove) {// 使用 filter 过滤出不等于要删除 id 的事项this.todos = this.todos.filter(todo => todo.id !== idToRemove);}}});
</script></body>
</html>