美文网首页
验证码code组件

验证码code组件

作者: 曼珠沙华_521b | 来源:发表于2020-03-17 15:25 被阅读0次
<template>
    <div>
        <div class="code-number-wrap">
            <div  :ref="`codeItem${item}`" v-text="cellText[index]" @keyup="keyupHandler(item,$event)" v-for="(item, index) in len" :key="index" :tabindex="item" class="code-item" contenteditable="true" ></div>
        </div>
    </div>
</template>
<script lang='ts'>
import { Component, Prop, Vue, Watch, Model } from 'vue-property-decorator';

@Component
export default class CodeNumber extends Vue {
    @Prop({ type: Number, default: 0 }) length!: number;
    @Prop({ type: String, default: 'cert' }) type!: string; // cert 身份证 validate 短信验证码
    @Model('change', { type: String }) value!: string;
    private len: number[] = [];
    private cellText: string[] = ['', '', '', ''];
    @Watch('length', { immediate: true, deep: true })
    private lengthWatcher(val: number) {
        if (typeof val === 'number') {
            this.len = [];
            for (let i = 0; i < val; i++) {
                this.len.push(i + 1);
            }
        }
    }
    @Watch('value', { immediate: true, deep: true })
    private valueChangeHandle(val:string) {
        this.cellText = val.split('');
    }
    private isNumberKey(code:string):boolean {
        // 是否是数字键
        return /\d+/.test(code);
        // return !(code.indexOf('Digit') === -1 && code.indexOf('Numpad') === -1);
    }
    private keyupHandler(index: number, $event: any) {
        let curEls: any = this.$refs[`codeItem${index}`];
        let targetEl = curEls[0]; // 当前单元格
        let currentCellText = targetEl.innerText;
        if ($event.keyCode === 8 || $event.keyCode === 46) {
            // 删除逻辑
            this.cellText[index - 1] = '';
            this.$emit('change', this.cellText.join(''));
            if (index === 1) return;
            let preEl = (this.$refs[`codeItem${index - 1}`] as any)[0];
            preEl.focus();
            this.cursorBackEnd(preEl); // 下个单元格光标后置
            return;
        }
        if (!/^\d*$/g.test(currentCellText) && index !== this.length) {
            // 单元格内容非数字,则清空
            targetEl.innerText = '';
            currentCellText = '';
        }
        if (index === this.length && this.type === 'cert') { // 身份证类型最后一位可以为X or x or 数字
            if (currentCellText.toLowerCase() !== 'x' && !/^\d*$/g.test(currentCellText)) {
                targetEl.innerText = '';
                currentCellText = '';
            }
        }
        if (index === this.length && this.type === 'validate' && !/^\d*$/g.test(currentCellText)) { // 身份证类型最后一位可以为X or x or 数字
            targetEl.innerText = '';
            currentCellText = '';
        }
        // let code:string = ($event.code || $event.keyCode).toString();
        if ((!this.isNumberKey(currentCellText) && index !== this.length) || (!this.isNumberKey(currentCellText) && index === this.length && this.type === 'validateCode')) return; // 非数字类型的按键 直接return
        if (currentCellText.length === 0) return; // 如果单元格内容为空不执行下个单元格的focus
        this.cellText[index - 1] = currentCellText.slice(0, 1);
        // 单元格内容超过一个字符时,才执行下行逻辑
        currentCellText.length > 1 &&
            (targetEl.innerText = currentCellText.slice(0, 1));
        this.$emit('change', this.cellText.join(''));

        if (index === this.length) {
            targetEl.blur();
            return; // 最后一个单元格不执行下个单元格的focus
        }
        let nextEls: any = this.$refs[`codeItem${index + 1}`];
        let nextTargetEl = nextEls[0]; // 下一个单元格
        nextTargetEl.focus();
        this.cursorBackEnd(nextTargetEl); // 下个单元格光标后置
    }
    private cursorBackEnd(targetEl: any) {
        // 单元格内光标后置
        let range: any;
        if (window.getSelection) {
            // ie11 10 9 ff safari
            range = window.getSelection(); // 创建range
            range.selectAllChildren(targetEl); // range 选择obj下所有子内容
            range.collapseToEnd(); // 光标移至最后
        } else if ((document as any).selection) {
            // ie10 9 8 7 6 5
            range = (document as any).selection.createRange(); // 创建选择对象
            range.moveToElementText(targetEl); // range定位到obj
            range.collapse(false); // 光标移至最后
            range.select();
        }
    }
    created() {
        this.cellText = this.value.split('');
    }
    mounted() {
        // 初始化光标在第一个位置
        let index = 1;
        let curEls: any = this.$refs.codeItem1;
        let targetEl = curEls[0]; // 当前单元格
        targetEl.focus();
    }
}
</script>
<style lang="scss" scoped>
$cellWidth: 40px;

