在本部分中,将添加一个 HTML 页面,其中包含用于创建和管理待办事项的窗体。 事件处理程序会附加到页面上的元素。 事件处理程序导致对 Web API 的操作方法发出 HTTP 请求。 Fetch API 的 fetch
函数可启动每个 HTTP 请求。
fetch
函数可返回 Promise 对象,该对象包含表示为 Response
对象的 HTTP 响应。 常见模式是通过调用 Response
对象上的 json
函数来提取 JSON 响应正文。 JavaScript 会使用 Web API 响应的详细信息来更新页面。
最简单的 fetch
调用接受一个表示路由的参数。 第二个参数(称为 init
对象)是可选的。 init
用于配置 HTTP 请求。
-
配置应用提供静态文件并启用默认文件映射。 在 Startup.cs 的
C#Configure
方法中需要以下突出显示的代码 :public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
-
在项目根中创建 wwwroot 文件夹 。
-
在 wwwroot 文件夹中创建一个 css 文件夹 。
-
在 wwwroot 文件夹中创建一个 js 文件夹 。
-
将一个名为 index.html 的 HTML 文件添加到 wwwroot 文件夹 。 将 index.html 的内容替换为以下标记 :
HTML<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>To-do CRUD</title> <link rel="stylesheet" href="css/site.css" /> </head> <body> <h1>To-do CRUD</h1> <h3>Add</h3> <form action="javascript:void(0);" method="POST" onsubmit="addItem()"> <input type="text" id="add-name" placeholder="New to-do"> <input type="submit" value="Add"> </form> <div id="editForm"> <h3>Edit</h3> <form action="javascript:void(0);" onsubmit="updateItem()"> <input type="hidden" id="edit-id"> <input type="checkbox" id="edit-isComplete"> <input type="text" id="edit-name"> <input type="submit" value="Save"> <a onclick="closeInput()" aria-label="Close">✖</a> </form> </div> <p id="counter"></p> <table> <tr> <th>Is Complete?</th> <th>Name</th> <th></th> <th></th> </tr> <tbody id="todos"></tbody> </table> <script src="js/site.js" asp-append-version="true"></script> <script type="text/javascript"> getItems(); </script> </body> </html>
-
将名为 site.css 的 CSS 文件添加到 wwwroot/css 文件夹 。 将 site.js 的内容替换为以下类型:
cssinput[type='submit'], button, [aria-label] { cursor: pointer; } #editForm { display: none; } table { font-family: Arial, sans-serif; border: 1px solid; border-collapse: collapse; } th { background-color: #f8f8f8; padding: 5px; } td { border: 1px solid; padding: 5px; }
-
将一个名为 site.js 的 JavaScript 文件添加到 wwwroot/js 文件夹。 将 site.js 的内容替换为以下代码:
Javascriptconst uri = 'api/todoitems'; let todos = []; function getItems() { fetch(uri) .then(response => response.json()) .then(data => _displayItems(data)) .catch(error => console.error('Unable to get items.', error)); } function addItem() { const addNameTextbox = document.getElementById('add-name'); const item = { isComplete: false, name: addNameTextbox.value.trim() }; fetch(uri, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(item) }) .then(response => response.json()) .then(() => { getItems(); addNameTextbox.value = ''; }) .catch(error => console.error('Unable to add item.', error)); } function deleteItem(id) { fetch(`${uri}/${id}`, { method: 'DELETE' }) .then(() => getItems()) .catch(error => console.error('Unable to delete item.', error)); } function displayEditForm(id) { const item = todos.find(item => item.id === id); document.getElementById('edit-name').value = item.name; document.getElementById('edit-id').value = item.id; document.getElementById('edit-isComplete').checked = item.isComplete; document.getElementById('editForm').style.display = 'block'; } function updateItem() { const itemId = document.getElementById('edit-id').value; const item = { id: parseInt(itemId, 10), isComplete: document.getElementById('edit-isComplete').checked, name: document.getElementById('edit-name').value.trim() }; fetch(`${uri}/${itemId}`, { method: 'PUT', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(item) }) .then(() => getItems()) .catch(error => console.error('Unable to update item.', error)); closeInput(); return false; } function closeInput() { document.getElementById('editForm').style.display = 'none'; } function _displayCount(itemCount) { const name = (itemCount === 1) ? 'to-do' : 'to-dos'; document.getElementById('counter').innerText = `${itemCount} ${name}`; } function _displayItems(data) { const tBody = document.getElementById('todos'); tBody.innerHTML = ''; _displayCount(data.length); const button = document.createElement('button'); data.forEach(item => { let isCompleteCheckbox = document.createElement('input'); isCompleteCheckbox.type = 'checkbox'; isCompleteCheckbox.disabled = true; isCompleteCheckbox.checked = item.isComplete; let editButton = button.cloneNode(false); editButton.innerText = 'Edit'; editButton.setAttribute('onclick', `displayEditForm(${item.id})`); let deleteButton = button.cloneNode(false); deleteButton.innerText = 'Delete'; deleteButton.setAttribute('onclick', `deleteItem(${item.id})`); let tr = tBody.insertRow(); let td1 = tr.insertCell(0); td1.appendChild(isCompleteCheckbox); let td2 = tr.insertCell(1); let textNode = document.createTextNode(item.name); td2.appendChild(textNode); let td3 = tr.insertCell(2); td3.appendChild(editButton); let td4 = tr.insertCell(3); td4.appendChild(deleteButton); }); todos = data; }
可能需要更改 ASP.NET Core 项目的启动设置,以便对 HTML 页面进行本地测试:
- 打开 Properties\launchSettings.json。
- 删除
launchUrl
以便在项目的默认文件 index.html 强制打开应用。
此示例调用 Web API 的所有 CRUD 方法。 下面说明 Web API 请求。
获取待办事项的列表
在以下代码中,将 HTTP GET 请求发送到 api/todoitems 路由:
Javascriptfetch(uri)
.then(response => response.json())
.then(data => _displayItems(data))
.catch(error => console.error('Unable to get items.', error));
当 Web API 返回成功状态的代码时,将调用 _displayItems
函数。 将 _displayItems
接受的数组参数中的每个待办事项添加到具有“编辑”和“删除”按钮的表中。 如果 Web API 请求失败,则会将错误记录到浏览器的控制台中。
添加待办事项
在以下代码中:
- 声明
item
变量来构造待办事项的对象文字表示形式。 - 使用以下选项来配置提取请求:
-
method
—指定 POST HTTP 操作谓词。 -
body
—指定请求正文的 JSON 表示形式。 通过将存储在item
中的对象文字传递到 JSON.stringify 函数来生成 JSON。 -
headers
—指定Accept
和Content-Type
HTTP 请求标头。 将两个标头都设置为application/json
,以便分别指定接收和发送的媒体类型。
-
- 将 HTTP POST 请求发送到 api/todoitems 路由。
function addItem() {
const addNameTextbox = document.getElementById('add-name');
const item = {
isComplete: false,
name: addNameTextbox.value.trim()
};
fetch(uri, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(response => response.json())
.then(() => {
getItems();
addNameTextbox.value = '';
})
.catch(error => console.error('Unable to add item.', error));
}
当 Web API 返回成功状态的代码时,将调用 getItems
函数来更新 HTML 表。 如果 Web API 请求失败,则会将错误记录到浏览器的控制台中。
更新待办事项
更新待办事项类似于添加待办事项;但是,二者存在两个重大差异:
- 路由的后缀为待更新项的唯一标识符。 例如 api/todoitems/1。
- 正如
method
选项所示,HTTP 操作谓词是 PUT。
fetch(`${uri}/${itemId}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));
删除待办事项
若要删除待办事项,请将请求的 method
选项设置为 DELETE
并指定该项在 URL 中的唯一标识符。
fetch(`${uri}/${id}`, {
method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));