本页目录
代码
<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>浏览器运行实例
原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。
<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
- 列表渲染详解