使用 Airtable、Vue + Vuetify 构建一个简单的 CRUD 应用程序
到目前为止,所有内容都是标准的 Vue、Veutify 和 Axios 样板。现在让我们深入了解 CRUD 应用程序的核心……
什么是 Airtable
如果您不熟悉Airtable ,它就像 Google Sheets 与关系型数据库的结合体。最棒的是,它是免费的,拥有简单易用的 GUI(即使没有编程经验的人也能轻松上手)以及数据 API!
创建数据库非常简单,只需在 Airtable 中添加一个“工作表”即可。例如,这里有一个名为“Somedata”的 Airtable,其中包含一个名为“Example”的表……
使用 Airtable 提供的各种数据类型添加您需要的任何列/字段。
每个 Airtable 都有一个 API😎
添加工作表和几列后,点击?
Airtable 用户界面右上角的(帮助)图标,然后选择“API 文档”。您将看到 Airtable API 的文档……
正如您对简单的 CRUD API 所期望的那样,它提供了List、Read、Create、Update和Delete等 API 方法。每个 API 端点都是一个 URL,由 Airtable ID(又称“应用程序 ID”)和表名组成。API 请求还需要一个唯一的 API 密钥,您也可以在 API 文档中找到该密钥。
例如,这是我的“Somedata”(应用程序 ID:appsAka4wMdRoGCUc)表名为“Example”的 API URL:
API 端点的示例 URL
https://api.airtable.com/v0/appsAka4wMdRoGCUc/Example
使用 Vuetify 的 Vue 应用
使用Vuetify 强大的组件框架,我们来创建 Vue 应用。我添加了一些常量来保存我的 Airtable 设置(稍后会用到它们):
<script>
const apiToken = "keyZoaskXXXX" // use your own key!
const airTableApp = "appXJzFFs2zgj4X5C"
const airTableName = "Example"
new Vue({
el: '#app',
vuetify: new Vuetify(),
})
</script>
<template>
<div id="app">
<v-app>
<v-content>
<h2>
Vuetify CRUD Example
</h2>
</v-content>
</v-app>
</div>
</template>
Axios 和 Vuetify 数据表
我们将使用Vue Axios与 Airtable API 进行通信。Vuetify 的DataTable 组件用于显示数据,并提供内置的分页、排序和搜索功能。
我们使用双重用途的对话框组件来创建或编辑记录。
到目前为止,所有内容都是标准的 Vue、Veutify 和 Axios 样板。现在让我们深入了解 CRUD 应用程序的核心……
1.v-data-table
首先让我们在模板标记中设置:
<div id="app">
<v-app>
<v-content class="container align-center px-1">
<h2 class="font-weight-light mb-2">
Vuetify CRUD Example
</h2>
<v-card>
<v-data-table
:headers="headers"
:items="items">
</v-data-table>
</v-card>
</v-content>
</v-app>
</div>
2.添加 Vuedata()
并items
供headers
Vuetify DataTable 使用。注意它们headers
与 Airtable 示例列相对应。
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{ text: 'Id', value: 'id' },
{ text: 'Name', value: 'Name' },
{ text: 'Details', value: 'details', sortable: false, width:"100" },
{ text: 'URL', value: 'url', name:'url', width:"180" },
{ text: 'Action', value: 'actions', sortable: false },
],
items: [],
dialog: false, // used to toggle the dialog
editedItem: {} // empty holder for create/update ops
}
},
})
从 Airtable API 读取
3.接下来,我们将使用 Axios向 Airtable API发出 GET请求loadItems()
(获取)。以下是读取“Example”中所有记录(行)的方法。当 Vue 组件有以下情况时,我们会调用此方法mounted()
……
...
mounted() {
this.loadItems()
},
methods: {
loadItems() {
this.items = []
axios.get(`https://api.airtable.com/v0/${airTableApp}/${airTableName}`,
{ headers: { Authorization: "Bearer " + apiToken }})
.then((response) => {
// load the API response into items for datatable
this.items = response.data.records.map((item)=>{
return {
id: item.id,
...item.fields
}
})
}).catch((error) => {
console.log(error)
})
},
请注意,我们现在已经使用了之前创建的 Airtable const。
处理来自 Airtable API 的响应
API响应数据如下所示...
列出来自 Airtable API 的记录响应
{
"records": [
{
"id": "recqbv38i4CbirwP4",
"fields": {
"Cat": "bar",
"URL": "https://codeply.com",
"Lat": -71.39241,
"Details": "Frontend editor online",
"Name": "Codeply",
"Lon": 41.46,
"Client": "John Doe"
},
"createdTime": "2020-03-25T18:33:52.000Z"
},
{
"id": "recsEjAfLlkKH5rcC",
"fields": {
"Cat": "lodging",
"URL": "https://themestr.app",
"Lat": -71.39,
"Details": "Theme builder and customizer for Bootstrap 4",
"Name": "Themestr.app",
"Lon": 41.67,
"Client": "Mary Janes"
},
"createdTime": "2020-03-25T18:33:52.000Z"
},
... more rows...
]
}
需要注意的是,上面表格数据包含在records
数组中,而行数据嵌套在fields
属性中。因此,该方法会像这样loadItems()
赋值给数据:this.items
this.items = response.data.records.map((item)=>{
return {
id: item.id,
...item.fields
}
})
现在this.items
数组具有扁平的结构,易于v-data-table
迭代:
[
{
"id": "recqbv38i4CbirwP4",
"Cat": "bar",
"URL": "https://codeply.com",
"Lat": -71.39241,
"Details": "Frontend editor online",
"Name": "Codeply",
"Lon": 41.46,
"Client": "John Doe".
"createdTime": "2020-03-25T18:33:52.000Z"
},
... more rows...
]
向 Airtable API 发送数据(POST 和 PUT)
4.继续使用saveItem
(创建或更新)的方法和deleteItem
:
,
methods: {
loadItems() {
...
},
saveItem(item) {
/* this is used for both creating and updating API records
the default method is POST for creating a new item */
let method = "post"
let url = `https://api.airtable.com/v0/${airTableApp}/${airTableName}`
let id = item.id
// airtable API needs the data to be placed in fields object
let data = {
fields: item
}
if (id) {
// if the item has an id, we're updating an existing item
method = "patch"
url = `https://api.airtable.com/v0/${airTableApp}/${airTableName}/${id}`
// must remove id from the data for airtable patch to work
delete data.fields.id
}
// save the record
axios[method](url,
data,
{ headers: {
Authorization: "Bearer " + apiToken,
"Content-Type": "application/json"
}
}).then((response) => {
if (response.data && response.data.id) {
// add new item to state
this.editedItem.id = response.data.id
if (!id) {
// add the new item to items state
this.items.push(this.editedItem)
}
this.editedItem = {}
}
this.dialog = !this.dialog
})
},
deleteItem(item) {
let id = item.id
let idx = this.items.findIndex(item => item.id===id)
if (confirm('Are you sure you want to delete this?')) {
axios.delete(`https://api.airtable.com/v0/${airTableApp}/${airTableName}/${id}`,
{ headers: {
Authorization: "Bearer " + apiToken,
"Content-Type": "application/json"
}
}).then((response) => {
this.items.splice(idx, 1)
})
}
},
5.现在我们将连接包含用于编辑数据的表单输入框的对话框。它还包含一个用于创建记录的“新建”按钮。在...v-dialog
下方添加标记。v-data-table
<v-card>
<v-data-table
:headers="headers"
:items="items"
>
</v-data-table>
<!-- this dialog is used for both create and update -->
<v-dialog v-model="dialog">
<template v-slot:activator="{ on }">
<div class="d-flex">
<v-btn color="primary" dark v-on="on">
New
</v-btn>
</div>
</template>
<v-card>
<v-card-title>
<span v-if="editedItem.id">Edit {{editedItem.id}}</span>
<span v-else>Create</span>
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12" sm="4">
<v-text-field v-model="editedItem.Name" label="Name"></v-text-field>
</v-col>
<v-col cols="12" sm="8">
<v-text-field v-model="editedItem.Details" label="Details"></v-text-field>
</v-col>
<v-col cols="12" sm="12">
<v-text-field v-model="editedItem.URL" label="URL"></v-text-field>
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue" text @click="showEditDialog()">Cancel</v-btn>
<v-btn color="blue" text @click="saveItem(editedItem)">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-card>
6.然后,添加一个方法来切换对话框的显示:
methods: {
showEditDialog(item) {
this.editedItem = item||{}
this.dialog = !this.dialog
},
loadItems() {...},
7.接下来,自定义插槽模板,使其与编辑现有记录的方法v-data-table
item.actions
挂钩。同时添加一个图标/按钮。showEditDialog()
deleteItem()
<v-data-table
:headers="headers"
:items="items">
<template v-slot:item.actions="{ item }">
<div class="text-truncate">
<v-icon
class="mr-2"
@click="showEditDialog(item)"
color="primary"
>
mdi-pencil
</v-icon>
<v-icon
@click="deleteItem(item)"
color="pink"
>
mdi-delete
</v-icon>
</div>
</template>
</v-data-table>
成品😏是可用的 Vuetify + Airtable CRUD 示例。
请在评论中告诉我您对此的想法,并在此处获取完整的源代码:https://codeply.com/p/Vx4dDt5c9G/vuetify-crud-example
鏂囩珷鏉ユ簮锛�https://dev.to/codeply/build-a-simple-crud-app-with-airtable-api-vue-vuetify-5565