naive-ui icon indicating copy to clipboard operation
naive-ui copied to clipboard

建议新增验证码输入组件

Open mattholy opened this issue 7 months ago • 1 comments

问题的清晰而简明的描述

验证码输入组件: image 接受一个长度参数,指示验证码长度,比如图中是6。 对外暴露一个结果值,以及输入事件、输入完成事件。

每次在输入框中完成输入后会自动focus到下一个输入框,全部输入完之后blur。如果删除一个输入就自动focus到上一个输入框。

建议的解决方案

类似于这样的东西:

<script setup lang="ts">
    import { ref, computed, watch, defineEmits, defineProps } from 'vue'
    import {
        NFlex, NInput
    } from 'naive-ui'
    import type { InputInst } from 'naive-ui'

    interface Props {
        length?: number
        code?: string
    }
    interface InputTarget {
        key: string
        ref: InputInst | null
        value: string
    }

    const props = defineProps<Props>()
    const emit = defineEmits(['update:code', 'complete'])

    const length = props.length ?? 6

    const inputs = ref<InputTarget[]>(Array.from({ length }, (_, index) => ({
        key: `input-${index}`,
        ref: null,
        value: ''
    })))

    const code = computed(() => inputs.value.map(input => input.value).join(''))

    const handleInput = (value: string, index: number) => {
        if (value.length === 1 && /^[a-zA-Z0-9]$/.test(value)) {
            inputs.value[index].value = value
            if (index < length - 1) {
                (inputs.value[index + 1].ref as InputInst)?.focus()
            } else {
                (inputs.value[index].ref as InputInst)?.blur()
                emit('complete', code.value)
            }
        } else if (value === '') {
            if (index > 0) {
                (inputs.value[index - 1].ref as InputInst)?.focus()
            }
        } else {
            inputs.value[index].value = value.slice(0, 1)
        }
    }

    watch(code, (newCode) => {
        emit('update:code', newCode)
    })
</script>

<template>
    <n-flex justify="space-around">
        <n-input v-for="(input, index) in inputs" :key="input.key"
            style="text-align: center; font-size: larger; width: 40px;" :maxlength="1" size="large" :show-button="false"
            placeholder="" v-model:value="input.value" @input="value => handleInput(value, index)"
            :ref="el => inputs[index].ref = el as unknown as InputInst"
            :allow-input="value => /^[a-zA-Z0-9]$/.test(value)" />
    </n-flex>
</template>

备选方案

No response

附加上下文

No response

验证

  • [X] 阅读 贡献指南
  • [X] 阅读 文档
  • [X] 检查是否已经存在请求相同功能的问题,以避免创建重复的问题。

mattholy avatar Aug 01 '24 05:08 mattholy