创建自定义输入框

在本指南中,我们将逐步介绍创建、注册和使用自定义输入框的过程。具体来说,我们将创建一个“一次性密码”输入框(简称 OTP)。OTP 通常用于双因素身份验证,用户需要输入通过短信或身份验证应用程序发送的代码。让我们开始吧!

SFC 构建工具

本指南假设您正在使用标准的 Vue 3 构建工具,如 Vite、Nuxt 3 或 Vue CLI,这些工具允许您导入 .vue 单文件组件。

创建组件

首先,让我们创建输入框的组件文件。我们将其命名为 OneTimePassword.vue

<script setup>
  const props = defineProps({
    context: Object,
  })
</script>

<template>
  <div>更多内容即将到来...</div>
</template>

FormKit 提供了许多开箱即用的输入框功能,我们希望保留这些功能,例如标签、帮助文本和显示错误消息。我们只需要修改输入框的输入部分。我们可以使用 @formkit/vue 包中的 createInput 实用函数来保留这些标准的 FormKit 功能。

在构建输入框时,我们希望能够可视化其进度,因此让我们创建一个示例表单:

  1. 导入 OneTimePassword.vue
  2. 将导入的组件传递给 createInput()
  3. 使用返回值(一个 输入框定义)作为 <FormKit> 组件的 type 属性。

我们将这个示例表单命名为 Register.vue

加载实时示例

太棒了!现在我们可以迭代我们的 OneTimePassword.vue 文件并查看结果。首先要注意的一件事是,我们的输入框已经支持标签、帮助文本、验证和其他通用的 FormKit 属性。这些功能都来自于 createInput()

此外,注意上面示例中的 <pre> 标签吗?它输出了表单数据的当前状态。我们将使用它来可视化自定义输入框的值。由于我们的输入框当前没有值,它不会出现在表单数据中。是时候改变这一点了!

输入和输出

让我们再次打开 OneTimePassword.vue,将我们的 <div> 改为 <input> 标签。我们将从一个单独的文本输入框开始,然后逐步增加功能。但是,我们如何设置和显示自定义输入框的值呢?

所有自定义输入框都会传递一个强大的 上下文对象 作为 context 属性。为了让我们的输入框能够 设置 其值,它需要调用 context.node.input(value)。为了正确地 显示 我们输入框的值,我们应该将输入框的 :value 属性设置为 context._value

加载实时示例

我们的小输入框已经长大了!它可能看起来不太好看,但它现在可以读取和写入值了。作为证明,尝试将表单的 values 对象的初始值设置为 { two_factor_code: '12345' },您将看到输入框自动填充了该值。

输入框的要求

好的,现在我们了解了如何创建输入框、如何使用它以及如何读取和写入值,让我们来解决实际的一次性密码输入框的“业务逻辑”。以下是我们的要求:

  • 用户输入一系列数字,每个数字都有自己的 <input> 标签。
  • 输入框的值应始终是所有数字的串联。
  • 只有在所有数字都已完成时(如果用户尚未完成,则无需在每次按键时提交和验证),输入框才会更改其值。
  • 它应允许用户单击给定的数字进行编辑。
  • 当用户键入数字时,它应自动聚焦到下一个输入框。
  • 它应支持复制/粘贴。

添加一个属性

对于我们的第一个要求,我们需要 n<input> 标签。也许将数字的数量作为一个属性暴露出来会更好。为此,我们需要告诉我们的 createInput 函数,我们想要接受一个新的属性:

createInput(OneTimePassword, {
  props: ['digits'],
})

现在我们可以访问 context.digits。回到 OneTimePassword.vue,让我们使用它来输出正确数量的 <input> 标签。

加载实时示例

好了 - 我们有了多个输入框!我们的第一个要求已经完成:

  • 用户输入一系列数字,每个数字都有自己的 <input> 标签。
样式

我们在上面的示例中添加了一些 CSS,但是在这个指南中我们不会深入讨论样式。建议使用 context.classes.yourKey 作为输入框中元素的类名。

互动性

请注意,在上面的示例中,当您在一个输入框中输入时,所有其他输入框都会同步为相同的值。这很好,但不是我们想要的。这是因为我们仍在使用相同的输入处理程序和 :value。下面是改进输入的计划:

  • 每个输入框只能修改最终字符串中相应索引处的字符。
  • 输入处理程序应调用 focus() 在下一个输入框上。
  • 当字符串的长度与 digits 相同时,我们通过调用 context.node.input() 来更新输入框的值。
加载实时示例

太棒了!这开始按照我们的预期工作。让我们再次检查我们的要求:

  • 用户输入一系列数字,每个数字都有自己的 <input> 标签。
  • 输入框的值应始终是所有数字的连接。
  • 我们只希望在完成所有数字后才更改输入框的值(如果用户尚未完成,则无需在每次按键时提交和验证)。
  • 它应允许用户单击某个数字进行编辑。
  • 当用户键入数字时,它应自动聚焦到下一个输入框。
  • 它应支持复制/粘贴。

复制和粘贴

看起来我们只剩下一件事要做 - 复制和粘贴支持。幸运的是,浏览器有一个 paste 事件。为了确保我们的用户体验是一流的,我们将做出一个假设:如果用户正在复制/粘贴,他们正在尝试复制和粘贴整个代码。而不是代码的单个数字。这似乎是合理的。

我们只需要在任何输入框上捕获复制/粘贴事件,获取正在粘贴的文本,并将 tmp 值设置为该数字字符串。让我们再次编写另一个事件处理程序:

handlePaste(e) {
  const paste = e.clipboardData.getData('text')
  if (typeof paste === 'string') {
    // 如果长度正确,则粘贴它。
    this.tmp = paste.substr(0, this.max)
    const inputs = e.target.parentElement.querySelectorAll('input')
    // 聚焦在最后一个字符上
    inputs.item(this.tmp.length - 1).focus()
  }
}
加载实时示例

我们的所有要求都已完成!

注册

现在,我们已经开发出了一个出色的输入框,让我们在应用程序中注册它,这样我们就可以在任何地方使用它,只需使用字符串 otp。打开您的 Vue 应用程序的主文件(其中包含 app.use(formKit))。我们只需添加以下内容:

import { createApp } from 'Vue'
import App from 'App.vue'
import OneTimePassword from './OneTimePassword.vue'
import { plugin, defaultConfig, createInput } from '@formkit/vue'

const app = createApp(App)
app.use(
  plugin,
  defaultConfig({
    inputs: {
      otp: createInput(OneTimePassword, {
        props: ['digits'],
      }),
    },
  })
)
app.mount('#app')

完成!现在您可以在应用程序的任何地方使用您的输入框:

<FormKit type="otp" digits="4" />

下一步

我们的一次性密码输入框工作得很好!以下是一些进一步完善的额外功能的想法:

  • 一个附带的验证规则,用于执行向后端的双因素身份验证调用。
  • 其他样式,使其更加突出。
  • 如果表单只包含一次性密码输入框,则可以自动提交表单!
  • 完成自定义输入框清单
  • 发布它!如果这个输入框(或您制作的任何其他输入框)对您有用,那么对其他人来说也可能有用。您可以考虑开源它!

希望本指南能帮助您了解如何声明、编写和注册自定义输入框。如果您想深入了解,请尝试阅读有关FormKit的核心内部创建自定义输入框的内容!

想了解更多?首先阅读有关FormKit核心的内容。深入了解