123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- <template>
- <view class="code-box">
- <view class="flex-box">
- <input
- type="number"
- focus="true"
- :maxlength="maxlength"
- class="hide-input"
- v-model="inputData.code"
- @input="getVal"
- />
- <view v-for="(item, index) in maxlength" :key="item">
- <view
- :class="[
- 'item',
- {
- active: codeIndex === item,
- middle: type === 'middle',
- bottom: type === 'bottom',
- box: type === 'box',
- },
- ]"
- >
- <view class="line" v-if="type !== 'middle'" />
- <view
- v-if="type === 'middle' && codeIndex <= item"
- class="bottom-line"
- />
- <view v-if="isPwd && inputData.codeArr.length >= item">
- <text class="dot">*</text>
- </view>
- <view v-else>
- {{ inputData.codeArr[index] ? inputData.codeArr[index] : "" }}
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
-
- <script setup lang="ts">
- import { reactive, ref } from "vue";
- const props = defineProps({
- maxlength: {
- type: Number,
- default: 6,
- },
- isPwd: {
- type: Boolean,
- default: false,
- },
- // middle-middle line, bottom-bottom line, box-square box
- type: {
- type: String,
- default: "bottom",
- },
- modelValue: {
- type: Number,
- },
- });
- const emit = defineEmits(["update:modelValue"]);
- const flexWidth = 80 / props.maxlength + "%";
- const inputData = reactive({
- codeArr: [] as Array<number>,
- code: null,
- });
- const codeIndex = ref(1);
-
- const getVal = (e) => {
- let { value } = e.detail;
- let arr: Array<number> = value.split("");
- codeIndex.value = arr.length + 1;
- inputData.codeArr = arr;
-
- if (codeIndex.value > Number(props.maxlength)) {
- emit("update:modelValue", inputData.code);
- }
- };
- </script>
-
- <style lang="scss" scoped>
- @keyframes twinkling {
- 0% {
- opacity: 0.2;
- }
- 50% {
- opacity: 0.5;
- }
- 100% {
- opacity: 0.2;
- }
- }
- .code-box {
- text-align: center;
- }
- .flex-box {
- display: flex;
- justify-content: space-evenly;
- flex-wrap: wrap;
- position: relative;
- }
- .flex-box .hide-input {
- position: absolute;
- top: 0;
- left: -100%;
- width: 200%;
- height: 100%;
- text-align: left;
- z-index: 9;
- opacity: 1;
- }
- .flex-box .item {
- position: relative;
- width: 106rpx;
- height: 100rpx;
- font-size: 46rpx;
- color: #333333;
- line-height: 100rpx;
- }
- .flex-box .item:last-child {
- margin-right: 0rpx;
- }
- .flex-box .middle {
- border: none;
- }
- .flex-box .box {
- box-sizing: border-box;
- border: 2rpx solid #dcdcdc;
- border-radius: 6rpx;
- }
- .flex-box .bottom {
- box-sizing: border-box;
- border-bottom: 1rpx solid #dcdcdc;
- }
- .flex-box .active {
- border-color: #00b38b;
- }
- .flex-box .active .line {
- display: block;
- }
-
- .flex-box .line {
- display: none;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- width: 2rpx;
- height: 50rpx;
- background: #333333;
- animation: twinkling 1s infinite ease;
- }
- .flex-box .dot {
- font-size: 80rpx;
- line-height: 40rpx;
- }
- .flex-box .bottom-line {
- height: 1rpx;
- background: #dcdcdc;
- width: 80%;
- position: absolute;
- border-radius: 2px;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
- </style>
|