代码
<script src="https://unpkg.com/vue@next"></script>
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">添加 todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="例如:明天早上跑步"
/>
<button>添加</button>
</form>
<ul>
<todo-item
v-for="(todo, index) in todos"
:key="todo.id"
:title="todo.title"
@remove="todos.splice(index, 1)"
></todo-item>
</ul>
</div>
<script>
const app = Vue.createApp({
data() {
return {
newTodoText: '',
todos: [
{
id: 1,
title: '看电影'
},
{
id: 2,
title: '吃饭'
},
{
id: 3,
title: '上 RUNOOB 学习'
}
],
nextTodoId: 4
}
},
methods: {
addNewTodo() {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
app.component('todo-item', {
template: `
<li>
{{ title }}
<button @click="$emit('remove')">删除</button>
</li>
`,
props: ['title'],
emits: ['remove']
})
app.mount('#todo-list-example')
</script>
浏览器运行实例
第一阶段:form表单
<form v-on:submit.prevent="addNewTodo">
</form>
<form> 标签用于创建供用户输入的 HTML 表单。通常包含一个或多个如下表单元素,如
其中的v-on:submit.prevent="addNewTodo"
,绑定了一个addNewTodo事件,其中的submit.prevent
指在该表单中的任何提交按钮都可以触发该事件(比如button
按钮)。
label
<label for="new-todo">添加 todo</label>
<label> 标签为 input 元素定义标注(标记)。其中的for="new-todo"
属性,表示与下面的<input id="new-todo">元素绑定。
当您点击<label>
元素时,焦点会自动跳到input控件上。例子如下
第二阶段:addNewTodo方法
addNewTodo() {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
this.todos.push
- 拿到todos数组,并开始操作
- push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
- 注意: 新元素将添加在数组的末尾。
- 注意: 此方法改变数组的长度。
- https://www.runoob.com/jsref/jsref-push.html
id: this.nextTodoId++,
title: this.newTodoText
在数组todos中添加新的元素,
- id的值是(拿到
nextTodoId
的值并且自加1)的值 - title的值是:v-model双向绑定的
newTodoText
的值
然后,清空newTodoText
的值:this.newTodoText = ''
第三阶段:子组件
app.component('todo-item', {
template: `
<li>
{{ title }}
<button @click="$emit('remove')">删除</button>
</li>
`,
props: ['title'],
emits: ['remove']
})
定义了一个组件todo-item
,接受一个父组件传入的值title
,通过props: ['title'],
接收,没有限制和默认值。
组件中还有一个<button>
按钮,绑定了一个自定义的单击事件$emit('remove')
,触发父组件的remove
监听,
即,当单击此“删除”按钮时,就会触发父组件:@remove="todos.splice(index, 1)"
的执行。
用emits: ['remove']
来声明remove
,以免控制台报错。
- 自定义事件详解
- 实战代码
- Vue中$emit的用法
- 父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
- 我们可以使用 v-on 绑定自定义事件
- 子组件可以使用$emit触发父组件的自定义监听
核心难点v-for渲染
<todo-item v-for="(todo, index) in todos" :key="todo.id" :title="todo.title"
@remove="todos.splice(index, 1)"></todo-item>
v-for="(todo, index) in todos
,很常见的v-for渲染,里面的index
是列表项的索引值(从0开始)
v-for 指令需要以 todo in todos 形式的特殊语法, todos
是源数据数组并且 todo
是数组元素迭代的别名。
:key="todo.id" :title="todo.title"
,分别赋值,key
是todos
数组里面,id
的值,title是todos
数组里面,title的值。
根据子组件,这里只会渲染title的值。
@remove="todos.splice(index, 1)"
绑定一个自定义事件remove
,当触发子组件的点击事件remove
,就会触发这里的事件,
todos.splice
,拿到数组todos
并开始操作,
splice(index, 1)
,删掉1个,当前列表索引。(删掉当前这个li(子组件)的数据)
跑一遍流程:添加数据
- 我单击“添加tudo”,通过
for="new-todo"
,焦点自动到input输入框 - 我开始输入文本“Npcink”,并单击“添加”按钮,提交from表单,通过
v-on:submit.prevent="addNewTodo"
全局按钮触发事件addNewTodo
- 通过
v-model
双向绑定,将我输入的值(npcink)传给了newTodoText
, addNewTodo
方法下,通过push() 方法新增一条数组,id的值是通过this
获得nextTodoId
的值并自增的,title的值是通过this拿到newTodoText
的值- 在子组件
todo-item
中,通过{{title}}
展示title的值,通过props: ['title']
拿到父组件的值 - 父组件中通过
v-for
来循环渲染数组内容,通过:title="todo.title"
拿到数组totds
中title
的值,并将其传给子组件的title
- 子组件
todo-item
将title
渲染出来
跑一遍流程:删除数据
- 单击删除按钮,通过子组件的
$emit('remove')
触发父组件的todos.splice(index, 1)
操作 - 删除了当前行的li数据
参考
- https://www.runoob.com/vue3/vue3-v-for.html
- label标签中的for属性:CSDN
- Vue 3 父子组件传递数据的几种通信方式:CSDN
- 列表渲染详解