代碼
<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 學(xué)習(xí)'
}
],
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>
瀏覽器運(yùn)行實(shí)例
第一階段:form表單
<form v-on:submit.prevent="addNewTodo">
</form>
<form> 標(biāo)簽用于創(chuàng)建供用戶輸入的 HTML 表單。通常包含一個(gè)或多個(gè)如下表單元素,如
其中的v-on:submit.prevent="addNewTodo"
,綁定了一個(gè)addNewTodo事件,其中的submit.prevent
指在該表單中的任何提交按鈕都可以觸發(fā)該事件(比如button
按鈕)。
label
<label for="new-todo">添加 todo</label>
<label> 標(biāo)簽為 input 元素定義標(biāo)注(標(biāo)記)。其中的for="new-todo"
屬性,表示與下面的<input id="new-todo">元素綁定。
當(dāng)您點(diǎn)擊<label>
元素時(shí),焦點(diǎn)會(huì)自動(dòng)跳到input控件上。例子如下
第二階段:addNewTodo方法
addNewTodo() {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
this.todos.push
- 拿到todos數(shù)組,并開(kāi)始操作
- push() 方法可向數(shù)組的末尾添加一個(gè)或多個(gè)元素,并返回新的長(zhǎng)度。
- 注意:?新元素將添加在數(shù)組的末尾。
- 注意:?此方法改變數(shù)組的長(zhǎng)度。
- https://www.runoob.com/jsref/jsref-push.html
id: this.nextTodoId++,
title: this.newTodoText
在數(shù)組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']
})
定義了一個(gè)組件todo-item
,接受一個(gè)父組件傳入的值title
,通過(guò)props: ['title'],
接收,沒(méi)有限制和默認(rèn)值。
組件中還有一個(gè)<button>
按鈕,綁定了一個(gè)自定義的單擊事件$emit('remove')
,觸發(fā)父組件的remove
監(jiān)聽(tīng),
即,當(dāng)單擊此“刪除”按鈕時(shí),就會(huì)觸發(fā)父組件:@remove="todos.splice(index, 1)"
的執(zhí)行。
用emits: ['remove']
來(lái)聲明remove
,以免控制臺(tái)報(bào)錯(cuò)。
- 自定義事件詳解
- 實(shí)戰(zhàn)代碼
- Vue中$emit的用法
- 父組件是使用 props 傳遞數(shù)據(jù)給子組件,但如果子組件要把數(shù)據(jù)傳遞回去,就需要使用自定義事件!
- 我們可以使用 v-on 綁定自定義事件
- 子組件可以使用$emit觸發(fā)父組件的自定義監(jiān)聽(tīng)
核心難點(diǎn)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
,很常見(jiàn)的v-for渲染,里面的index
是列表項(xiàng)的索引值(從0開(kāi)始)
v-for 指令需要以?todo in todos?形式的特殊語(yǔ)法, todos
是源數(shù)據(jù)數(shù)組并且 todo
是數(shù)組元素迭代的別名。
:key="todo.id" :title="todo.title"
,分別賦值,key
是todos
數(shù)組里面,id
的值,title是todos
數(shù)組里面,title的值。
根據(jù)子組件,這里只會(huì)渲染title的值。
@remove="todos.splice(index, 1)"
綁定一個(gè)自定義事件remove
,當(dāng)觸發(fā)子組件的點(diǎn)擊事件remove
,就會(huì)觸發(fā)這里的事件,
todos.splice
,拿到數(shù)組todos
并開(kāi)始操作,
splice(index, 1)
,刪掉1個(gè),當(dāng)前列表索引。(刪掉當(dāng)前這個(gè)li(子組件)的數(shù)據(jù))
跑一遍流程:添加數(shù)據(jù)
- 我單擊“添加tudo”,通過(guò)
for="new-todo"
,焦點(diǎn)自動(dòng)到input輸入框 - 我開(kāi)始輸入文本“Npcink”,并單擊“添加”按鈕,提交from表單,通過(guò)
v-on:submit.prevent="addNewTodo"
全局按鈕觸發(fā)事件addNewTodo
- 通過(guò)
v-model
雙向綁定,將我輸入的值(npcink)傳給了newTodoText
, addNewTodo
方法下,通過(guò)push() 方法新增一條數(shù)組,id的值是通過(guò)this
獲得nextTodoId
的值并自增的,title的值是通過(guò)this拿到newTodoText
的值- 在子組件
todo-item
中,通過(guò){{title}}
展示title的值,通過(guò)props: ['title']
拿到父組件的值 - 父組件中通過(guò)
v-for
來(lái)循環(huán)渲染數(shù)組內(nèi)容,通過(guò):title="todo.title"
拿到數(shù)組totds
中title
的值,并將其傳給子組件的title
- 子組件
todo-item
將title
渲染出來(lái)
跑一遍流程:刪除數(shù)據(jù)
- 單擊刪除按鈕,通過(guò)子組件的
$emit('remove')
觸發(fā)父組件的todos.splice(index, 1)
操作 - 刪除了當(dāng)前行的li數(shù)據(jù)
參考
- https://www.runoob.com/vue3/vue3-v-for.html
- label標(biāo)簽中的for屬性:CSDN
- Vue 3 父子組件傳遞數(shù)據(jù)的幾種通信方式:CSDN
- 列表渲染詳解