如何在nuxt.js应用中使用appwrite云数据库
#javascript #教程 #vue #nuxt

Appwrite是一个开源且安全的后端,即服务平台,具有数据库函数和其他核心API,用于构建用于Web,Mobile和Flutter开发人员的类似服务器的应用程序。 AppWrite与客户端和服务器端编程语言集成。

Appwrite Cloud提供与AppWrite相同的服务,例如功能,身份验证,数据库,存储等。使用AppWrite Cloud,所有内容都是从专用URL而不是在Docker上运行的本地实例来管理的。

本教程将向您展示如何在NUXTJ中构建创建,读取,更新和删除(CRUD)应用程序,使用AppWrite Cloud和Pink Design适合前端开发人员。

项目概况

在本课程结束时,CRUD应用程序应该看起来像这样:

Tooodooos app

github和emo

this repo中检查此项目的完整源代码。另外,尝试演示here

先决条件

完成本教程需要以下内容:

  • 对JavaScript,Vue和CSS的理解
  • Node >= 16用于依赖项安装
  • 访问AppWrite Cloud帐户

加入并提交appwrite cloud here的请求。

设置appwrite云

登录到AppWrite Cloud,并通过单击“+创建项目”按钮在云实例中创建一个新项目。

create project

ps:确保给项目一个理想的名称。

创建一个数据库

导航到创建的项目,单击窗口左窗格上的数据库,并给您的数据库一个名称。

TooodooosDB

创建收藏

AppWrite使用集合作为文档容器。通过单击创建的数据库名称,单击创建Collection 按钮并给出集合一个名称。

Collections

添加属性

创建字段参数至关重要,因为它们将保存数据库中的所有注册数据。要创建属性,请导航到创建的集合,然后单击属性选项卡。对于本教程,属性如下:

属性键 属性类型 大小 默认值 必需
todo 字符串 255 -

create attribute

接下来,在集合中选择设置选项卡,然后更新权限以管理用户的访问和权利。

Permissions

最后,注册您的Web应用程序。单击概述左窗格上的选项卡,然后添加Web应用程序平台

Register your web app

主机名带有星号(*)确保在开发过程中访问;否则,如果未设置,交叉原始资源共享(CORS)可能会阻止访问网站数据,从而丢弃错误。

脚手架nuxt应用程序

nuxt是建立在VUE之上的渐进开源框架。让S支架使用以下命令:

    npx nuxi init todo

按照说明进行操作,并运行像yarn install这样的提供的命令。此命令将安装所有必需的依赖项。

接下来,导航到项目目录,然后 todos ****,然后在终端中启动开发服务器:

    cd todos && yarn dev

Nuxt app

安装依赖项

如前所述,您需要NUXT应用中的这两个依赖项:appwrite和appwrite pink Design。

在您的终端中,运行此命令:

    yarn add appwrite
    yarn add @appwrite.io/pink

包括appwrite pink中的粉红色

在您看到AppWrite CSS及其图标的动作之前,让我们在应用程序的根目录中创建页面文件夹。之后,创建一个文件,index.vue,****并添加以下代码。

pages/index.vue

    <template>
      <p class="heading-level-1">Add tooodooos</p>
    </template>

    <script setup lang="ts">
    import "@appwrite.io/pink";
    import "@appwrite.io/pink-icons";
    </script>

接下来,在项目的输入点app.vue中,将组件NuxtWelcome更改为NuxtPage

app.vue

    <template>
      <NuxtPage />
    </template>

在此结果确认AppWrite CSS库正在工作:

Heading 1 class to text

项目树目录应该看起来像这样:

    .
    ├── pages
    │   └── index.vue
    ├── public
    ├── package.json
    ├── tsconfig.json
    ├── yarn.lock
    ├── README.md
    ├── nuxt.config.js
    └── app.vue

构建UI

Todos应用程序的用户界面将展示使用输入字段创建的所有托多斯,并使用编辑和删除图标列出所有播放。

现在,让我们使用称为组件 的新目录更新应用程序目录,其中将包括以下文件:AboutTodo.vueHeader.vueListTodo.vueTodos.vue。另外,在名为about.vue的页面文件夹中创建另一个文件。

更新的项目树目录:

    .
    ├── components
    │   ├── AboutTodo.vue
    │   ├── Header.vue
    │   ├── ListTodo.vue
    │   └── Todos.vue
    ├── pages
    │   ├── about.vue
    │   └── index.vue
    ├── public
    ├── package.json
    ├── tsconfig.json
    ├── yarn.lock
    ├── README.md
    ├── nuxt.config.js
    └── app.vue

在文件组件中包括以下代码:

