预览图


组件源码
父组件
<template><div class="google-verify-content"><p>{{ props.title }}</p><GoogleCode @finishCode="getGoogleCode" /><div class="login-modal-footer"><n-buttontype="tertiary"class="login-modal-btn"@click="$emit('closeModal')">取消</n-button><n-buttontype="primary"class="login-modal-btn"@click="submitCallback">{{ props.confirmText }}</n-button></div></div></template><script lang="ts" setup>import { ref } from "vue";const googleCode = ref("");let emit = defineEmits(["submitCallback", "closeModal"]);let props = defineProps({title: {type: String,default: "为保障系统信息和商户资金安全,请您进行谷歌验证",},confirmText: {type: String,default: "保存",},});function submitCallback() {emit("submitCallback", googleCode.value);}function getGoogleCode(val) {googleCode.value = val;}</script>
核心子组件-输入窗口
初始版本
<!--* @Date: 2022-03-02 14:20:28* @LastEditTime: 2022-03-09 17:36:41--><template><div v-bind="$attrs" class="goole-code-box"><div id="google-input" class="google-input-content" @click="state.canInput = true"><inputclass="input-item":class="{ active: state.canInput && state.inputCodeArr.length === index }"v-for="(item, index) in state.inputLengthArr":key="index"type="text"maxlength="1"@input="onChange($event, index)"@focus="state.focus = true"@blur="state.focus = false"v-model="item.content"/><slot name="get-code-btn"></slot></div></div></template><script lang="ts" setup>import { reactive, onMounted, onBeforeUnmount, watchEffect } from "vue";import _ from "lodash";let emit = defineEmits(["setGooglecode", "finishCode"]);let state = reactive({inputCodeArr: [],canInput: false,focus: false,inputLengthArr: [{id: 0,content: "",},{id: 1,content: "",},{id: 2,content: "",},{id: 3,content: "",},{id: 4,content: "",},{id: 5,content: "",},],});let keyMap = {48: "0",49: "1",50: "2",51: "3",52: "4",53: "5",54: "6",55: "7",56: "8",57: "9",};let props = defineProps({status: {type: Boolean,default: true,},});watchEffect(() => {if (state.inputCodeArr.length === 0) {state.inputLengthArr.forEach((item) => (item.content = ""));}if (!props.status && !state.focus) {console.log("失焦处理");state.canInput = false; //外部状态禁用}if (state.inputCodeArr.length) {state.inputLengthArr.forEach((item) => {if (item.id === state.inputCodeArr.length - 1) {item.content = state.inputCodeArr[item.id];}if (item.id > state.inputCodeArr.length - 1) {item.content = "";}});let outPut = state.inputCodeArr.join("");if (state.inputCodeArr.length === 6) {state.canInput = false;console.log("finishCode", outPut);emit("finishCode", outPut);}}});onMounted(() => {document.onkeydown = (e) => {var keyNum = window.event ? e.keyCode : e.which;if (!state.canInput) {return;}if (keyNum === 8) {// 删除键盘state.inputCodeArr.pop();let outPut = state.inputCodeArr.join("");console.log(outPut, "outPut");emit("setGooglecode", outPut);return;}if (state.inputCodeArr.length === 6) {state.canInput = false;return;}// 数字监听if (keyMap[keyNum] && state.inputCodeArr.length <= 6) {console.log("你输入了" + keyMap[keyNum], state.inputLengthArr);state.inputCodeArr.push(keyMap[keyNum]);let outPut = state.inputCodeArr.join("");emit("setGooglecode", outPut);}};});onBeforeUnmount(() => {document.onkeydown = null;});const onChange = (event, index) => {console.log(event, index);};</script>
- fixed 双数组难以维护的问题
- 聚焦后无法让下个数组窗口自动聚焦
- 输入完毕后,修改之前输入窗口的值, 聚焦值和改动值同时改变
版本v1.01
<!--* @Date: 2022-03-02 14:20:28* @LastEditTime: 2022-04-01 16:37:11--><template><div v-bind="$attrs" class="goole-code-box"><divid="google-input"class="google-input-content"><inputclass="input-item":id="nameId(index)":class="{ active: state.focusIndex === index }"v-for="(item, index) in state.inputLengthArr"type="text"maxlength="1"@input="onChange($event, index)"@focus="getFocus($event, index)"v-model="item.content"/><slot name="get-code-btn"></slot></div></div></template><script lang="ts" setup>import { reactive } from "vue";import _ from "lodash";let emit = defineEmits(["finishCode"]);let state = reactive({focusIndex: 0,inputLengthArr: [{id: 0,content: "",},{id: 1,content: "",},{id: 2,content: "",},{id: 3,content: "",},{id: 4,content: "",},{id: 5,content: "",},],});/*** @description: 聚焦问题修改* @param {*} event* @param {*} index* @return {*}*/function getFocus(event, index) {state.focusIndex = index;}function submitGoogle() {let virfyLength = _.sumBy(state.inputLengthArr, "content");console.log("finishCode", virfyLength);emit("finishCode", virfyLength);}/*** @description: 焦点自动获取优化* @param {*} event* @param {*} index* @return {*}*/function onChange(event, index) {if (event.data) {document.getElementById(nameId(index + 1))?.focus();state.focusIndex = index + 1;} else {if (index === 0) return;document.getElementById(nameId(index - 1))?.focus();state.focusIndex = index - 1;}let virfyLength = _.sumBy(state.inputLengthArr, "content");if (virfyLength.length === 6) {submitGoogle();}}function nameId(index) {return "googel-input" + index;}</script><style lang="scss" scoped>.goole-code-box {width: 100%;.google-input-content {display: flex;justify-content: space-between;flex-wrap: nowrap;input.input-item {background: var(--n-close-color-hover);border-radius: 8px 8px 8px 8px;opacity: 0.3;text-align: center;outline: none;height: 0.75rem;width: 0.75rem;font-size: 30px;color: #ffffff;border: none;}input.active {border: 2px solid $default-primary !important;-moz-box-shadow: 1px 1px 7px var(--n-color-hover);-webkit-box-shadow: 1px 1px 7px var(--n-color-hover);box-shadow: 1px 1px 7px var(--n-color-hover);}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {// chrome-webkit-appearance: none;appearance: none;margin: 0;}input {// 火狐-moz-appearance: textfield;}}}</style>

- v1.01保证正常功能使用,但在实际场景中存在使用问题
- 没有一键复制功能
版本v2.01
<template><div v-bind="$attrs" class="goole-code-box"><divid="google-input"class="google-input-content"><inputclass="input-item":id="nameId(index)":class="{ active: state.focusIndex === index }"v-for="(item, index) in state.inputLengthArr"type="text"maxlength="1"autocomplete="off":onkeydown="onkeydown"@input="onChange($event, index)"@focus="getFocus($event, index)"v-model="item.content"/><slot name="get-code-btn"></slot></div></div></template>
<script lang="ts" setup>import { reactive } from "vue";import { readClipboard, clearClipboard } from "@/utils/copy";import _ from "lodash";let emit = defineEmits(["finishCode"]);let state = reactive({focusIndex: 0,inputLengthArr: [{id: 0,content: "",},{id: 1,content: "",},{id: 2,content: "",},{id: 3,content: "",},{id: 4,content: "",},{id: 5,content: "",},],});clearClipboard();function readCode() {readClipboard().then((res) => {let boardStr = res;if (boardStr.length === 6) {emit("finishCode", boardStr);state.inputLengthArr.forEach((item, index) => {item.content = boardStr.charAt(index);});}}).catch((err) => console.warn(err));}/*** @description: 聚焦问题修改* @param {*} event* @param {*} index* @return {*}*/function getFocus(event:Event, index:number) {if (index === 0) {readCode();}state.focusIndex = index;}function onkeydown(event:Event) {if (state.focusIndex === 0) return true;if( event.keyCode === 8) {clearClipboard();}console.log(event.keyCode , state.inputLengthArr[state.focusIndex]);if (state.inputLengthArr[state.focusIndex].content === "" &&event.keyCode === 8) {document.getElementById(nameId(state.focusIndex - 1))?.focus();state.focusIndex = state.focusIndex - 1;}}function submitGoogle() {let virfyLength = _.sumBy(state.inputLengthArr, "content");emit("finishCode", virfyLength);}/*** @description: 焦点自动获取优化* @param {*} event* @param {*} index* @return {*}*/function onChange(event, index) {if (event.data) {document.getElementById(nameId(index + 1))?.focus();state.focusIndex = index + 1;} else {if (index === 0) return;document.getElementById(nameId(index - 1))?.focus();state.focusIndex = index - 1;}let virfyLength = _.sumBy(state.inputLengthArr, "content");if (virfyLength.length === 6) {submitGoogle();}}function nameId(index) {return "googel-input" + index;}</script>
依赖自定义工具函数-一键复制(原生)
关于复制到粘贴板
