09月25, 2017

小程序自定义键盘

最近做的小程序用到了自定义键盘,在网上找了一下没有找到相关的介绍,就用wxml和wxss(其实就是网页的html和css)来实现了,下面简单介绍一下我的思路。

背景

小程序的Input组件调用的是系统的输入法,在一般情况下可以满足我们的思路。但是当需要英文和数字混合输入的时候,体验就不好了,需要来回切换。为了用户体验,我就想有没有自定义键盘,这样可以提升用户体验。

带着这个问题百度了一圈没有发现,也可能是我搜索的不对。 既然没有找到,那就只有自己来实现。

思路和实现

我们想实现的效果就是当用户点击输入框的时候,弹出我们自定义的虚拟键盘,当用户输入完成的时候点击页面空白处或键盘上的完成按钮来隐藏键盘。

根据上面的思路我们把这个需求拆分成下面几步来实现。

1. input控件

由于不需要弹出系统的输入法,所以我的想法是禁用input控件。可能有人会问,要是禁用了还怎么输入呢?这个简单,我们本来就没打算让用户输入,而是用虚拟键盘的点击事件来模拟用户输入,后面再详细说这个。

代码比较简单

<view>
    <input  type="text"  placeholder="如:T124" value='{{input}}'  catchtap="bindKeyInput" disabled/>

 </view>

给input组件的value绑定data.input,用于显示用户的输入

绑定点击事件bindKeyInput,用于显示虚拟键盘

2. 样式编写

先看wxml结构

外层一个view来包裹起来,并加上wx-if来实现显示和隐藏的控制。

包裹层wxml

//最外层结构
<view class='keyboard' wx-if="{{showKeyboard}}">
  我是虚拟键盘
</view>

因为键盘固定在底部,所以要给外层加一个固定底部的样式,并加上背景颜色。

wxss

.keyboard{
  width:100%;
  position: fixed;
  bottom: 0;
  background-color: #EAEAEA;
}

此时预览是看不出来效果的,因为我们没有给外层view高度。改一下wxss的keyboard类,加上高度

.keyboard{
  width:100%;
  position: fixed;
  bottom: 0;
  background-color: #EAEAEA;
  height: 500rpx;
}

可以看到已经保持在底部了。

接着我们再添加键盘内容

<view class='keyboard'>
  <view class='letter'> 
    <view class='letter-view'>C 城际</view>
    <view class='letter-view' >D 动车</view>
    <view class='letter-view' >G 高铁</view>
    <view class='letter-view'>L 临客</view>
    <view class='letter-view'>K 快速</view>
    <view class='letter-view'>T 特快</view>
    <view class='letter-view'>Y 旅游</view>
    <view class='letter-view'>Z 直达</view>
  </view>
  <view class='key-number'>
    <view class='number-view'>1</view>
    <view class='number-view'>2</view>
    <view class='number-view'>3</view>
    <view class='number-view'>删除</view>
    <view class='number-view'>4</view>
    <view class='number-view'>5</view>
    <view class='number-view'>6</view>
    <view class='number-view'>0</view>
    <view class='number-view'>7</view>
    <view class='number-view'>8</view>
    <view class='number-view'>9</view>
    <view class='number-view'>隐藏</view>
  </view>
</view>

可以看到我把键盘分成了两部分,上半部分为字母,下半部分为数字和功能键。

我们使用flex布局来做,先来看上半部分。

.letter{
  display: flex;
  flex-direction: row;
}

上面声明之后,我们可以看到字母全部排到一行上了。

flex-direction:row 的作用就是用来让元素按行显示。

接着添加

flex-wrap: wrap;
 justify-content:center;

flex-wrap:wrap; 的作用是指定元素是否换行以及换行之后的显示

justify-content:center;是横轴方向居中。

这样之后letter类就成了

.letter{
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content:center;
}

接着来为letter-view类添加样式

.letter-view{
  border: solid 1rpx #EAEAEA;
  margin: 10rpx;
  background-color: #FFFFFF;
  flex: 0 0 160rpx;
  text-align: center;
  height: 100rpx;
  line-height: 100rpx;
}

其中,flex: 0 0 160rpx; flex 属性是 flex-grow、flex-shrink 和 flex-basis 属性的简写属性。这句话就是设置每个元素宽为160rpx。关于flex属性可以看这篇文章。 rpx是微信小程序提供的样式,可以根据屏幕宽度进行自适应,参考尺寸单位

剩下的样式都比较简单了,我们直接看效果

alt

可以看到实现了我们想要的效果。

同样的方式,我们来给下面数字键盘添加样式。

.key-number{
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content:center;
  margin: 30rpx auto;
}

.number-view{
  border: solid 1rpx #EAEAEA;
  margin: 10rpx;
  background-color: #FFFFFF;
  flex: 0 0 150rpx;
  text-align: center;

code block

  height: 100rpx;
  line-height: 100rpx;
}

