一、效果图
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: `
-
-
-
-
-
-
-
- :class="{ active: activeIndex === index }" @click="handleClickItem(index)">
- {{ item }}
-
-
-
-
-
-
- 'vnp-del-wrapper': val === 'del',
- 'vnp-type-wrapper': val === 'type',
- }">
-
- 中/英
- 中/英
-
-
-
-
- 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">
-
-
-
- @click="handleClickKey(val)">
- {{ val }}
-
-
-
-
- `,
- 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-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>
-
-
- <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为名注册的组件,在模板中可以通过
或
引用。