components/AboutTodo.vue

    <template>
      <div class="container">
        <h2 class="eyebrow-heading-2">About Tooodooos</h2>
        <p class="text" :style="{ 'margin-top': 1 + 'rem' }">
          Using Appwrite functions and Appwrite Cloud, adding todos have become
          simpler for anyone wanting to create their own. Appwrite as a tool is a
          backend-as-a-service platform.
        </p>
        <p class="text" :style="{ 'margin-top': 1 + 'rem' }">
          The technology used to build this app is Nuxt, Appwrite Pink for the
          design system, and integrating Appwrite of course.
        </p>
      </div>
    </template>

abouttodo 组件将在单击导航栏中单击“导航到/大约页面”。

上面的代码使用AppWrite粉红色设计将关于页面的内容集中。该组件中还包括Vue style bindings<p>元素中,该元素设置了1REM的最高边距。

components/Header.vue

    <template>
      <header
        class="u-flex u-main-space-between u-cross-center u-position-sticky"
        style="--inset-block-start: auto">
        <NuxtLink to="/" class="u-bold">Tooodooos</NuxtLink>
        <ul class="list">
          <li class="list-item">
            <span class="text">
              <NuxtLink to="/about">About</NuxtLink>
            </span>
          </li>
        </ul>
      </header>
    </template>

上面的代码片段使用AppWrite的粉红色 display list 元素来设置导航栏。还包括 nuxtlink 组件,分别用于导航到家庭和大约页面。

components/ListTodo.vue

    <template>
      <div class="u-flex u-main-space-between u-cross-center u-width-full-line">
        <span class="text">{{ item }}</span>
        <div class="u-cursor-pointer">
          <span
            class="icon-pencil"
            aria-hidden="true"
            :style="{ 'margin-right': space + 'em' }"></span>
          <span class="icon-trash" aria-hidden="true"></span>
        </div>
      </div>
    </template>

    <script setup>
    const props = defineProps({
      item: String,
    });

    const space = ref("1");
    </script>

上面的代码显示了 props 数组的待办事项列表项目以及粉红色设计的铅笔和垃圾图标。

components/Todos.vue

    <template>
      <div class="container">
        <Header />
        <h1 class="heading-level-1" :style="{ 'margin-top': 1 + 'rem' }">
          {{ name }}
        </h1>
        <form
          class="form u-width-full-line u-max-width-500 u-flex u-main-center"
          :style="{ 'margin-top': 1 + 'em' }">
          <ul class="form-list">
            <li class="form-item">
              <label class="label">Todo</label>
              <div class="input-text-wrapper">
                <input
                  class="input-text"
                  type="text"
                  placeholder="add new todo"
                  v-model="input.todo" />
              </div>
            </li>
          </ul>
          <button class="button" :style="{ 'margin-top': 1 + 'em' }">
            <span class="text">Add todo</span>
          </button>
        </form>
        <div :style="{ 'margin-top': marginTop + 'em' }">
          <ul class="list">
            <li class="list-item">
              <list-todo item="Create API documentation" />
            </li>
          </ul>
        </div>
      </div>
    </template>

    <script setup>
    const name = ref("Add tooodooos");

    const marginTop = ref("3");

    const input = reactive({
      todo: "",
    });
    </script>

以下内容在上面的代码段中发生:

  • 在脚本部分中,使用构图API
  • 声明变量
  • <template>中传递这些值
  • 导入标题 list-todo 组件
  • 使用粉红色设计中的类并定义了:style绑定到元素
  • 项目传递给列表-DODO组件

pages/about.vue

    <template>
      <div class="container">
        <Header />
        <about-todo />
      </div>
    </template>

该代码负责导入 header aid-todo 组件以显示关于页面的内容。

创建环境变量

由于已部署的项目在GitHub上公开可用,因此可以创建一个本地文件.env,其中包括您所有的秘密键和常数。

在nuxt.js应用中创建环境变量的this guide

发布新的汤do到appwrite云

创建,读取,更新和删除中的create操作( crud)将使用HTTP协议方法, post ,这可能意味着创建一个新列表,任务,或张贴。此操作将将此请求发送到数据库AppWrite Cloud。

现在,使用以下代码更新 todos 组件:

