# 验证码输入

分格的一次性验证码输入。只写一个空的容器，格子由库生成；支持粘贴、退格回退、方向键。校验由你来做，用 ZhaoUI.otp 把结果显示出来。

**依赖**：`zhaoui.css` 与 `zhaoui.js`（原生 HTML、CSS、JS，不需要框架或 jQuery）。

## 用法

```html
<div id="otpLabel">输入 6 位验证码</div>
<div class="zh-otp" id="otp" data-length="6" aria-labelledby="otpLabel"></div>

<script>
document.getElementById('otp').addEventListener('zh:otp-complete', function (e) {
  // 换成你自己的校验
  if (e.detail.value === '123456') ZhaoUI.otp.ok('#otp'); else ZhaoUI.otp.error('#otp');
});
</script>
```

## 样式类

`zh-otp`、`zh-otp-cell`

## 属性

| 属性 | 用在 | 取值 | 说明 |
|---|---|---|---|
| `data-length` | .zh-otp | 整数，默认 6 | 验证码位数 |
| `aria-labelledby` | .zh-otp | 标签元素的 id | 容器会自动加 role="group"，用它给整组命名 |
| `is-error / is-ok` | .zh-otp | class | 由 ZhaoUI.otp.error / ok 设置，也会在用户再次输入时自动清除 |

## 方法

- `ZhaoUI.otp.value(el)`：读取当前已输入的内容
- `ZhaoUI.otp.error(el)`：标记为错误并播放抖动动画
- `ZhaoUI.otp.ok(el)`：标记为通过
- `ZhaoUI.otp.clear(el)`：清空所有格子并把焦点放回第一格

## 事件

| 事件 | 触发于 | detail | 说明 |
|---|---|---|---|
| `zh:otp-complete` | .zh-otp | { value } | 所有格子填满时触发（冒泡），value 是完整的验证码字符串 |

## 无障碍

- 每一格都有「第 N 位，共 M 位」的 aria-label；第一格带 autocomplete="one-time-code"，手机可以自动填入短信验证码
- 只接受数字，粘贴一串数字会从当前格开始依次填入
- ← → 在格子间移动，Home / End 到首尾，空格子里按退格会回到上一格并清空它
- el 参数可以是元素，也可以是选择器

## 常见问题

### 验证码输入是什么？

分格的一次性验证码输入。只写一个空的容器，格子由库生成；支持粘贴、退格回退、方向键。校验由你来做，用 ZhaoUI.otp 把结果显示出来。

### 怎么使用验证码输入？

先在页面里引入 zhaoui.css 和 zhaoui.js（放在 </body> 前，不加 defer），再照本页「用法」里的标记书写；需要用代码控制时，用「方法」里列出的接口。

### 验证码输入有哪些事件？

zh:otp-complete（所有格子填满时触发（冒泡），value 是完整的验证码字符串）。

### 验证码输入有哪些方法？

ZhaoUI.otp.value(el)：读取当前已输入的内容；ZhaoUI.otp.error(el)：标记为错误并播放抖动动画；ZhaoUI.otp.ok(el)：标记为通过；ZhaoUI.otp.clear(el)：清空所有格子并把焦点放回第一格。

### 验证码输入支持键盘和读屏吗？

每一格都有「第 N 位，共 M 位」的 aria-label；第一格带 autocomplete="one-time-code"，手机可以自动填入短信验证码；只接受数字，粘贴一串数字会从当前格开始依次填入；← → 在格子间移动，Home / End 到首尾，空格子里按退格会回到上一格并清空它。

### 验证码输入需要依赖框架吗？

不需要。ZhaoUI 是原生 HTML、CSS 和 JavaScript，不依赖 jQuery、Vue 或 React。