.code-number-wrap {
    color: $c-7f8389;
    display: flex;
    justify-content: space-between;
    align-items: center;

    .code-item {
        display: inline-block;
        width: $cellWidth;
        height: $cellWidth;
        line-height: $cellWidth;
        text-align: center;
        border: 1px solid $c-d4d5d9;
        -webkit-user-select: text;
    }
}
</style>
<style lang="scss">
.pix-form-item-error .code-number-wrap .code-item {
    border: 1px solid #ff6167;
}
</style>

调用

<template>
    <div>
        <h1 class="error-tips">{{titles.name}}</h1>
        <div class="titleColor">
            <Steps :current="current" :above="true" v-if="titles.type">
                <Step v-for="(item, index) in stepNames" :key="index" :title="item"></Step>
            </Steps>
        </div>
        <div class="confirm-sign-wrap">
            <p class="send-result-tips">我们已经向<span class="phone"><strong>{{phone}}</strong> </span>发送验证码<br></p>
            <p class="tips">输入验证码即代表您同意签署;</p>
             // 调用组件
            <code-number :length="6" v-model="validateCode"></code-number>
            <p class="tip">
                <span v-if="showBtn" @click="fetchValidateCode" class="fr colors">{{btnText}}</span>
                <span v-if="!showBtn" class="fr time-count-tips">{{timeCount}}秒之后重新获取验证码</span>
            </p>
            <div class="btn-wrap">
                <Button :disabled="validateCode.length<6" type="primary" size="large" @click="confirmSign">确认签署</Button>
            </div>
        </div>
    </div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import { State, Getter, Action, Mutation, namespace } from 'vuex-class';
import CodeNumber from '@/components/bussCom/codeNumber/codeNumber.vue';

@Component({
    components: {
        CodeNumber
    }
})
export default class Crumb extends Vue {
    // @Prop(Number) current!: number; // 当前步骤数
    @Prop({ type: Function }) responseProcess!: Function;
    @Mutation setIsShow: any;
    @Mutation setComponentName: any;
    @State userInfo!: any;
    @State titles!: any;
    @State stepNames!: any;
    @State current!: any;
    private source: any; // 缓存
    private phone: string = '';
    private sendphone: string = '';
    private showBtn: boolean = true;
    private validateCode: string = '';
    private timeCount: number = 60;
    private timer: number = -1;
    private accountUid: string = ''; // 创建签章账号ID
    private btnText: string = '获取验证码';
    private show: boolean = false;
    
}
</script>
<style lang="scss" scoped>

.error-tips {
    text-align: center;
    margin: 10px 0;
}

.titleColor {
    background: #faf9f9;
    margin: 10px 0;
}

.confirm-sign-wrap {
    color: $c-7f8389;
    width: 320px;
    margin: 0 auto;
    font-size: $fontSize;
    margin-bottom: 260px;

    .phone {
        color: $text-active;
        padding: 0 10px;
    }

    .send-result-tips {
        margin: 40px 0 32px 0;
        text-align: center;
    }

    .pix-spin {
        color: black !important;
    }

    .tips {
        margin-bottom: 16px;
        // color: $text-active;
        // line-height: 32px;
        text-align: center;
    }

    .tip {
        margin-top: 10px;
        cursor: default;

        .colors {
            color: #1d78f4;
            cursor: pointer;
        }
    }
}

.btn-wrap {
    text-align: center;
    margin-top: 24px;

    button {
        width: 100%;
        margin-top: 10px;
    }
}

.pix-steps-item {
    margin-top: 10px;
}

div >>> .pix-steps .pix-steps-head {
    background: #faf9f9 !important;
}

div >>> .pix-steps .pix-steps-title {
    background: #faf9f9 !important;
}

.textColor {
    color: black;
    z-index: 1000000;
}
</style>

相关文章

网友评论

      本文标题:验证码code组件

      本文链接:https://www.haomeiwen.com/subject/trutyhtx.html