Neste guia, vamos percorrer o processo de criação, registro e uso de uma entrada personalizada. Especificamente, vamos criar uma entrada de "senha de uso único" ("OTP" para abreviar). As OTPs são comumente usadas para autenticação de dois fatores quando um usuário precisa digitar um código enviado via SMS ou aplicativo autenticador. Vamos começar!
Este guia pressupõe que você está usando uma ferramenta de construção Vue 3 padrão como Vite, Nuxt 3 ou Vue CLI que permitirá que você importe componentes de arquivo único .vue
.
Para começar, vamos criar o arquivo de componente da nossa entrada. Vamos chamá-lo de OneTimePassword.vue
:
<script setup>
const props = defineProps({
context: Object,
})
</script>
<template>
<div>Mais por vir aqui...</div>
</template>
O FormKit fornece muitos recursos de entrada prontos para uso que vamos querer preservar - como rótulos, texto de ajuda e exibição de mensagens de erro. Tudo o que realmente queremos modificar é a seção de entrada da nossa entrada. Podemos preservar esses recursos padrão do FormKit usando a função utilitária createInput
do pacote @formkit/vue
.
Conforme construímos nossa entrada, vamos querer visualizar seu progresso, então vamos criar um formulário de amostra para:
OneTimePassword.vue
createInput()
type
de um componente <FormKit>
.Vamos chamar este formulário de amostra de Register.vue
:
Excelente! Agora podemos iterar em nosso arquivo OneTimePassword.vue
e ver os resultados. Uma das primeiras coisas a notar é como nossa entrada já suporta rótulos, texto de ajuda, validação e outras props universais do FormKit. Esses recursos são cortesia de createInput()
.
Além disso, notou aquela tag <pre>
no exemplo acima? Ela está exibindo o estado atual dos dados do formulário. Vamos usar isso para visualizar o valor da nossa entrada personalizada. Como nossa entrada atualmente não tem valor, ela não aparece nos dados do formulário. Hora de mudar isso!
Vamos abrir OneTimePassword.vue
novamente e mudar nossa tag <div>
para uma tag <input>
. Vamos começar com uma única entrada de texto e evoluir a partir daí. Mas como realmente definimos e exibimos o valor da nossa entrada personalizada?
Todas as entradas personalizadas recebem o todo-poderoso objeto de contexto como a prop context
. Para que nossa entrada possa definir seu valor, ela precisa chamar context.node.input(value)
. Para exibir corretamente o valor da nossa entrada, devemos definir o atributo :value
da entrada para context._value
.
Nossa pequena entrada cresceu! Pode não parecer bonita, mas agora lê e escreve valores. Como prova, tente definir o valor inicial do objeto values
do formulário para { two_factor_code: '12345' }
e você verá que a entrada é preenchida automaticamente com o valor.
Ok, agora que entendemos como criar uma entrada, como usá-la e como ler e escrever valores - vamos abordar a verdadeira "lógica de negócios" de nossa entrada de senha única. Aqui estão nossos requisitos:
<input>
.Para nosso primeiro requisito, precisamos de n
tags <input>
. Talvez seja melhor expor o número de dígitos como uma prop. Para fazer isso, precisamos informar à nossa função createInput
que queremos aceitar uma nova prop:
createInput(OneTimePassword, {
props: ['digits'],
})
Agora temos acesso a context.digits
. De volta em OneTimePassword.vue
, vamos usar isso para gerar o número correto de tags <input>
.
OK — temos várias entradas! Nosso primeiro requisito está completo:
<input>
.Adicionamos um toque de CSS no exemplo acima, mas em geral não vamos nos aprofundar em estilização neste guia. É recomendado usar context.classes.yourKey
como o nome da classe dos elementos em sua entrada.
Perceba no exemplo acima que quando você digita em uma entrada, todas as outras entradas são sincronizadas com o mesmo valor? Bem legal, mas não é o que queremos. Isso ocorre porque ainda estamos usando o mesmo manipulador de entrada e :value
. Aqui está um plano para melhorar nossa entrada:
focus()
na próxima entrada.digits
, atualizamos o valor da entrada chamando context.node.input()
.Ótimo! Isso está começando a funcionar como esperamos. Vamos verificar nossos requisitos novamente:
<input>
.Parece que só temos uma coisa a fazer — suporte para copiar & colar. Felizmente, os navegadores possuem um evento paste
. Para garantir que nossa experiência do usuário seja de primeira linha, faremos uma suposição: se um usuário está copiando/colando, ele está tentando copiar e colar todo o código. Não um único dígito do código. Parece razoável.
Tudo o que precisamos fazer é capturar o evento de copiar/colar em qualquer uma de nossas tags de entrada, obter o texto que está sendo colado e definir o valor tmp
para essa sequência de dígitos. Vamos criar outro manipulador de eventos:
handlePaste(e) {
const paste = e.clipboardData.getData('text')
if (typeof paste === 'string') {
// Se for do tamanho certo, cole.
this.tmp = paste.substr(0, this.max)
const inputs = e.target.parentElement.querySelectorAll('input')
// Foca no último caractere
inputs.item(this.tmp.length - 1).focus()
}
}
Nossos requisitos estão todos completos!
Agora que criamos uma excelente entrada, vamos registrá-la em nossa aplicação para que possamos usá-la em qualquer lugar apenas usando a string otp
. Abra o arquivo principal da sua aplicação Vue (onde app.use(formKit)
está). Vamos apenas adicionar a ele:
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')
Pronto! Agora você pode usar sua entrada em qualquer lugar da sua aplicação:
<FormKit type="otp" digits="4" />
Nossa entrada de senha de uso único está funcionando muito bem! Aqui estão algumas ideias para recursos adicionais que poderíamos desenvolver ainda mais:
Esperamos que este guia tenha ajudado você a entender como as entradas personalizadas são declaradas, escritas e registradas. Se você quiser se aprofundar mais, tente ler sobre os princípios internos do FormKit e criando entradas personalizadas!