代码
<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
- 列表渲染详解
