新增新的待辦事項表單:Vue 事件、方法和模型
現在我們已經有了示例資料,以及一個迴圈,它獲取每個資料並將其渲染到應用中的 ToDoItem 中。我們接下來真正需要的是讓使用者能夠將他們自己的待辦事項輸入到應用程式中,為此我們需要一個文字 <input>,一個當資料提交時觸發的事件,一個在提交時觸發的新增資料並重新渲染列表的方法,以及一個控制資料的模型。這就是我們將在本文中討論的內容。
| 先決條件 |
熟悉核心 HTML、CSS 和 JavaScript 語言,瞭解 終端/命令列。 Vue 元件以 JavaScript 物件(管理應用程式資料)和基於 HTML 的模板語法(對映到底層 DOM 結構)的組合形式編寫。要進行安裝,並使用 Vue 的一些更高階功能(如單檔案元件或渲染函式),您需要一個安裝了 node + npm 的終端。 |
|---|---|
| 目標 | 瞭解如何在 Vue 中處理表單,以及相關的事件、模型和方法。 |
建立新的待辦事項表單
我們現在有一個顯示待辦事項列表的應用程式。但是,我們無法更新專案列表,除非手動更改程式碼!讓我們解決這個問題。讓我們建立一個新的元件,允許我們新增新的待辦事項。
- 在您的元件資料夾中,建立一個名為
ToDoForm.vue的新檔案。 - 新增一個空白的
<template>和一個<script>標籤,就像以前一樣。html<template></template> <script> export default {}; </script> - 讓我們新增一個 HTML 表單,它允許您輸入新的待辦事項並將其提交到應用程式中。我們需要一個
<form>,帶有一個<label>、一個<input>和一個<button>。更新您的模板,如下所示。因此,我們現在有一個表單元件,可以在其中輸入新的待辦事項標題(當它最終被渲染時,它將成為相應html<template> <form> <label for="new-todo-input"> What needs to be done? </label> <input type="text" id="new-todo-input" name="new-todo" autocomplete="off" /> <button type="submit">Add</button> </form> </template>ToDoItem的標籤)。 - 讓我們將此元件載入到我們的應用程式中。返回到
App.vue,並在之前的語句下方新增以下import語句,位於您的<script>元素中。jsimport ToDoForm from "./components/ToDoForm"; - 您還需要在
App元件中註冊新的元件 — 更新元件物件的components屬性,使其看起來像這樣。jscomponents: { ToDoItem, ToDoForm, } - 最後,在本節中,透過將
<to-do-form />元素新增到App的<template>中,將ToDoForm元件渲染到應用程式中,如下所示。html<template> <div id="app"> <h1>My To-Do List</h1> <to-do-form></to-do-form> <ul> <li v-for="item in ToDoItems" :key="item.id"> <to-do-item :label="item.label" :done="item.done" :id="item.id"></to-do-item> </li> </ul> </div> </template>
現在,當您檢視執行的網站時,您應該會看到新顯示的表單。
如果您填寫它並點選“新增”按鈕,該頁面將把表單釋出回伺服器,但這並不是我們真正想要的。我們實際上想要做的是在 submit 事件 上執行一個方法,該方法將新的待辦事項新增到 App 內定義的 ToDoItem 資料列表中。為此,我們需要向元件例項新增一個方法。
建立方法並使用 v-on 將其繫結到事件
要使一個方法對 ToDoForm 元件可用,我們需要將其新增到元件物件中,這在元件物件的 methods 屬性中完成,它位於 data()、props 等的位置。methods 屬性儲存我們可能需要在元件中呼叫的任何方法。當引用時,方法會完全執行,因此不要將其用於在模板中顯示資訊。對於顯示來自計算的資料,您應該使用 computed 屬性,我們將在稍後介紹。
- 在此元件中,我們需要向
ToDoForm元件物件的methods屬性中新增一個onSubmit()方法。我們將使用它來處理提交操作。按如下方式新增它。jsexport default { methods: { onSubmit() { console.log("form submitted"); }, }, }; - 接下來,我們需要將該方法繫結到
<form>元素的submit事件處理程式。與 Vue 如何使用v-bind語法繫結屬性非常類似,Vue 還有一個用於事件處理的特殊指令:v-on。v-on指令透過v-on:event="method"語法工作。並且與v-bind類似,也有一種簡寫語法:@event="method"。為了保持一致性,我們將在這裡使用簡寫語法。將submit處理程式新增到您的<form>元素中,如下所示。html<form @submit="onSubmit">…</form> - 當您執行它時,應用程式仍然將資料釋出到伺服器,導致重新整理。由於我們是在客戶端執行所有處理,因此沒有伺服器來處理回發。我們還會在頁面重新整理時丟失所有本地狀態。要防止瀏覽器釋出到伺服器,我們需要在頁面冒泡時停止事件的預設操作(
Event.preventDefault(),在普通 JavaScript 中)。Vue 有一種稱為 **事件修飾符** 的特殊語法,可以為我們直接在模板中處理這個問題。修飾符以點為字尾附加到事件的末尾,如下所示:@event.modifier。以下是事件修飾符列表。.stop:停止事件傳播。等效於普通 JavaScript 事件中的Event.stopPropagation()。.prevent:防止事件的預設行為。等效於Event.preventDefault()。.self:僅當事件從該確切元素髮出時才觸發處理程式。{.key}:僅透過指定的鍵觸發事件處理程式。MDN 有一個有效的鍵值列表;多詞鍵只需要轉換為 kebab-case(例如page-down)。.native:偵聽元件的根(最外層包裝)元素上的本機事件。.once:偵聽事件,直到它被觸發一次,之後不再偵聽。.left:僅透過左滑鼠按鈕事件觸發處理程式。.right:僅透過右滑鼠按鈕事件觸發處理程式。.middle:僅透過中間滑鼠按鈕事件觸發處理程式。.passive:等效於在使用addEventListener()的普通 JavaScript 中建立事件偵聽器時使用{ passive: true }引數。
.prevent修飾符來停止瀏覽器的預設提交操作。在您的模板中,將.prevent新增到@submit處理程式中,如下所示。html<form @submit.prevent="onSubmit">…</form>
如果您現在嘗試提交表單,您會注意到頁面沒有重新載入。如果開啟控制檯,您可以看到我們在 onSubmit() 方法中新增的 console.log() 的結果。
使用 v-model 將資料繫結到輸入
接下來,我們需要一種方法來獲取表單的 <input> 的值,以便我們可以將新的待辦事項新增到 ToDoItems 資料列表中。
我們首先需要在表單中有一個 data 屬性來跟蹤待辦事項的值。
- 向
ToDoForm元件物件新增一個data()方法,該方法返回一個label欄位。我們可以將label的初始值設定為一個空字串。您的元件物件現在應該看起來像這樣。jsexport default { methods: { onSubmit() { console.log("form submitted"); }, }, data() { return { label: "", }; }, }; - 我們現在需要一種方法將
new-todo-input元素的欄位的值附加到label欄位。Vue 專門為此提供了一個指令:v-model。v-model繫結到您為其設定的資料屬性,並使其與<input>保持同步。v-model在所有各種輸入型別中都適用,包括複選框、單選按鈕和選擇輸入。要使用v-model,您需要向<input>新增一個具有v-model="variable"結構的屬性。因此,在我們的案例中,我們將將其新增到new-todo-input欄位中,如下所示。現在就執行此操作。html<input type="text" id="new-todo-input" name="new-todo" autocomplete="off" v-model="label" />注意:您還可以透過事件和
v-bind屬性的組合來同步資料與<input>值。事實上,這就是v-model在幕後所做的。但是,確切的事件和屬性組合因輸入型別而異,並且需要比僅僅使用v-model快捷方式更多的程式碼。 - 讓我們透過在
onSubmit()方法中記錄提交的資料的值來測試v-model的使用。在元件中,資料屬性使用this關鍵字訪問。因此,我們使用this.label訪問label欄位。更新您的onSubmit()方法,使其看起來像這樣。jsmethods: { onSubmit() { console.log('Label value: ', this.label); } }, - 現在返回執行的應用程式,在
<input>欄位中新增一些文字,然後點選“新增”按鈕。您應該會在控制檯中看到您輸入的值,例如Label value: My value
使用修飾符更改 v-model 行為
與事件修飾符類似,我們也可以新增修飾符來更改 v-model 的行為。在我們的案例中,有兩個值得考慮。第一個是 .trim,它將刪除輸入之前或之後的空格。我們可以將修飾符新增到 v-model 語句中,如下所示:v-model.trim="label"。
我們應該考慮的第二個修飾符稱為 .lazy。此修飾符更改了 v-model 為文字輸入同步值的時間。如前所述,v-model 同步透過使用事件來更新變數。對於文字輸入,這是使用 input 事件 完成的。通常,這意味著 Vue 會在每次按鍵後同步資料。.lazy 修飾符會導致 v-model 使用 change 事件。這意味著 Vue 只有在輸入失去焦點或提交表單時才會同步資料。對於我們的目的,這是更合理的,因為我們只需要最終資料。
要同時使用 .lazy 修飾符和 .trim 修飾符,我們可以將它們連結起來,例如 v-model.lazy.trim="label"。
更新您的 v-model 屬性以連結 lazy 和 trim,如上所示,然後再次測試您的應用程式。例如,嘗試提交一個兩端都有空格的值。
使用自定義事件將資料傳遞給父級
我們現在非常接近能夠將新的待辦事項新增到我們的列表中。接下來,我們需要能夠將新建立的待辦事項傳遞給 App 元件。為此,我們可以讓 ToDoForm 發出一個傳遞資料的自定義事件,並讓 App 監聽它。這與 HTML 元素上的本機事件非常相似:子元件可以發出一個事件,該事件可以透過 v-on 監聽。
在我們的 ToDoForm 的 onSubmit 事件處理程式中,讓我們新增一個 todo-added 事件。自定義事件的發出方式如下:this.$emit("event-name")。重要的是要知道,事件處理程式區分大小寫,並且不能包含空格。Vue 模板也會轉換為小寫,這意味著 Vue 模板無法監聽以大寫字母命名的事件。
- 將
onSubmit()方法中的console.log()替換為以下內容jsthis.$emit("todo-added"); - 接下來,返回
App.vue並將一個methods屬性新增到你的元件物件中,其中包含一個addToDo()方法,如下所示。目前,這個方法只需將To-do added日誌記錄到控制檯中。jsexport default { name: "app", components: { ToDoItem, ToDoForm, }, data() { return { ToDoItems: [ { id: "todo-" + nanoid(), label: "Learn Vue", done: false }, { id: "todo-" + nanoid(), label: "Create a Vue project with the CLI", done: true, }, { id: "todo-" + nanoid(), label: "Have fun", done: true }, { id: "todo-" + nanoid(), label: "Create a to-do list", done: false, }, ], }; }, methods: { addToDo() { console.log("To-do added"); }, }, }; - 接下來,將一個針對
todo-added事件的事件監聽器新增到<to-do-form></to-do-form>中,當事件觸發時,它會呼叫addToDo()方法。使用@簡寫,監聽器看起來像這樣:@todo-added="addToDo"html<to-do-form @todo-added="addToDo"></to-do-form> - 當你提交
ToDoForm時,你應該會看到addToDo()方法中的控制檯日誌。這很好,但我們還沒有將任何資料傳回App.vue元件。我們可以透過在ToDoForm元件中的this.$emit()函式中傳遞額外的引數來做到這一點。在本例中,當我們觸發事件時,我們希望將label資料一併傳遞過去。這可以透過將你想要傳遞的資料作為$emit()方法中的另一個引數來實現:this.$emit("todo-added", this.label)。這類似於原生 JavaScript 事件包含資料的方式,只是自定義 Vue 事件預設情況下不包含任何事件物件。這意味著發出的事件將直接與你提交的任何物件匹配。因此,在我們的例子中,我們的事件物件只是一個字串。更新你的onSubmit()方法,如下所示jsonSubmit() { this.$emit('todo-added', this.label) } - 為了實際在
App.vue中獲取此資料,我們需要在addToDo()方法中新增一個引數,該引數包含新待辦事項的label。返回App.vue並立即更新它jsmethods: { addToDo(toDoLabel) { console.log('To-do added:', toDoLabel); } }
如果你再次測試你的表單,你將看到你在提交時在控制檯中記錄的任何文字。Vue 自動將 this.$emit() 中事件名稱之後的引數傳遞到你的事件處理程式。
將新的待辦事項新增到我們的資料中
現在我們已經獲得了 ToDoForm 中的資料,並將其提供給 App.vue,我們需要向 ToDoItems 陣列中新增一個代表它的專案。這可以透過將一個包含我們新資料的待辦事項物件推送到陣列中來實現。
- 更新你的
addToDo()方法,如下所示jsaddToDo(toDoLabel) { this.ToDoItems.push({id: "todo-" + nanoid(), label: toDoLabel, done: false}); } - 再次嘗試測試你的表單,你應該會看到新的待辦事項被追加到列表的末尾。
- 在我們繼續之前,讓我們再做進一步的改進。如果你在輸入為空時提交表單,則仍然會將沒有文字的待辦事項新增到列表中。為了解決這個問題,我們可以防止在名稱為空時觸發 todo-added 事件。由於名稱已經被
.trim修飾符修剪過,我們只需要測試空字串。返回你的ToDoForm元件,並更新onSubmit()方法,如下所示。如果標籤值為空,則不要發出todo-added事件。jsonSubmit() { if (this.label === "") { return; } this.$emit('todo-added', this.label); } - 再次嘗試你的表單。現在你將無法將空專案新增到待辦事項列表中。
使用 v-model 更新輸入值
在我們的 ToDoForm 元件中,還有一件事需要修復,那就是提交後,<input> 仍然包含舊值。但要修復這一點很容易,因為我們使用 v-model 將資料繫結到 ToDoForm 中的 <input>,如果我們將 name 引數設定為等於空字串,則輸入也將更新。
將你的 ToDoForm 元件的 onSubmit() 方法更新為此方法
onSubmit() {
if (this.label === "") {
return;
}
this.$emit('todo-added', this.label);
this.label = "";
}
現在,當你點選 "新增" 按鈕時,"new-todo-input" 將會清除自身。