The body of the

In this installment, we will further refine the prototype click-and-pop input box structure of the previous installment

Click on the control

Secondary pop-up

As can be seen in the figure, when we click the button again to pop up the input box, the keyboard of the machine will not be pulled up, and the input box will be fixed in the last position

The main issues are: When we click the button for the first time, the variable inputFocus that controls the pull-up of the keyboard and keyboardHeight that controls the position of the input box are not initialized, so that they still retain the previous value, so that the keyboard will not pull up when we click the button for the second time. The input box will also appear in the previous position

Obviously, to solve this problem, we need to start with the variables inputFocus and keyboardHeight

  • inputfocuse

    To ensure that the variable inputFocus changes from False to true when the button is clicked to bring up the input box, we simply reset inputFocus to false when we click to hide the input box

    However, if we compare the two functions, we can find that inputFocus changes with the variable showOverlay, which controls the hidden display of the entire structure

    So, instead of adding the same modified inputFocus statement to both functions, we can use the data listener provided by the applets in the Component constructor, observers, The implementation variable inputFocus changes with the variable showOverlay and avoids writing the same logic twice

    observers: {
        showOverlay: function () {
          setTimeout(() = > {
            this.setData({
              inputFocus:!this.data.inputFocus
            })
          }, 100); }},Copy the code

    As can be seen from the picture below, after modification, the second click of the button will pop up the local keyboard

  • keyboardheight

    However, we can also see from the figure that when the button is clicked for the second time, the input box appears much faster than the first time because the variable keyboardheight has obtained the position value above the keyboard of the machine for the first time, resulting in a sense of disconnection

    My current solution to this problem is as follows: Since the keyboard pull-up and the position change of the input box work well with the first click to pop up the input box, I reset the variable KeyboardHeight once when I click hide the input box, so that each time the input box appears, the effect will be the same as the first time

    onClickHide: function () {
      this.setData({
        showOverlay:!this.data.showOverlay,
        keyboardHeight: 0
      });
    },
    Copy the code

    The improved effect is shown below

Drop down keyboard to hide input box

For now, we hide the entire structure by clicking on the mask layer. But beyond that, our clicking on the drop-down native keyboard also indicates that we need to hide the entire structure, which we don’t have yet

For this problem, we can simplify it to: trigger an event when the native keyboard retracts

We first look at the field component, found that when the keyboard height change of the trigger event bind: keyboardheightchange can be used to achieve our requirements

But this event is triggered not only when the keyboard is pulled down, but also when the keyboard is pulled up. So we consider replacing the bind: Focus event that sets the position of the input box when you pull on the keyboard with this event

The logic that this event needs to implement is

  • Set the position of the input box when the keyboard is pulled up
  • Hide the entire structure when the keyboard is pulled down
definePosition: function (e) {
  if (this.data.keyboardHeight ! = =0 && e.detail.height === 0) {
    // Drop down the keyboard to hide the input box
    this._hideInput();
  } else {
    // When the keyboard pops up, the input box position will be set
    this.setData({
      keyboardHeight: e.detail.height }); }},// Since the pull-down keyboard triggers the same logic as clicking on the mask layer, we separate that part
_hideInput: function () {
  this.setData({
    showOverlay:!this.data.showOverlay,
    keyboardHeight: 0
  });
},
Copy the code

Since then, we’ve implemented a pull-down keyboard to hide the entire structure

Click on the input

Input validation

The function of the input box is: after the user finishes the input, click the button on the right to submit the input. Since the user may need to enter the content multiple times, we want the entire input structure to remain after the submit button is clicked

However, in our current structure, clicking the arrow button on the right generated by opening IS-IS link will not trigger the event bind:click-icon corresponding to the tail icon, so we replace it with icon interface

<van-field
  model:value="{{ value }}"
  focus="{{ inputFocus }}"
  placeholder="What are you going to do?"
  left-icon="circle"
  right-icon="envelop-o"
  confirm-hold
  adjust-position="{{ false }}"
  bind:keyboardheightchange="definePosition"
  bind:click-icon="submit"
/>
Copy the code

After the replacement, there was another problem, the submit button on the right side was not working. But in either case, after a single click, the entire input structure disappears, as shown below