样式同上面基本一样,没什么好说的。

先看看效果吧。

好的,但这里样式完成了,我们还得给按钮加上点击事件,来响应用户点击。

3. 虚拟键盘的显示与隐藏

我们想要的效果是当用户点击输入框的时候弹出键盘,点击页面空白部分时或点击隐藏按钮时隐藏按钮。 在data中添加上showKeyboard变量,并设置默认值为false

data: {
    input: '',
    showClear: false,
    showKeyboard: false   //是否显示虚拟键盘
  },

在wxml为虚拟键盘部分添加wx-if

<view class='keyboard' wx-if="{{showKeyboard}}">
……
</view>

为input组件添加点击事件,用于响应用户点击

<view>
    <input  type="text"  placeholder="如:T124" value='{{input}}'  catchtap="bindKeyInput" disabled/>

 </view>

当点击input组件的时候如果虚拟键盘没有显示,则显示出来。如果已经显示了,则隐藏。

bindKeyInput: function(){
    console.log('key input')
    let showKeyboard = this.data.showKeyboard
    this.setData({
      showKeyboard: !showKeyboard
    })
  },

为隐藏按钮添加点击事件

<view class='number-view' catchtap='hideKeyboard'>隐藏</view>
hideKeyboard: function(){
    this.setData({
      showKeyboard: false
    })
  },

好的,我们来看一下效果

4. 点击事件编写

点击事件我们直接使用tap类型的事件,使用catchtap来阻止冒泡事件向上冒泡。

<view class='keyboard' wx-if="{{showKeyboard}}">
  <view class='letter'> 
    <view class='letter-view' data-letter='C' catchtap='letterButton'>C 城际</view>
    <view class='letter-view' data-letter='D' catchtap='letterButton'>D 动车</view>
    <view class='letter-view' data-letter='G' catchtap='letterButton'>G 高铁</view>
    <view class='letter-view' data-letter='L' catchtap='letterButton'>L 临客</view>
    <view class='letter-view' data-letter='K' catchtap='letterButton'>K 快速</view>
    <view class='letter-view' data-letter='T' catchtap='letterButton'>T 特快</view>
    <view class='letter-view' data-letter='Y' catchtap='letterButton'>Y 旅游</view>
    <view class='letter-view' data-letter='Z' catchtap='letterButton'>Z 直达</view>
  </view>
  <view class='key-number'>
    <view class='number-view' data-number='1' catchtap='numberButton'>1</view>
    <view class='number-view' data-number='2' catchtap='numberButton'>2</view>
    <view class='number-view' data-number='3' catchtap='numberButton'>3</view>
    <view class='number-view' catchtap='delInput'>删除</view>
    <view class='number-view' data-number='4' catchtap='numberButton'>4</view>
    <view class='number-view' data-number='5' catchtap='numberButton'>5</view>
    <view class='number-view' data-number='6' catchtap='numberButton'>6</view>
    <view class='number-view' data-number='0' catchtap='numberButton'>0</view>
    <view class='number-view' data-number='7' catchtap='numberButton'>7</view>
    <view class='number-view' data-number='8' catchtap='numberButton'>8</view>
    <view class='number-view' data-number='9' catchtap='numberButton'>9</view>
    <view class='number-view' catchtap='hideKeyboard'>隐藏</view>
  </view>
</view>

给字母按键绑定letterButton的函数,并给每个字母添加data-*,用于获取到点击之后的值。

下面来看看letterButton函数的实现

data: {
    input: '',    //输入值
    showKeyboard: false,   //是否显示虚拟键盘
    showClear: true
  },

//字母按键
  letterButton: function(event){
    let data = event.currentTarget.dataset
    console.log(data.letter)
    this.setData({
      input: data.letter,
     showClear: true
    })
  }

在这里我们在data里面定义了两个值,input用于绑定用户按键点击,showKeyboard用于是否显示虚拟键盘,稍后在详细将这个。

因为我这个应用是用于查询火车时刻表,而车次的字母只有一位,且是在第一位的,所以,我就直接把用户点击的字母的值赋值到input输入框中。 我们来看看效果

可以看到没有问题

同样的方式,来实现数字点击的numberButton函数

//数字按键
  numberButton: function(event){
    let data = event.currentTarget.dataset
    console.log(data.number)
    let input = this.data.input

    input = input + data.number
    if(input.length > 6){
      return
    }

    this.setData({
      input: input,
      showClear: true
    })
  },

再来实现删除的按钮 delInput: function(){ let input = this.data.input let newInput = input.substring(0, input.length-1)

this.setData({
  input: newInput,
  showClear: newInput.length  //最后一个数字时隐藏删除按钮
})

}

来看看效果

到这里我们的虚拟键盘就做好了。

全部代码地址

https://github.com/guandaxia/train-late-wxapp

手机体验

有问题欢迎给我留言

本文链接:http://blog.guansixu.cn/post/wxapp-keyboard.html

-- EOF --

Comments