Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

preface

When using the mobile component library Vant’s time Picker, I encountered this problem: when the popup Picker component selects the time, it will trigger the page behind the popup layer. This is a very obvious Bug.

What bugs

Let’s start with the scenario, which is a scrollable list with infinite loading. The requirement is to hide the form when you swipe up, show the query button, and show the form when you click the query.

When the time is not selected, it will trigger the scrolling of the following page. The reason is that the Picker of this time Picker has a scrolling through, and then the page behind the elastic layer will scroll, triggering the form hiding. This can be a headache, and the time can not be selected. Take a look at the requirements implementation process before proposing a solution.

Look at the

To save space, only the key logic is retained, where the Boolean value showSearch indicates the explicit and implicit of the form

Vue kit

<template>
<div class="personal">
    <transition name="fade-transform"  mode="out-in" appear>
	<div class="search-container" v-if="showSearch">
            <div class="search-form">
                <van-form :model="form" ref="form" :label-style="{color:'#636B7E',fontSize:'13px'}">
                    <van-field v-model="form.bxcrxm" placeholder="Please enter your name" clearable />
                        <van-row type="flex" justify="space-between" align="center">
                           <van-col :span="11">
                                <van-field
                                    clickable
                                    readonly
                                    placeholder="Start time"
                                    @click="showStartPicker = true"
                                    />
                                    <van-popup v-model="showStartPicker" position="bottom">
                                        <van-datetime-picker
                                            type="datetime"
                                            @cancel="showStartPicker = false"
                                        />
                                      </van-popup>
                            </van-col>
                            <van-col :span="1" >
                                        <div class="line">
                                        </div>
                                </van-col>
                                <van-col :span="11">
                                        <van-field
                                            readonly
                                            clickable
                                            placeholder="End time"
                                            @click="showEndPicker = true"
                                         />
                                        <van-popup v-model="showEndPicker" position="bottom">
                                        <van-datetime-picker
                                            type="datetime"
                                            @cancel="showEndPicker = false"
                                        />
                                        </van-popup>
                            </van-col>
                        </van-row>
                </van-form>
             </div>
       </div>
    </transition>
     <div class="list-container">// List container</div>
   </div>
   </template>
<script>
 import {touchStart,touchEnd}  from '@/utils/touch'
 export default {
     data(){
         showSearch:true.showStartPicker:false
     },
     mounted () {
         this.bindTouch()
     },
     methods: {bindTouch(){
            document.querySelector('.personal').addEventListener('touchstart', touchStart)
            document.querySelector('.personal').addEventListener('touchend'.(e) = > { touchEnd(e ,this)})}}}</script>
Copy the code

With the touch. Js mentioned below, add touch listeners to the root element after Dom initialization and change the value of ShowSearch as you slide up. Here’s a trick: use the arrow function to pass this in. It’s time to deal with the Bug we’re talking about

touch.js

Separate maintained JS files to determine the relevant finger slide logic, placed in the utils directory.

var touchStartX = null
var touchStartY = null
export const touchStart=(e) = > {
    touchStartX = e.touches[0].clientX;
    touchStartY = e.touches[0].clientY;
}
export const touchEnd=(e,that) = > {
    let deltaX = e.changedTouches[0].clientX - touchStartX;
    let deltaY = e.changedTouches[0].clientY - touchStartY;
    if (Math.abs(deltaX) > 50 && Math.abs(deltaX) > Math.abs(deltaY)) {
        if (deltaX >= 0) {
            / / left smooth
        } else {
            / / right slide}}else if (Math.abs(deltaY) > 50 && Math.abs(deltaX) < Math.abs(deltaY)) {
        if (deltaY < 0) {
            / / slide
            that.showSearch = false
        } else{}}else{}}Copy the code

You can see that the showSearch in the Vue file has been changed in the touchEnd function with the slider logic passed in.

Get rid of it

You change the value of showSearch based on finger swipes, without considering the interaction within the form. To return to this Bug, since it is generated after the Picker component is displayed, fix it from here. Prepare a showStartPicker data, use it in the template, and change it dynamically. This allows you to know the state of the Picker component (shown or hidden), so you can unbind touch scroll events to subsequent pages when the Picker shell is on, and register them when the Picker shell is off.

Listen on the showStartPicker to do the above.

 watch: {
    showStartPicker(newVal){
        if(newVal) {
                this.unBindTouch()
        }else{
                this.bindTouch()
        }
    }
}
Copy the code

The final result

If there’s an easier way, feel free to ask in the comments section.