Our tests show that when we click the confirm input button on the right, success or failure triggers a bind: Click =”onClickHide” event on the parent element overlay, which hides the entire input structure

As you can see, an event bubbled up at Click during the click, which can be prevented from bubbling by placing a catch event in the view, the parent element previously used to control the position of the input box

Meanwhile, when we open the hold-keyboard (focus) of the Field component, clicking the page will not bring the keyboard down

  • WXML

    <view
      class="input-wrap"
      style="bottom: {{ keyboardHeight }}px ! important;"
      catch:tap="noop"
    >
      <van-field
        model:value="{{ value }}"
        focus="{{ inputFocus }}"
        placeholder="What are you going to do?"
        left-icon="circle"
        right-icon="envelop-o"
        confirm-hold
        hold-keyboard
        adjust-position="{{ false }}"
        bind:keyboardheightchange="definePosition"
        bind:click-icon="submit"
      />
    </view>
    Copy the code
  • JavaScript

    noop: function () {}
    Copy the code

The effect after modification is shown in the figure below. It can be seen that the function of multiple input has been basically realized

Enter the refresh

At this time, there is still a small problem in our input, that is, we input some content in the input box, but do not click the icon on the right to confirm, but hide the structure. When we click the button again to pop up the input box, the input box will still save the content entered last time, as shown in the picture below:

To do this, we can refresh the input field each time it pops up

onClickShow: function () {
  this.setData({
    showOverlay:!this.data.showOverlay,
    value: ""
  });
}
Copy the code

The improved effect is shown in the figure below:

style

The elastic

In our click-and-pop input box structure, the remaining input box is not elastic, and we need to achieve roughly three parts of elasticity, respectively:

  1. The height of the input box
  2. Size of left and right ICONS
  3. The size of the input text

As you can see from the Field component documentation, the component opens three external style interfaces for input fields, text, and ICONS, and ICONS only open the right icon, so using external style classes to implement elasticity is obviously cumbersome

Therefore, we will take the approach of using CSS variables to achieve the elasticity of the input box

By looking at the source code of the Field component, we can see that the entire input field is placed in a cell component, and by looking at the style of the cell component (as shown below), we can see that CSS variables are open for height, icon size, and text size

We can set these three CSS variables in a style class and bind them directly to the Field component to make the entire input box elastic

  • CSS

    .input {
      --cell-line-height: 4vh;
      --cell-font-size: 3vh;
      --field-icon-size: 4vh;
    }
    Copy the code
  • WXML

    <van-field
      class="input"
      model:value="{{ value }}"
      focus="{{ inputFocus }}"
      placeholder="What are you going to do?"
      left-icon="circle"
      right-icon="envelop-o"
      confirm-hold
      hold-keyboard
      adjust-position="{{ false }}"
      bind:keyboardheightchange="definePosition"
      bind:click-icon="submit"
    />
    Copy the code
  • iPhone 6/7/8

  • iPhone X

Button to change

In order to make the user clearly understand that the button on the right is used to confirm this input, we can change the icon of the confirm button on the right after the user enters

The scheme I adopted here is to place two icon elements, and then use wx:if to determine whether the input value is empty to determine which icon element to display. The advantage of this is that the confirmation input event can be bound to the icon corresponding to the value is not empty. This avoids an invalid event triggered by clicking the confirm button on the right when the input is empty

<van-field
  class="input"
  model:value="{{ value }}"
  focus="{{ inputFocus }}"
  placeholder="What are you going to do?"
  confirm-hold
  hold-keyboard
  adjust-position="{{ false }}"
  bind:keyboardheightchange="definePosition"
  bind:confirm="submit"
  data-value="{{ value }}"
>

  <van-icon
    wx:if="{{ value === '' }}"
    slot="right-icon"
    name="fire-o"
  />
  <van-icon
    wx:else
    slot="right-icon"
    name="fire"
    bind:click="submit"
    data-value="{{ value }}"
  />

</van-field>
Copy the code

The final result is shown below

trailer

In this article, we’ve refined our click-and-pop input box structure step by step, finally reaching a level that we can barely call usable

However, as a small part of the entire page, this structure corresponds to a large amount of code, which is clearly not a good practice

In the next installment, we’ll take advantage of what we’ve learned about components and treat the entire structure as a custom component, taking the load off our code 🙂