沒啥特別的技術,就是記錄一下本身開發時遇到的問題和解決方案,之後本身查看着方便css
自定義的車牌號鍵盤html
效果json
要實現一個方便輸入車牌號的鍵盤和輸入框,支持新能源車牌。小程序
最開始的想法是用多個小程序的input輸入框實現,可是發現了一個很不爽的體驗,每一個的輸入框聚焦都會引起手機鍵盤的彈出,emmmm,這可不是我要的效果。數組
最終的實現方案就是 沒用到一個input輸入框,所有使用的div實現輸入框效果。將鍵盤選中的內容存到一個數組裏,輸入框裏展現對應數組的文字。app
我把它寫成一個component,方便多頁面使用xss
wxml文件flex
<view class="modal-box">
<view class="modal-wrapper">
<view class="modal-title">
<view class="titleWrapper"><text class="title-text">請錄入車牌號</text></view>
<view class="iconWrapper"><image class="close-icon" src="../images/close.png" bindtap="onCancel" /></view>
</view>
<view class="modal-content">
<view class="modal-input">
<block wx:for="{{8}}" wx:key="index">
<view data-index="{{index}}" class="input {{selectInputIndex===index?'activeInput':''}}" bindtap='inputCarNum'>
<text>{{carNumArr[index] || ''}}</text>
</view>
</block>
<view class="line"></view>
</view>
</view>
<view class="model-btn-group">
<button bindtap="onOk" class="btn confirm" disabled="{{btnDisabled}}">確認</button>
</view>
</view>
<!-- 車牌 -->
<view class='keyboard' >
<!-- 省鍵盤 -->
<view class="provinces" hidden='{{hiddenPro}}'>
<view class="pro-li fl" wx:for="{{provinceArr}}" wx:key="index" catchtap='proTap' data-province="{{item}}">{{item}}</view>
</view>
<!-- 號碼鍵盤 -->
<view class="keyNums" hidden='{{hiddenStr}}'>
<view wx:if="{{selectInputIndex===1}}" class="row numRow">
<view class="pro-li disabled" wx:for="{{numArr}}" wx:key="index" data-str="{{item}}">{{item}}</view>
</view>
<view wx:else class="row numRow">
<view class="pro-li " wx:for="{{numArr}}" wx:key="index" catchtap='strTap' data-str="{{item}}">{{item}}</view>
</view>
<view class="strOne row">
<view class="pro-li " wx:for="{{strArrOne}}" wx:key="index" catchtap='strTap' data-str="{{item}}">{{item}}</view>
</view>
<view class="strTwo row">
<view class="pro-li " wx:for="{{strArrTwo}}"wx:key="index" catchtap='strTap' data-str="{{item}}">{{item}}</view>
</view>
<view class="strThree row">
<view class="pro-li " wx:for="{{strArrThree}}" wx:key="index" catchtap='strTap' data-str="{{item}}">{{item}}</view>
<view class='kb-icon pro-li' catchtap='backSpace'>
<image class='delete-icon' src="../images/delete.png" />
</view>
</view>
</view>
</view>
<view class="modal-cover"></view>
</view>
複製代碼
js代碼ui
const INPUT_NUM = 8;//車牌號輸入框個數
const EmptyArray = new Array(INPUT_NUM).fill('');//['','','','','','','','']
// 車牌輸入框的下標
const INPUT_INDEX = {
FIRST: 0,
SECOND: 1
};
Component({
data: {
// 鍵
provinceArr: ['京', '滬', '津', '蘇', '粵', '冀', '晉', '蒙', '遼', '吉', '黑', '浙', '皖', '閩', '贛', '魯', '豫', '鄂', '湘',
'桂', '瓊', '渝', '川', '貴', '雲', '藏', '陝', '甘', '青', '寧', '新', '港', '澳', '臺'],
strArrOne: ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'P'],
strArrTwo: ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
strArrThree: ['Z', 'X', 'C', 'V', 'B', 'N', 'M'],
numArr: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
hiddenPro: false, // 隱藏省份鍵盤
hiddenStr: true, // 隱藏數字字母鍵盤
carNumArr: EmptyArray,
selectInputIndex: 0,
btnDisabled: true
},
methods: {
proTap(e) { //點擊省份
let province = e.currentTarget.dataset.province;
const { carNumArr, selectInputIndex } = this.data;
this.setData({
hiddenPro: true,
hiddenStr: false
});
carNumArr[selectInputIndex] = province;
// 選擇車牌號時觸發
this.setData({
carNumArr,
// 選中一個後,下一個輸入框聚焦
selectInputIndex: selectInputIndex !== carNumArr.length - 1 ? selectInputIndex + 1 : selectInputIndex,
btnDisabled: this.btnDisabled()
});
},
strTap(e) { //點擊字母數字
const str = e.currentTarget.dataset.str;
const { carNumArr, selectInputIndex } = this.data;
carNumArr[selectInputIndex] = str;
this.setData({
carNumArr,
// 選中一個後,下一個輸入框聚焦
selectInputIndex: selectInputIndex !== carNumArr.length - 1 ? selectInputIndex + 1 : selectInputIndex,
btnDisabled: this.btnDisabled()
});
},
inputCarNum(e) {
const { index } = e.currentTarget.dataset;
this.setData({
showCarKeyboard: true,
selectInputIndex: index
});
if (index === INPUT_INDEX.FIRST) {
// 第一個輸入框展現省份鍵盤,第二個展現字母數字輸入框(數字不可點),之後就是數字字母輸入框(均可點)
this.setData({
hiddenPro: false,
hiddenStr: true
});
} else if (index === INPUT_INDEX.SECOND) {
this.setData({
hiddenPro: true,
hiddenStr: false
});
} else {
this.setData({
hiddenPro: true,
hiddenStr: false
});
}
},
backSpace() { //刪除
const { carNumArr, selectInputIndex } = this.data;
carNumArr[selectInputIndex] = '';
this.setData({
carNumArr,
selectInputIndex: selectInputIndex !== INPUT_INDEX.FIRST ? selectInputIndex - 1 : selectInputIndex,
btnDisabled: this.btnDisabled()
}, () => {
if (this.data.selectInputIndex === INPUT_INDEX.FIRST) { //這裏必需要用this.data.selectInputIndex,用最新的
this.setData({
hiddenPro: false,
hiddenStr: true
});
}
});
},
// 只有輸入內容的車牌號位數合法時,展現確認按鈕
btnDisabled() {
const { carNumArr } = this.data;
const disabled = carNumArr.some((item, index) => {
if (index !== carNumArr.length - 1) {
return !item;
}
return false;
});
return disabled;
},
onCancel() {
this.setData({ carNumArr: EmptyArray });
this.triggerEvent('onCancel');
},
onOk() {
const carNum = this.data.carNumArr.join('');
this.triggerEvent('onOk', carNum);
}
},
});
複製代碼
wxss文件this
/* 鍵盤 */
.keyboard {
width: 100%;
position: fixed;
bottom: 0;
left:0;
z-index: 1000;
background-color: rgba(210, 213, 219, 90);
}
.fl {
float: left
}
.carnum {
text-align: center;
height: 88rpx
}
.tel {
border-bottom: 2rpx solid #ddd;
height: 100rpx;
line-height: 100rpx;
}
.provinces {
overflow: hidden;
padding-top: 20rpx;
}
.pro-li {
font-size: 32rpx;
color: #353535;
height: 76rpx;
width: 62rpx;
line-height: 76rpx;
text-align: center;
margin-left: 12rpx;
margin-bottom: 20rpx;
background-color: #fff;
box-shadow: 0px 1rpx 2rpx 0 #979797;
border-radius: 5px;
flex: 1
}
.keyNums .disabled {
background-color: #F7F7F7;
color: #CCC
}
.keyNums {
overflow: hidden;
padding-top: 20rpx;
display: flex;
flex-direction: column;
}
.keyNums .row {
display: flex;
}
.keyNums .numRow {
padding: 0 10rpx;
}
.keyNums .strOne {
padding: 0 10rpx;
}
.keyNums .strOne .strOneItem {
flex: 1
}
.keyNums .strTwo {
padding: 0 40rpx;
}
.keyNums .strOne .strTwoItem {
flex: 1
}
.keyNums .strThree {
padding-left: 116rpx;
padding-right: 10rpx;
}
.keyNums .strOne .strThreeItem {
flex: 1
}
.keyNums .strOne .strThreeItem:nth-child(7) {
margin-left: 100px
}
.keyNums .pro-li:nth-child(16) {
color: red
}
.keyNums .strThree .kb-del {
margin-left: 12rpx
}
.keyNums .strThree .kb-icon {
flex: 1.5;
background: #ABB3BD;
margin-left: 40rpx;
}
/* modal樣式 */
.modal-box {
width: 100%;
position: absolute;
top: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
}
.modal-wrapper {
margin: 30% 30rpx;
height: 380rpx;
padding: 30rpx;
background-color: #fff;
border-radius: 10rpx;
z-index: 300;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
align-content: space-between;
justify-content: space-between;
overflow: hidden;
text-align: left;
}
.modal-wrapper .model-btn-group {
display: flex;
box-sizing: border-box;
font-size: 32rpx;
}
.model-btn-group view {
width: 50%;
text-align: center;
box-sizing: border-box;
}
.model-btn-group .btn {
flex: 1;
font-size: 18px
}
.model-btn-group .cancel {
color: #999;
}
.model-btn-group .confirm {
color: #fff;
background-color: #ff5000;
}
.model-btn-group .confirm.active {
opacity: 1;
}
.modal-cover {
width: 100%;
background-color: #242424;
opacity: 0.5;
z-index: 299;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
overflow: hidden;
}
.modal-input {
display: flex;
}
.modal-input .input {
border: 1px solid #979797;
margin-right:6rpx;
border-radius: 3px;
flex: 1;
text-align: center;
padding: 8px;
height: 22px;
}
.modal-input .input:nth-child(1) {
border-right-width: 0;
margin-right: 0;
position: relative;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.modal-input .input:nth-child(1)::after {
content: "";
position: absolute;
right: -1px;
width: 1px;
height: 20px;
background-color: #979797;
z-index: -10
}
.modal-input .input:nth-child(2) {
position: relative;
border-left-width: 0;
margin-right:20rpx;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.modal-input .input:nth-child(2)::after {
content: "";
position: absolute;
right:-16rpx;
top: 45%;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: #979797
}
.modal-input .input:nth-child(8) {
border: 1px dashed #979797;
}
.modal-input .activeInput {
border-radius: 3px !important;
border: 1px solid #FF5000 !important
}
.modal-input .text {
text-align: right;
color: #c5c5c5;
font-size: 28rpx;
}
.modal-placeholder-class {
color: #c5c5c5;
}
.modal-title {
display: flex;
font-size: 20px;
color: #333333
}
.titleWrapper {
flex: 1;
}
.title-text {
font-size: 18px;
font-weight: bold;
}
.iconWrapper {
flex: 1;
text-align: right;
}
.close-icon {
width: 35rpx;
height: 35rpx;
}
.delete-icon {
width: 55rpx;
height: 40rpx;
margin-top: 18rpx;
}
複製代碼
json文件,標識出來這是一個component
{
"component": true
}
複製代碼
要在json裏引用組件
{
"usingComponents": {
"carKeyboard": "/components/carKeyboard/carKeyboard"
}
}
複製代碼
<!--index.wxml-->
<view class="container">
<view>
<button class="btn" bindtap="inputCarNum">輸入車牌號</button>
</view>
<block wx:if="{{showKeyboard}}">
<carKeyboard carNum="{{carNum}}" bind:onOk="onOk" bind:onCancel="onCancel" />
</block>
</view>
複製代碼
//index.js
Page({
data: {
carnum: '',
showKeyboard:false,
},
inputCarNum() {
this.setData({showKeyboard: true})
},
onOk(e){
console.log(e.detail,'輸入的車牌號')
},
onCancel(){
this.setData({ showKeyboard: false })
}
})
複製代碼