一、事件处理和表单输入绑定
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 += 1
this.$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>