一、效果图

vant+vue软键盘

 

 二、实现

1.因为是在html静态页面中使用,所以要先引入vant.css、vant.js、vue.js到需要使用的html页面;

2.将实现好的车牌软键盘功能放到一个js里面,再将该组件使用js方式引入到html界面,同样该组件的css代码也要引入;

 3.这里的车牌号软键盘实现方式是借鉴的该方法:vue.js - vant-number-plate基于vue+vant+less的车牌号输入组件(车牌号虚拟键盘)_个人文章 - SegmentFault 思否

 我这里稍微改进了一下,车牌号小于7位数时不能点击完成。新建一个keyboard.js文件夹,注册一个成对象,直接上代码:

// 车牌号软键盘
var keyboardVm = Vue.component('VanCardBoard', {
    template: `<van-action-sheet v-model="visible" get-container="body">
    <div class="vnp-header">
        <button type="button" class="vnp-btn-finish" @click="finish">完成</button>
    </div>
    <div class="vnp-input-box-outer">
        <div class="vnp-input-box" :class="{'vnp-red':activeIndex<=6}">
            <ul>
                <li v-for="(item, index) in val" :key="index"
                    :class="{ active: activeIndex === index }" @click="handleClickItem(index)">
                    <span>{{ item }}</span>
                </li>
            </ul>
        </div>
    </div>
    <div class="vnp-keys">
        <div class="vnp-keys-row" v-for="(item, index) in keyboardList" :key="index">
            <div class="vnp-btn-key-wrapper" v-for="(val, index) in item" :key="index" :class="{
                        'vnp-del-wrapper': val === 'del',
                        'vnp-type-wrapper': val === 'type',
                    }">
                <van-button v-if="val === 'type'" class="vnp-btn-key" @click="handleChangeType">
                    <span v-if="type === 'cn'">中/<span class="vnp-smaller">英</span></span>
                    <span v-else><span class="vnp-smaller">中</span>/英</span>
                </van-button>
                <van-button v-else-if="val === 'del'" class="vnp-btn-key" @click="handleDel">
                    <svg viewBox="0 0 32 22" xmlns="http://www.w3.org/2000/svg" class="vnp-delete-icon">
                        <path
                            d="M28.016 0A3.991 3.991 0 0132 3.987v14.026c0 2.2-1.787 3.987-3.98 3.987H10.382c-.509 0-.996-.206-1.374-.585L.89 13.09C.33 12.62 0 11.84 0 11.006c0-.86.325-1.62.887-2.08L9.01.585A1.936 1.936 0 0110.383 0zm0 1.947H10.368L2.24 10.28c-.224.226-.312.432-.312.73 0 .287.094.51.312.729l8.128 8.333h17.648a2.041 2.041 0 002.037-2.04V3.987c0-1.127-.915-2.04-2.037-2.04zM23.028 6a.96.96 0 01.678.292.95.95 0 01-.003 1.377l-3.342 3.348 3.326 3.333c.189.188.292.43.292.679 0 .248-.103.49-.292.679a.96.96 0 01-.678.292.959.959 0 01-.677-.292L18.99 12.36l-3.343 3.345a.96.96 0 01-.677.292.96.96 0 01-.678-.292.962.962 0 01-.292-.68c0-.248.104-.49.292-.679l3.342-3.348-3.342-3.348A.963.963 0 0114 6.971c0-.248.104-.49.292-.679A.96.96 0 0114.97 6a.96.96 0 01.677.292l3.358 3.348 3.345-3.348A.96.96 0 0123.028 6z"
                            fill="currentColor"></path>
                    </svg>
                </van-button>
                <van-button v-else class="vnp-btn-key" :class="{ 'vnp-btn-empty': !val }"
                    @click="handleClickKey(val)">
                    {{ val }}
                </van-button>
            </div>
        </div>
    </div>
</van-action-sheet>`,
    model: {
        prop: 'value',
    },
    props: {
        show: {
            type: Boolean,
            default: false,
        },
        value: {
            type: String,
            default: '',
        },
    },
    data() {
        return {
            value: '', //当前输入的车牌
            val: ['', '', '', '', '', '', '', ''], //固定八位
            activeIndex: 0, //当前活动的软键盘按钮
            type: 'cn',
            cn: [
                ['京', '津', '沪', '渝', '冀', '豫', '云', '辽', '黑', '湘'],
                ['皖', '鲁', '新', '苏', '浙', '赣', '鄂', '桂', '甘', '晋'],
                ['蒙', '陕', '吉', '闽', '贵', '粤', '青', '藏', '川', '宁'],
                ['type', '琼', '使', '领', '学', '警	', '挂', '', 'del'],
            ],
            en: [
                ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
                ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'O', 'P'],
                ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
                ['type', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'del'],
            ],
        };
    },
    computed: {
        visible: {
            set(val) {
                this.$emit('update:show', val);
            },
            get() {
                return this.show;
            },
        },
        keyboardList() {
            return this.type === 'en' ? this.en : this.cn;
        },
    },
    watch: {
        activeIndex() {
            this.handleActiveChange(this.activeIndex);
        },
        value: {
            immediate: true,
            handler() {
                if (this.val.join('') === this.value) {
                    return;
                }
                const val = this.value.split('');
                while (val.length < 8) {
                    val.push('');
                }
                this.val = val;
            },
        },
    },
    methods: {
        // 点击某个输入框
        handleClickItem(index) {
            this.activeIndex = index;
        },
        // 中英文切换
        handleChangeType() {
            this.type = this.type === 'en' ? 'cn' : 'en';
        },
        // 选中某个键盘按钮值
        handleClickKey(val) {
            if (val) {
                this.$set(this.val, this.activeIndex, val);
                if (this.activeIndex < 7) {
                    this.activeIndex += 1;
                }
            }
        },
        // 获焦顶部要填入的单元格
        handleActiveChange(activeIndex) {
            if (activeIndex === 0) {
                this.type = 'cn';
            } else {
                this.type = 'en';
            }
        },
        handleDel() {
            this.$set(this.val, this.activeIndex, '');
            if (this.activeIndex > 0) {
                this.activeIndex -= 1;
            }
        },
        finish() {
            const _val = this.val.join('');
            if (_val.length <= 6) return;
            this.$emit('input', _val);
            this.visible = false;
        },
    },
});

 keyboard.css样式:

.vnp-header {
	height: 40px;
	padding-top: 6px;
	position: relative;
}

.vnp-header .vnp-btn-finish {
	position: absolute;
	right: 0;
	height: 100%;
	padding: 0 16px;
	color: #576b95;
	font-size: 14px;
	background-color: transparent;
	border: none;
	cursor: pointer;
}

.vnp-input-box-outer {
	width: 82%;
	max-width: 600px;
	margin: 0 auto;
	padding: 10px;
}

.vnp-input-box {
	padding: 10px 0;
	border: 1px solid #d8d8d8;
	border-radius: 2px;
	color: #8d8d8d;
	font-size: 15px;
	text-align: center;
}

.vnp-input-box ul {
	display: flex;
}

.vnp-input-box li {
	flex: 1;
	border-right: 1px solid #eaeaea;
	height: 28px;
	line-height: 28px;
}

.vnp-input-box li:first-child {
	border-right: 0;
}

.vnp-input-box li:last-child {
	border: none;
}

.vnp-input-box li.active {
	color: #1989fa;
}

.vnp-input-box li.active>span {
	height: 100%;
	width: 20px;
	display: inline-block;
	border-bottom: 1px solid #1989fa;
}
.vnp-red {
	border: 1px solid red;
}
.vnp-keys {
	padding: 3px;
	background: #f2f3f5;
	padding-bottom: 22px;
}

.vnp-keys .vnp-keys-row {
	display: flex;
	justify-content: center;
}

.vnp-keys .vnp-btn-key-wrapper {
	flex: 0 1 calc((100% - 6px * 10) / 10);
	padding: 3px;
	box-sizing: content-box;
}

.vnp-keys .vnp-btn-key-wrapper.vnp-del-wrapper,
.vnp-keys .vnp-btn-key-wrapper.vnp-type-wrapper {
	flex: 1;
}

.vnp-keys .vnp-btn-key-wrapper.vnp-type-wrapper .vnp-smaller {
	color: #999;
	font-size: 12px;
}

.vnp-keys .vnp-btn-key-wrapper .vnp-btn-key {
	padding: 0;
	width: 100%;
	border-radius: 4px;
}

.vnp-keys .vnp-btn-key-wrapper .vnp-btn-empty {
	background: transparent;
	border: none;
}

.vnp-keys .vnp-btn-key-wrapper .vnp-delete-icon {
	width: 18px;
	vertical-align: middle;
}

4.在表单中使用:

<van-form>
	<van-field label="车牌号" required :value="form.cardNumber" is-link placeholder="请选择" @click="showCardBoard=true"></van-field>
	<!-- 车牌号软键盘 -->
	<van-card-board v-model="form.cardNumber" :show.sync="showCardBoard"></van-card-board>
</van-form>


<script type="text/javascript">
	var vm = new Vue({
		el: '#vehicleAuditAdd',
		data: {
            form: {
				cardNumber: ''
			},
			showCardBoard: false,    //控制车牌号软键盘显示隐藏
        }
    })
</script>

三、知识点总结

1、如何将选中的车牌号回显在需要显示的表单中?

this.$emit('input',this.val)

解答:

  • 子组件在传值的时候,选用input,如this.$emit(‘input’,this.val),在父组件直接用v-model绑定,就可以获取到了 。
  • 子组件也可以通过$emit(‘input’,false),去改变父组件中v-model 和 子组件中 value 的值 。

因此,值在input中回显时,可以不用写自定义事件。

2. 当在多个静态页面需要使用该组件时,如何封装成组件?

解答:

  • 因为已经在静态页面引入了vue.js,所以我们可以使用 Vue 应用实例的 app.component() 方法,让组件在当前 Vue 应用中全局可用。
  • 语法:
  • 如果同时传递一个组件名字符串及其定义,则注册一个全局组件;如果只传递一个名字,则会返回用该名字注册组件 (如果存在的话)。
  • Vue 支持将模板中使用 kebab-case 的标签解析为使用 PascalCase 注册的组件。例如VanCardBoard为名注册的组件,在模板中可以通过 <VanCardBoard> 或 <van-card-board> 引用。
Logo

前往低代码交流专区

更多推荐