components/Todos.vue

    <template>
      <div class="container">
        <Header />
        <h1 class="heading-level-1" :style="{ 'margin-top': 1 + 'rem' }">
          {{ name }}
        </h1>
        <form
          class="form u-width-full-line u-max-width-500 u-flex u-main-center"
          :style="{ 'margin-top': 1 + 'em' }"
          @submit.prevent="handleInputChange">
          <ul class="form-list">
            <li class="form-item">
              <label class="label">Todo</label>
              <div class="input-text-wrapper">
                <input
                  class="input-text"
                  type="text"
                  :placeholder="inputError ? 'please enter a todo' : 'add new todo'"
                  v-model="input.todo" />
              </div>
            </li>
          </ul>
          <button class="button" :style="{ 'margin-top': 1 + 'em' }">
            <span class="text">Add todo</span>
          </button>
        </form>
        <div :style="{ 'margin-top': marginTop + 'em' }">
          <ul class="list">
            <li class="list-item">
              <list-todo item="Create API documentation" />
            </li>
          </ul>
        </div>
      </div>
    </template>

    <script setup>
    import { Client, Databases, ID } from "appwrite";

    const client = new Client();
    const databases = new Databases(client);

    const runtimeConfig = useRuntimeConfig();

    client
      .setEndpoint(runtimeConfig.public.API_ENDPOINT)
      .setProject(runtimeConfig.public.PROJECT_ID);

    const name = ref("Add tooodooos");

    const marginTop = ref("3");

    const input = reactive({
      todo: "",
    });

    const inputError = ref(false);

    const create = (data) =>
      databases.createDocument(
        runtimeConfig.public.DATABASE_ID,
        runtimeConfig.public.COLLECTION_ID,
        ID.unique(),
        data
      );

    const handleInputChange = () => {
      if (!input.todo) {
        return (inputError.value = true);
      }
      create({
        todo: input.todo,
      }).then(
        function (response) {
          window.location.reload();
        },
        function (error) {
          console.log(error);
        }
      );
    };
    </script>

以下在此代码段中发生:

  • 导入AppWrite软件包并初始化Web SDK的新实例
  • 使用useRuntimeConfig(),您可以访问环境变量
  • inputError变量设置为false有助于检查用户试图通过绑定:placeholder属性发送空输入字段的错误
  • 带有参数的create函数 data 是在appwrite cloud ****中连接属性键, todo 使用指令在<input>元素中传递的值v-model
  • 使用@submit.prevent指令传递给<form>的函数handleInputChange将在输入字段中将键入值发送到AppWrite Server
  • 添加了每一个新的todo,页面刷新带有window.location.reload()函数

显示所有招待列表

本节使用读取操作。

再次使用此代码更新Todos组件:

components/Todos.vue

    <template>
      <div class="container">
        <Header />
        <h1 class="heading-level-1" :style="{ 'margin-top': 1 + 'rem' }">
          {{ name }}
        </h1>
        <form
          class="form u-width-full-line u-max-width-500 u-flex u-main-center"
          :style="{ 'margin-top': 1 + 'em' }"
          @submit.prevent="handleInputChange">
          <ul class="form-list">
            <li class="form-item">
              <label class="label">Todo</label>
              <div class="input-text-wrapper">
                <input
                  class="input-text"
                  type="text"
                  :placeholder="inputError ? 'please enter a todo' : 'add new todo'"
                  v-model="input.todo" />
              </div>
            </li>
          </ul>
          <button class="button" :style="{ 'margin-top': 1 + 'em' }">
            <span class="text">Add todo</span>
          </button>
        </form>
        <div :style="{ 'margin-top': marginTop + 'em' }">
          <ul class="list">
            <li class="list-item" v-for="item in todos" :key="item.$id">
              <list-todo :item="item" />
            </li>
          </ul>
        </div>
      </div>
    </template>
    <script setup>
    ...

    const todos = ref(null);

    const getTodo = databases.listDocuments(
      runtimeConfig.public.DATABASE_ID,
      runtimeConfig.public.COLLECTION_ID
    );

    onMounted(() => {
      getTodo.then(
        function (response) {
          todos.value = response.documents;
        },
        function (error) {
          console.log(error);
        }
      );
    });
    </script>

上面的代码负责以下内容:

  • getTodo功能负责列出onMounted lifecycle钩中应用程序中的所有todo项目
  • 使用
  • 元素上的v-for指令循环循环,并用 v-bind替换先前的项目道具:item :项目 list-todo上的属性 component

更新待办事项

纠正列表项目(TODOS)对于使用 Update 操作的任何CRUD应用程序至关重要。复制 - 此更新的代码:

components/ListTodo.vue

    <template>
      <div class="u-flex u-main-space-between u-cross-center u-width-full-line">
        <span class="text">{{ item.todo }}</span>
        <div class="u-cursor-pointer">
          <span
            class="icon-pencil"
            aria-hidden="true"
            @click.prevent="showModal = !showModal"
            :style="{ 'margin-right': space + 'em' }"></span>
          <span class="icon-trash" aria-hidden="true"></span>
        </div>
      </div>
      <div
        v-if="showModal"
        class="u-z-index-20 u-padding-24"
        :style="{
          position: 'fixed',
          top: '0',
          right: 0,
          left: 0,
          bottom: 0,
          'background-color': 'rgba(0, 0, 0, 0.8)',
          height: '100vh',
        }">
        <form
          class="form u-width-full-line u-max-width-500 u-flex u-main-center"
          @submit.prevent="handleUpdateTodo">
          <ul class="form-list">
            <li class="form-item">
              <label class="label" :style="{ color: 'white' }">Edit todo</label>
              <div class="input-text-wrapper">
                <input
                  class="input-text"
                  type="text"
                  v-model="item.todo" />
              </div>
            </li>
          </ul>
          <button class="button" :style="{ 'margin-top': 1 + 'em' }">
            <span class="text">Update todo</span>
          </button>
        </form>
        <div class="u-cursor-pointer">
          <span
            class="icon-x u-font-size-32"
            @click.prevent="showModal = !showModal"
            aria-hidden="true"
            :style="{
              position: 'absolute',
              top: '0',
              right: '1em',
              color: '#fff',
            }"></span>
        </div>
      </div>
    </template>

    <script setup>
    import { Client, Databases } from "appwrite";

    const client = new Client();
    const databases = new Databases(client);

    const runtimeConfig = useRuntimeConfig();

    client
      .setEndpoint(runtimeConfig.public.API_ENDPOINT)
      .setProject(runtimeConfig.public.PROJECT_ID);

    const props = defineProps({
      item: Object,
    });

    const space = ref("1");

    const showModal = ref(false);

    const updateTodo = (database_id, collection_id, document_id, data) =>
      databases.updateDocument(database_id, collection_id, document_id, data);

    const handleUpdateTodo = () => {
      updateTodo(props.item.$databaseId, props.item.$collectionId, props.item.$id, {
        todo: props.item.todo,
      }).then(
        function (response) {
          console.log(`${props.item.todo} successfully updated in DB`);
        },
        function (error) {
          console.log("Error updating the document", error.message);
        }
      );
    };
    </script>

此代码片段旨在更新文档的唯一ID。使用补丁方法,它仅更新部分数据:

  • 可变showModal通过单击铅笔图标
  • 填充模态
  • handleUpdateTodo函数中,用键 todo 传递对象,并在 中传递的值,以使用指令, v-model显示确切的数据

删除待办事项清单

此CRUD应用程序的最后一个操作是使用 delete 方法从客户端和服务器中删除数据。

让S以下代码更新 listTodo 组件:

components/ListTodo.vue

    <template>
      <div class="u-flex u-main-space-between u-cross-center u-width-full-line">
        <span class="text">{{ item.todo }}</span>
        <div class="u-cursor-pointer">
          <span
            class="icon-pencil"
            aria-hidden="true"
            @click.prevent="showModal = !showModal"
            :style="{ 'margin-right': space + 'em' }"></span>
          <span
            class="icon-trash"
            aria-hidden="true"
            @click.prevent="handleDeleteTodo"></span>
        </div>
      </div>
      <div
        v-if="showModal"
        class="u-z-index-20 u-padding-24"
        :style="{
          position: 'fixed',
          top: '0',
          right: 0,
          left: 0,
          bottom: 0,
          'background-color': 'rgba(0, 0, 0, 0.8)',
          height: '100vh',
        }">
        <form
          class="form u-width-full-line u-max-width-500 u-flex u-main-center"
          @submit.prevent="handleUpdateTodo">
          <ul class="form-list">
            <li class="form-item">
              <label class="label" :style="{ color: 'white' }">Edit todo</label>
              <div class="input-text-wrapper">
                <input class="input-text" type="text" v-model="item.todo" />
              </div>
            </li>
          </ul>
          <button class="button" :style="{ 'margin-top': 1 + 'em' }">
            <span class="text">Update todo</span>
          </button>
        </form>
        <div class="u-cursor-pointer">
          <span
            class="icon-x u-font-size-32"
            @click.prevent="showModal = !showModal"
            aria-hidden="true"
            :style="{
              position: 'absolute',
              top: '0',
              right: '1em',
              color: '#fff',
            }"></span>
        </div>
      </div>
    </template>

    <script setup>
    ...

    const deleteTodo = (database_id, collection_id, document_id) =>
      databases.deleteDocument(database_id, collection_id, document_id);

    const handleDeleteTodo = () => {
      deleteTodo(
        props.item.$databaseId,
        props.item.$collectionId,
        props.item.$id
      ).then(
        function (response) {
          window.location.reload();
        },
        function (error) {
          console.log(error);
        }
      );
    };
    </script>

handleDeleteTodo函数删除了一个带有唯一ID的todo项目,并在@click evert the <span> delete delete iCON上使用 @click evert。

在这一点上,UI看起来像这样:

Todo demo

结论

本教程向您展示了如何构建todo crud应用程序并将其功能与AppWrite Cloud配对以创建,存储,更新和删除客户端和服务器。

资源