用 Alpine.js 构建一个 ajax 表单

一晃11月都要过去了,离22考研仅剩25天,很久没水文章了,水一篇~

不解释Alpine.js是啥了,感兴趣的小伙伴自行百度,类似轻量Vue框架吧?这篇教程就带着大家入门一下

首先,让我们建立一个像这样的常规联系表格:
表格
关键问题是我们如何将通过 ajax 发送数据并使用 Alpine 处理所有表单数据。 大家之前应该已经用 vanilla JS 或 jQuery 做过无数次了。常规方式必须通过引用获取所有元素,访问它们的值,然后发送数据。 Alpine可以使这项任务变得轻而易举,类似Vue和其他前端框架那样。

下面我们建立一个简单的表单(姓名、电子邮件、消息提交按钮)

<form action="/contact" method="POST" class="w-64 mx-auto">
    <div class="mb-4">
        <label class="block mb-2">Name:</label>
        <input type="text" name="name" class="border w-full p-1">
    </div>
    <div class="mb-4">
        <label class="block mb-2">E-mail:</label>
        <input type="email" name="email" class="border w-full p-1">
    </div>
    <div class="mb-4">
        <label class="block mb-2">Message:</label>
        <textarea name="message" class="border w-full p-1"></textarea>
    </div>
    <button class="bg-gray-700 hover:bg-gray-800 text-white w-full p-2">Submit</button>
</form>

这就是表单的基本 HTML 结构。 到目前为止,根本没有 javascript,它只是一个可以与页面重新加载一起使用的常规表单。 现在,让我们在上面撒一些 Alpine.js 。 如下所示:

<script>
    function contactForm() {
      return {
        formData: {
          name: '',
          email: '',
          message: ''
        },
      }
    }
</script>

然后你只需要在里面添加那个函数调用 x-data

<form action="/contact" method="POST" class="w-64 mx-auto" x-data="contactForm()">

现在,介绍一下 x-model 指令。 这个指令可以使输入元素与组件数据保持同步。 因为 formData 在组件范围内有对象,因此我们可以在输入和文本区域中使用它们,如下所示:

<form action="/contact" method="POST" class="w-64 mx-auto" x-data="contactForm()">
    <div class="mb-4">
      <label class="block mb-2">Name:</label>
      <input type="text" name="name" class="border w-full p-1" x-model="formData.name">
    </div>

    <div class="mb-4">
      <label class="block mb-2">E-mail:</label>
      <input type="email" name="email" class="border w-full p-1" x-model="formData.email">
    </div>

    <div class="mb-4">
      <label class="block mb-2">Message:</label>
      <textarea name="message" class="border w-full p-1" x-model="formData.message"></textarea>
    </div>
    <button class="bg-gray-700 hover:bg-gray-800 text-white w-full p-2">Submit</button>
</form>

在 vanilla JavaScript 中,可能必须使用类似的内容获取元素, getElementById 然后访问其值。 有了 x-model ,当输入 input 元素时,数据对象会自动更新为输入的任何内容。

现在,至于 ajax 部分,让我们只使用 fetch API ,因此我们不必拉外部依赖项,但您当然可以根据自己的需要进行调整:

function contactForm() {
    return {
        formData: {
            name: '',
            email: '',
            message: ''
        },
        message: '',

        submitData() {
            this.message = ''

            fetch('/contact', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(this.formData)
            })
            .then(() => {
                this.message = 'Form sucessfully submitted!'
            })
            .catch(() => {
                this.message = 'Ooops! Something went wrong!'
            })
        }
    }
}

并在表单结束标记之前添加此段落:

<p x-text="message"></p>

如果你不明白 .then and .catch 语句是 什么 ,别担心,你可以查看这篇关于 Promises 的 文章。基本上,整个 submitData 方法将对 /contact 路由执行 POST 请求 ,并将表单数据作为字符串化 JSON 传递。 如果一切都成功, .then 则执行块,如果响应中有错误,则执行 .catch

现在,我们必须在提交表单时调用此方法。 表单元素发出一个 submit 事件,所以我们可以使用 x-on 指令来监听它 ,因为我们不想重新加载页面,所以我们添加 .prevent 事件修饰符来“劫持”表单提交并使用我们自己的方法“submitData” :

<form action="/contact" method="POST" class="w-64 mx-auto" x-data="contactForm()" @submit.prevent="submitData">

就是这样! 这样就获得了一个使用 Alpine.js 构建的可工作的 ajax 表单 。 我们可以再加点东西,为提交按钮添加一些动态样式以改善用户体验:

在头部添加这个样式标签(我只会添加这个样式,因为到目前为止,TailwindCSS 不支持开箱即用的禁用状态 ):

<style>
    button:disabled {
      cursor: not-allowed;
      opacity: 0.5;
    }
</style>

现在,用这个替换旧的提交按钮:

<button class="bg-gray-700 hover:bg-gray-800 disabled:opacity-50 text-white w-full p-2 mb-4" x-text="buttonLabel" :disabled="loading"></button>

再介绍两个有趣的属性 x-text 指令和 :disabled 。我们将使用 x-text 来动态更改按钮的标签 :disabled ,并在提交表单时禁用该按钮。

contactForm 使用以下内容更新函数:

loading: false,
buttonLabel: 'Submit',

submitData() {
    this.buttonLabel = 'Submitting...'
    this.loading = true;
    this.message = ''

    fetch('/contact', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(this.formData)
    })
    .then(() => {
        this.message = 'Form sucessfully submitted!'
    })
    .catch(() => {
        this.message = 'Ooops! Something went wrong!'
    })
    .finally(() => {
        this.loading = false;
        this.buttonLabel = 'Submit'
    })
}

就是这样!

打赏
评论区
头像
    头像
    hou
      

    VUE做单页面太复杂了,还是直接用这个方便些,省得前后端反复定义路由