preview


preface

Demo gist address 👈

Do Web development often encounter list operations, if it does not involve mobile terminal, then put a few buttons on the list, the user clicks to finish. If it is mobile terminal, limited by the screen width, too many buttons will affect the layout, so it is common to slide the list on the mobile terminal.

Do native development, the system may provide a list of basic deletion functions, so how should the web page be implemented?

This article uses address management as a demo and react as an implementation. In fact, no matter what framework it is, most of the frameworks involved are web interfaces.

Demo uses Coroutine, which makes it easy to manage a series of event flows.

The principle of

Two things to deal with: sliding and layout

sliding

Slide events need to be listened for, and listeners should be set up on each item of the list, which handles slide events.

If mobile is listening for these three events:

  • Touchstart slides to start, recording the initial position
  • There’s a bunch of positions that are created when you swipe touchMove
  • Touchend slides to end and records the end position

Otherwise, listen for these:

  • mousedown
  • mousemove
  • mouseup
  • Mouseleave (leave it to Mouseup)

Listen for these events at the beginning of the lifecycle:

startupTouchEvent() {
  const current = ReactDOM.findDOMNode(this);
  current.addEventListener('touchstart'.this.moveLoop);
  current.addEventListener('touchend'.this.moveLoop);
  current.addEventListener('touchmove'.this.moveLoop);
}
Copy the code

Where this.moveLoop is:

this.moveLoop = coroutine(function* () {
      let e = {};
      while (e = yield) {
        if (e.type === 'touchstart') {
          // trace position
          const startX = e.touches[0].clientX;
          while (e = yield) {
            if (e.type === 'touchmove') {
              // trace position
              // console.log('touchmove', e);
              const movedX = e.changedTouches[0].clientX;
              const deltaX = movedX - startX;
              // console.log('moved', deltaX);
              if (deltaX <= 0) { that.moveMask(deltaX); }}if (e.type === 'touchend') {
              const endX = e.changedTouches[0].clientX;
              const deltaX = endX - startX;
              // console.log('end', deltaX);
              if (deltaX >= - 40) {
                that.closeMaskIfNeeded();
              } else {
                that.openMask();
              }
              break; }}}}})Copy the code

Corutine is used here.

First, record the position startX = e.touches[0]. ClientX; .

E.moveedtouches [0]. ClientX, subtract initial touches deltaX = movedx-startX; If deltaX is less than 0, then it is left to slide, do the UI operation, move the upper div left to deltaX.

When the finger leaves the screen, record the position and get the difference from the initial position deltaX = endx-startx. Judge deltaX. If the slide is too small (40px) or to the right, close the expanded div. So expand the div completely.

layout

      <div className="address-swipe-wrapper">
        <div className="swiper-operation-btns">
          <button style={{
            backgroundColor: '#7EA1D6'}}onClick={onEdit}>The editor</button>
          <button style={{
            backgroundColor: 'red'}}onClick={onDelete}>delete</button>
        </div>
        <div className="address-item" onClick={onClick} style={{
          left.position: 'relative',
          transition: 'all 250ms'}} >
          {selected &&
            <img className="address-item-selected-icon" src={require('./img/check.png')} alt="Selected" />
          }
          <div className="address-content">
            <div>{`${name}  ${mobile}`}</div>
            <div>{provinceName+cityName+districtName+detailedAddress}</div>
          </div>
        </div>
      </div>
Copy the code

The absolute layout of the address-item is overlaid by the action buttons. When the address-item is slid or expanded, it moves left by a relative distance.

To make sliding work, you can add transition: ‘All 250ms’.

A few other methods

  openMask() {
    this.setState({
      left: - 160.
    });
  }
  moveMask(deltaX) {
    this.setState({
      left: deltaX
    });
  }
  closeMaskIfNeeded() {
    this.setState({
      left: 0
    });
  }
Copy the code

summary

Will gestures swipe and click conflict?

PreventDefault () no, on PC and mobile (ios/ Android), it doesn’t trigger address-item selection, there’s no collisions, unless evt.preventdefault ().

How to achieve click blank close?

Add a listening event to window:

window.addEventListener('touchstart'.this.closeMaskIfNeeded);
Copy the code

It worked well on PC, but it was exceptional on Mobile. So moved to TODO to be solved.

TODO

  1. Wrapped in HOC
  2. Prohibit longitudinal sliding while horizontal sliding
  3. Click on the blank area to close the expanded item
  4. Add bounce to action buttons when expanding (Telegramx-ios right swipe)

reference

  • TouchEvents
  • mobile touch event – SO
  • swipe in react – SO