微信封装组件车牌号输入
前言
今天乘着休息来总结下之前用的到自定义键盘来输入车辆号牌微信组件。下面是效果图,请欣赏:
背景
近期做了一个和车有关的项目,有车肯定就有车牌,我们都知道车牌是有一定规律的,如果简单的给个输入框的话…这里省略一万字哈,从小我的编程老师告诉我不要相信任何用户输入的东西。嗯嗯!现在想想还真的是这样,总有一些别具一格的用户就喜欢反着来,也不知道是真不懂还是搞破坏哈。还有个老师告诉我永远要把用户当SB,虽然自己也是用户,感觉不好,但是话糙理不糙啊,因为你永远不知道使用你写的东西的是什么…(甚至是不是人)。在这样的背景下你说要让用户输入一个正确的车牌号,那可真是比登天还难啊,太南了,臣妾做不到啊。大猜想
既然这样哈,我们自己也来当一回用户看看大概有什么情况发生哈,来咯,不要走开哦,下面就是发挥用户脑洞的时候了。我a.12345鄂a.ii111Xa.6666666za.哈哈哈哈哈…
哇哦,估计写一天都写不完呢,后面看大家的啦,这里有一个前提就是咱不考虑以英文开头的车牌,如果需要考虑大家可以举一反三啦。找规律
其实没啥规律可找的,直接上百度一搜就知道车牌的规则。前面是省份简称,第二位是字母,后面是字母和数字的混合,这里有几个特殊的就是教练车、港澳车进大陆、领事馆的车。另外字母和字母o和数字1和0不好辨认,所以字母i和字母o去掉了,最后规律就有了。 结构和样式
知道规律后就可以开始动手操作了,先看看设计图的键盘布局:
上面图片是省份简称键盘布局
上面图片是第二位字母键盘布局
上面图片是后面几位的键盘布局
下面就根据这几个布局来写结构了: {{item}} {{item}} {{item}} {{item}}
分别把数据放入四个数组中,由于第二位少了一些,所以干脆少一行,还有删除的按钮,以及最后的遮罩层,用于点击其他地方关闭键盘
接下来先加几个测试的数据把基本的颜色写好: data: { dataArr1:["京","沪","粤","津","冀","晋","辽","蒙","黑","吉"], dataArr2:["苏","浙","皖","闽","赣","鲁","豫","鄂","湘"], dataArr3:["川","贵","云","渝","桂","琼","藏","陕"], dataArr4:["甘","青","宁","新","台"] }
这里以输入省份的为例
接下来就是把我们的样式添加上去就可以看到效果了: .keyboard { position: fixed; left: 0; bottom: 0; z-index: 99999; width: 100%; background: #d1d6d9; padding: 20rpx 10rpx 0; padding-bottom:calc(30px + env(safe-area-inset-bottom)/2); box-sizing: border-box; } .keyboard .item { display: flex; align-items: center; justify-content: center; margin-bottom: 20rpx; } .keyboard .item view { width: 9%; height: 70rpx; line-height: 70rpx; text-align: center; margin-right: 10rpx; background: #ffffff; border-radius: 10rpx; font-size: 28rpx; } .keyboard .item view:last-child { margin-right: 0; } .keyboard .delbtn { position: fixed; right: 10rpx; bottom: calc(40px + env(safe-area-inset-bottom)/2); height: 70rpx; width: 18%; z-index: 999999; background: #adb3bd; border-radius: 10rpx; display: flex; align-items: center; justify-content: center; } .keyboard .delbtn image{ width: 60rpx; height: 60rpx; } .mask{ position: fixed; left: 0; top: 113rpx; bottom: 0; right: 0; z-index: 99998; }
这里样式就不多说了,大家可以按照自己的喜好来就行
现在已经可以看到效果了,如图:
组件实现
组件的实现其实很简单,主要需要知道微信组件的用法就ok。 参数
实现之前来看看需要什么参数,由于是键盘肯定是需要显示和隐藏的,所以需要一个显示和隐藏的参数这里就命名为isShow。再看我们的样式如果是输入第二位或者后面的呢是不是之前定义的几个数组数据就得改变,问题来了什么时候改变呢?是不是应该在点击输入的地方就打开这个时候就知道了是输入省份还是输入第二位还是后面的,所以这里需要有一个参数来表示当前是需要显示什么类型的键盘暂命名为keyType。到这里参数有了,再来看看是否需要设置默认值是啥,对于isShow来说开始肯定是false即为不显示的,至于keyType默认那个都行,这里默认值设为省份的。这里的参数其实就是需要调用组件时传递过来的参数,所以这两个参数就是设为组件的属性。
有了上面的分析,组件的大概就出来了,代码如下:Component({ properties: { keyType:{ type:String, value:"province" }, isShow:{ type:Boolean, value:false } }, data: { dataArr1:["京","沪","粤","津","冀","晋","辽","蒙","黑","吉"], dataArr2:["苏","浙","皖","闽","赣","鲁","豫","鄂","湘"], dataArr3:["川","贵","云","渝","桂","琼","藏","陕"], dataArr4:["甘","青","宁","新","台"] } })键盘类型的判断
ok,上面已经把键盘所需参数考虑好了,接下来就是需要根据传入的keyType来切换不同的键盘数组的值了。其实就是在组件方法里面写一个方法来切换就行了,实现如下: Component({ properties: { keyType:{ type:String, value:"province" }, isShow:{ type:Boolean, value:false } }, data: { dataArr1:[], dataArr2:[], dataArr3:[], dataArr4:[] }, methods: { changeType(){ if(this.data.keyType == "letter"){ this.setData({ dataArr1:["Q","W","E","R","T","Y","U","P","N","M"], dataArr2:["A","S","D","F","G","H","J","K","L"], dataArr3:["Z","X","C","V","B"], dataArr4:[] }) }else if(this.data.keyType == "province"){ this.setData({ dataArr1:["京","沪","粤","津","冀","晋","辽","蒙","黑","吉"], dataArr2:["苏","浙","皖","闽","赣","鲁","豫","鄂","湘"], dataArr3:["川","贵","云","渝","桂","琼","藏","陕"], dataArr4:["甘","青","宁","新","台"] }) }else if(this.data.keyType == "carlicense"){ this.setData({ dataArr1:["1","2","3","4","5","6","7","8","9","0"], dataArr2:["A","B","C","D","E","F","G","H","J","K"], dataArr3:["L","M","N","P","Q","R","S","T","U","V"], dataArr4:["W","X","Y","Z","港","澳","学","领"] }) } } } })
切的方法有了,现在就是在初始化的时候调用这个方法就行了,修改代码如下: Component({ properties: { keyType:{ type:String, value:"province" }, isShow:{ type:Boolean, value:false } }, data: { dataArr1:[], dataArr2:[], dataArr3:[], dataArr4:[] }, attached(){ this.changeType() }, methods: { changeType(){ if(this.data.keyType == "letter"){ this.setData({ dataArr1:["Q","W","E","R","T","Y","U","P","N","M"], dataArr2:["A","S","D","F","G","H","J","K","L"], dataArr3:["Z","X","C","V","B"], dataArr4:[] }) }else if(this.data.keyType == "province"){ this.setData({ dataArr1:["京","沪","粤","津","冀","晋","辽","蒙","黑","吉"], dataArr2:["苏","浙","皖","闽","赣","鲁","豫","鄂","湘"], dataArr3:["川","贵","云","渝","桂","琼","藏","陕"], dataArr4:["甘","青","宁","新","台"] }) }else if(this.data.keyType == "carlicense"){ this.setData({ dataArr1:["1","2","3","4","5","6","7","8","9","0"], dataArr2:["A","B","C","D","E","F","G","H","J","K"], dataArr3:["L","M","N","P","Q","R","S","T","U","V"], dataArr4:["W","X","Y","Z","港","澳","学","领"] }) } } } })
到这里组件的基本功能已经完成了,但是当我们点击键盘上的内容的时候,你会发现没有反应,嗯嗯…这里好像漏了一个东西,既然是键盘肯定是需要得到输入结果的啦。 获取输入内容
要获取键盘输入的内容就需要给键盘的每个按键新增事件来获取输入内容,将之前的结构中新增事件,具体可参见文章第一段代码,具体的实现代码如下: methods: { inputKey(e){ console.log(e.currentTarget.dataset.value) }, delKey(e){ console.log(e.currentTarget.dataset.value) }, hideKeyBoard(){ this.setData({ isShow:false }) } }
这里将删除和关闭键盘的时间也添加上了,通过以上两个方法就能获取输入的值了。这时当我们点击某个字符时就会看到控制面板里打印出刚刚选择的值了。
可是我需要不是打印出值啊,是需要将值显示在页面上才行,这里就需要将组建获取到的值传递给调用改组件的页面了,如何传递给调用该组件的页面呢? 组件传参
这里咱们就可以去微信小程序的官方文档看看了,毕竟官方文档是个好东西嘛,找到下图所示的地方:
我们这里用到的就是组件通信的第二点事件,可以传递任意数据的,那么根据官方文档的介绍我相信大家一看就知道怎么使用了,代码如下: methods: { inputKey(e){ this.triggerEvent("inputword", {type:"input",value:e.currentTarget.dataset.value}) }, delKey(e){ this.triggerEvent("inputword", {type:"del"}) }, hideKeyBoard(){ this.setData({ isShow:false }) this.triggerEvent("inputword", {type:"blur"}) } }
这里呢是将所以的操作都通过一个事件来传递数据,通过增加一个type来区分到底是输入、删除还是关闭键盘。组件使用
嗯嗯,不容易啊,终于到了使用组件的时候了,这里根据微信组件的用法如下操作: 在页面配置文件中引入组件地址 在页面中添加组件的标签 在添加的标签上面添加需要传递的参数和事件
相关代码如下: { "navigationBarTitleText": "新增车辆", "usingComponents": { "keyboard":"../../components/keyboard/index" } }
在需要用到改组件的页面的配置文件中加入上面带代码 {{provinceCn}} {{provinceCode}} {{carCode}}
在使用到的页面中加入上面最后一行的代码,并添加上相信的参数和事件
下一步就是在页面的js中来处理相应的参数和事件,具体代码如下: Page({ data: { focusProvince:false, focusCode:false, setKeyType:"province", showKeyBoard:false, keyIndex:0, provinceCn:"", provinceCode:"", carCode:"" }, inputWord(e){ if(e.detail.type == "input"){ if(this.data.keyIndex == 0){ this.setData({ provinceCn:e.detail.value }) }else if(this.data.keyIndex == 1){ this.setData({ provinceCode:e.detail.value }) }else if(this.data.keyIndex == 2){ if(this.data.carCode.length < 6){ this.setData({ carCode:this.data.carCode + e.detail.value }) } } }else if(e.detail.type == "del"){ if(this.data.carCode){ this.setData({ carCode:this.data.carCode.substr(0, this.data.carCode.length - 1) }) } }else if(e.detail.type == "blur"){ this.setData({ focusCode:false, focusProvince:false }) } }, chooseProvinceCn(){ this.setData({ setKeyType:"province", showKeyBoard:true, keyIndex:0, focusProvince:true, focusCode:false }) }, chooseProvinceCode(){ this.setData({ setKeyType:"letter", showKeyBoard:true, keyIndex:1, focusProvince:true, focusCode:false }) }, chooseCarCode(){ this.setData({ setKeyType:"carlicense", showKeyBoard:true, keyIndex:2, focusCode:true, focusProvince:false }) } })
页面中的inputWord就是我们最终需要处理的事件,另外几个是输入后控制焦点并显示相应的红色方框的开关。 测试
这一步就是程序小哥哥小姐姐比较害怕的,测试的小哥哥小姐姐就那咋自己写的代码不停的乱搞一通,哈哈哈,最后骨头里挑刺。这里呢当我们分别选择不同输入的type时会发现键盘的内容没有改变,嗯嗯,原来还是写了个bug给自己啊。 解决键盘类型判断的bug
通过上面自己简单的测试后发现有个bug需要去修复,其实这个问题的点在于每次去显示键盘时传递给组件的keyType有缓存导致的,所以需要再组件中属性声明的地方来个监听变化咯,说干就干,改好了马上下班,代码如下: Component({ properties: { keyType:{ type:String, value:"letter", observer:function(newVal,oldVal){ this.changeType() } }, isShow:{ type:Boolean, value:false } } })
在属性中新增observer的监听函数,当有变化的时候就去调用判断类型的函数就可以了。这样就可以愉快的使用。最后打卡,背包走人咯…等等后面还有呢 结束语
目前这个组件也只是为了完成需求而写的,可能实际使用过程中还是会有很多问题的,欢迎大家提出哦。最后放上每个文件完整的代码哦 组件的代码WXML {{item}} {{item}} {{item}} {{item}} WXSS.keyboard { position: fixed; left: 0; bottom: 0; z-index: 99999; width: 100%; background: #d1d6d9; padding: 20rpx 10rpx 0; padding-bottom:calc(30px + env(safe-area-inset-bottom)/2); box-sizing: border-box; } .keyboard .item { display: flex; align-items: center; justify-content: center; margin-bottom: 20rpx; } .keyboard .item view { width: 9%; height: 70rpx; line-height: 70rpx; text-align: center; margin-right: 10rpx; background: #ffffff; border-radius: 10rpx; font-size: 28rpx; } .keyboard .item view:last-child { margin-right: 0; } .keyboard .delbtn { position: fixed; right: 10rpx; bottom: calc(40px + env(safe-area-inset-bottom)/2); height: 70rpx; width: 18%; z-index: 999999; background: #adb3bd; border-radius: 10rpx; display: flex; align-items: center; justify-content: center; } .keyboard .delbtn image{ width: 60rpx; height: 60rpx; } .mask{ position: fixed; left: 0; top: 113rpx; bottom: 0; right: 0; z-index: 99998; }JSComponent({ properties: { keyType:{ type:String, value:"letter", observer:function(newVal,oldVal){ this.changeType() } }, isShow:{ type:Boolean, value:false } }, data: { dataArr1:[], dataArr2:[], dataArr3:[], dataArr4:[] }, attached(){ this.changeType() }, methods: { changeType(){ if(this.data.keyType == "letter"){ this.setData({ dataArr1:["Q","W","E","R","T","Y","U","P","N","M"], dataArr2:["A","S","D","F","G","H","J","K","L"], dataArr3:["Z","X","C","V","B"], dataArr4:[] }) }else if(this.data.keyType == "province"){ this.setData({ dataArr1:["京","沪","粤","津","冀","晋","辽","蒙","黑","吉"], dataArr2:["苏","浙","皖","闽","赣","鲁","豫","鄂","湘"], dataArr3:["川","贵","云","渝","桂","琼","藏","陕"], dataArr4:["甘","青","宁","新","台"] }) }else if(this.data.keyType == "carlicense"){ this.setData({ dataArr1:["1","2","3","4","5","6","7","8","9","0"], dataArr2:["A","B","C","D","E","F","G","H","J","K"], dataArr3:["L","M","N","P","Q","R","S","T","U","V"], dataArr4:["W","X","Y","Z","港","澳","学","领"] }) } }, inputKey(e){ this.triggerEvent("inputword", {type:"input",value:e.currentTarget.dataset.value}) }, delKey(e){ this.triggerEvent("inputword", {type:"del"}) }, hideKeyBoard(){ this.setData({ isShow:false }) this.triggerEvent("inputword", {type:"blur"}) } } })使用页面代码JSON{ "navigationBarTitleText": "新增车辆", "usingComponents": { "keyboard":"../../components/keyboard/index" } }WXML {{provinceCn}} {{provinceCode}} {{carCode}} WXSS.bind-car { display: flex; align-items: center; background: #FFFFFF; padding: 25rpx 30rpx; } .bind-car .car-province { margin-right: 30rpx; width: 170rpx; height: 88rpx; border: 1rpx solid #999999; border-radius: 4rpx; display: flex; } .bind-car .car-province view { width: 86rpx; height: 88rpx; line-height: 88rpx; text-align: center; font-size: 34rpx; font-weight: 500; color: #333333; } .bind-car .car-province view:first-child { position: relative; } .bind-car .car-province view:first-child::after { content: ""; position: absolute; right: 0; top: 50%; width: 1rpx; height: 40rpx; background: #999999; margin-top: -20rpx; } .bind-car .car-province.active { border-color: #FF5152; } .bind-car .car-province.active view:first-child::after { background: #E83333; } .car-number { width: 100%; height: 88rpx; line-height: 88rpx; border: 1rpx solid #999999; border-radius: 4rpx; font-size: 34rpx; font-weight: 500; color: #333333; text-align: center; } .car-number.active { border-color: #E83333; }JSPage({ data: { focusProvince:false, focusCode:false, setKeyType:"province", showKeyBoard:false, keyIndex:0, provinceCn:"", provinceCode:"", carCode:"" }, inputWord(e){ if(e.detail.type == "input"){ if(this.data.keyIndex == 0){ this.setData({ provinceCn:e.detail.value }) }else if(this.data.keyIndex == 1){ this.setData({ provinceCode:e.detail.value }) }else if(this.data.keyIndex == 2){ if(this.data.carCode.length < 6){ this.setData({ carCode:this.data.carCode + e.detail.value }) } } }else if(e.detail.type == "del"){ if(this.data.carCode){ this.setData({ carCode:this.data.carCode.substr(0, this.data.carCode.length - 1) }) } }else if(e.detail.type == "blur"){ this.setData({ focusCode:false, focusProvince:false }) } }, chooseProvinceCn(){ this.setData({ setKeyType:"province", showKeyBoard:true, keyIndex:0, focusProvince:true, focusCode:false }) }, chooseProvinceCode(){ this.setData({ setKeyType:"letter", showKeyBoard:true, keyIndex:1, focusProvince:true, focusCode:false }) }, chooseCarCode(){ this.setData({ setKeyType:"carlicense", showKeyBoard:true, keyIndex:2, focusCode:true, focusProvince:false }) } })
微信版分付来了,微信版花呗,分付,是腾讯的一款信用支付产品,支付分在600分以上都有可能开通,他的入口在微信的钱包里,大家可以点击微信钱包,支付,在零钱通之下可以看到分付,还有支付分,如果没有就说
华为麒麟之后,高通再遇劲敌,天玑2000性能比肩骁龙898手机厂商之间的竞争愈演愈烈,最关键的还是手机芯片厂商之间的竞争。甚至可以说,芯片的级别往往能够直接给手机的性能定位。在安卓阵营,几乎所有的高性能手机都采用高通骁龙系芯片。而在华为麒
微信开始收割用户据中国日报网报道微信拟推出聊天记录云存储服务,该服务可能采用年付费的模式,安卓用户每年130元,苹果用户每年180元。微信不主动存储聊天记录,但可以应广大网友的要求收费为用户存储。
腾讯放弃音乐版权独家授权权利,以后一个APP就可以听所有歌了?大家好,我是老朋友牙牙。喜欢听音乐的人,想必都有这种烦恼,本来收藏好好的歌曲,再听的时候告知你没有版权了所以手机里光是音乐APP都有好几个,网易云酷狗咪咕酷我QQ音乐等想听全喜欢的
现在独立显卡那么贵,对于DIY装机消费者要如何应对?此前,按照显卡市场行情走势,本以为九月可以降价一波,显卡降价对装机行业无疑是重大好消息,不过万万没有想到,装机之家八月份的电脑配置刚发布不久,显卡价格又疯涨了起来,这一波涨价,让千
麻烦联通给我们消费者一个解释今年7月份月初联通客服人员致电推荐5G流量叠加包,在二次确定后在原套餐里不需要收取任何费用后我确定开通了,但3天后扣了19块钱,我向该公司反馈情况经过多次沟通退还相应费用并给了相应
MYSQL那点破事!索引SQL调优事务B树分表。大家好,我是Tom哥为了便于大家查找问题,了解全貌,整理个目录,我们可以快速全局了解关于mysql数据库,面试官一般喜欢问哪些问题接下来,我们逐条来看看每个问题及答案MyISAM和
什么是周界防范报警系统解决什么样的问题?周界防范报警系统又称周界防盗报警系统,一般由探测部分信号传输部分报警联动部分和控制部分四大块组成,在需要被保护的固定区域安装周界防护报警系统后,当有人企图穿越被保护区域四周的边界时
假如宇宙中存在tree(tree(tree(3)))个原子将会是什么样的?tree(3)是一个比葛立恒数还大的数,如果葛立恒数还可以用数学符号写出其存在形式的话,tree(3)则完全无法用任何表达式写出来。葛立恒数其具体形式如下所示这个数由64层组成,箭
黑洞引力那么大,可以把原子撕碎吗?问题黑洞引力那么大,可以把原子撕碎吗?答案是肯定的,黑洞不但撕碎了原子,还撕碎一切最小的粒子。宇宙中存在着三种致密天体,即白矮星中子星黑洞,这三种天体都是以破坏原子结构为存在依据的
手机屏保文案,有什么好句子推荐?时间改变着一切,一切改变着我们。知我者谓我心忧,不知我者谓我何求。不负光阴不负自己,不负被爱不负所爱。这世界不只有眼前的苟且,还有诗和远方。年轻是我们唯一拥有权利去编织梦想的时光。