current position:Home>Vue Za wiper technical scheme

Vue Za wiper technical scheme

2022-04-29 13:07:03NEXT_ FE

demo.gif

Preface

When I was doing business recently , The product students put forward such a demand :

vue-za-swiper-function.png

After looking for open source, there is no suitable , So I decided to write a . General idea and main reference Swiper, monitor touchmove event , The dynamic change translateX To achieve sliding , Set a specific... When sliding to the boundary translateX Create a circular sliding effect . This paper mainly introduces the technical scheme of gesture sliding and button sliding , When reading articles, you can combine Warehouse code Read together .

img.png

This article will be followed by this 8 A list of elements as an example , hypothesis Swiper Container Container visual elements are 4 individual , Explain ZSwiper Gesture sliding and button sliding functions .

initialization

As shown in the figure above , To avoid sliding left to the far left or right to the far right , The sliding distance is too large , And when you can't see the elements , We need to copy an array and split it into two parts , Spliced in the original head and tail .

initDoubleList() {
  const mid = Math.floor((this.list.length / 2));
  this.halfLen = mid;
  this.doubleList = [ ...this.list.slice(mid), ...this.list, ...this.list.slice(0, mid) ]
}
 Copy code 

Then calculate the position of the left boundary , Will be the first 1 Elements , That's the index 4 The elements of , Put it on the far left of the container . Calculate the position of the right boundary , For later calculation .

initTranslateX() {
  const translateX = this.getDomTranslateX() - this.itemFullWidth * this.halfLen;
  this.setDomTranslateX(translateX);
  return Math.abs(translateX);
},

mounted() {
  this.initItemFullWidth();
  const initialTranslateX = this.initTranslateX();
  this.leftBorder = initialTranslateX;
  this.rightBorder = this.itemFullWidth * this.list.length + initialTranslateX;
}  
 Copy code 

Gestures slide left and right

img_13.png

As shown in the figure above , The idea of gesture sliding is relatively simple , The main difficulty is when the slide reaches the boundary , How to make a cycle . Combined with the above 2 Look at the picture , For example, we keep sliding to the right , Slide to the right border (RightBorder) When , take translateX Return to the left boundary (LeftBorder), The effect of scrolling to the right is infinite .

touchstart(evt) {
  const touch = evt.targetTouches[0];

  this.lastX = touch.pageX;
  this.translateX = this.getDomTranslateX();
}

touchmove(evt) {
  const touch = evt.targetTouches[0];
  const xDiff = touch.pageX - this.lastX;

  this.lastX = touch.pageX;
  this.setMove(xDiff);
}

setMove(xDiff) {
  this.translateX += xDiff;
  const translateXAbs = Math.abs(this.translateX);

  if (translateXAbs >= this.rightBorder) {
    this.translateX = -(this.leftBorder + (translateXAbs - this.rightBorder));
  } else if (translateXAbs <= this.leftBorder) {
    this.translateX = -(this.rightBorder - (this.leftBorder - translateXAbs));
  }

  this.setDomTranslateX(this.translateX);
}
 Copy code 

Click the button to slide

Click slide left

Next, click the left button to slide as an example to explain . Because the element may be truncated when you click the button , Product students want the truncated elements to be fully visible after the sliding stops , Disassemble the requirements and turn them into the following :

img_1.png

Let's look at the overall process first , As shown in the following code , The user clicks the button to trigger handleSlide(), Set the animation properties first , And then call _slidePrev() Refresh translateX Animation effect appears , Remove the animation attributes after the sliding animation .

mounted() {
  //  Use  throttle  Avoid problems with animation caused by users' fast and continuous clicks 
  this.handleSlide = throttle(() => {
    Object.assign(this.$refs.swiperWrapper.style, {
      'transition-duration': `${ this.slideAnimationDuration }ms`,
    });

    this.translateX = this.getDomTranslateX();
    this._slidePrev();
    
    setTimeout(() => {
      Object.assign(this.$refs.swiperWrapper.style, {
        'transition-duration': '0ms',
      });
    }, this.slideAnimationDuration);

  }, this.slideAnimationDuration + 200, {
    trailing: false,
  });
},
methods: {
  getObserveEntries() {
    return new Promise((resolve) => {
      const observer = new IntersectionObserver((entries) => {
        observer.disconnect();

        resolve(entries);
      }, {
        root: this.$refs.swiperBody,
      });

      this.$refs.swiperItems.forEach((el) => {
        observer.observe(el);
      });
    })
  },
  _slidePrev() {
    this.getObserveEntries().then(((entries) => {
      const lastVisibleIndex = entries
        .findLastIndex((item) => item.intersectionRatio >= this.intersectionRatioThreshold)

      const isAllVisible = entries
        .filter((item) => item.intersectionRatio >= this.intersectionRatioThreshold).length === this.halfLen

      const targetIndex = isAllVisible ? lastVisibleIndex - 1 : lastVisibleIndex
      const target = entries[targetIndex]

      const xDiff = target.rootBounds.right - target.boundingClientRect.right
      this.translateX += xDiff
      this.setDomTranslateX(this.translateX)

      const translateXAbs = Math.abs(this.translateX)
      setTimeout(() => {
        if (translateXAbs <= this.leftBorder) {
          this.translateX = -(this.itemFullWidthValue * (targetIndex - this.halfLen + 1 + this.list.length))
          this.setDomTranslateX(this.translateX)
        }
      }, this.slideAnimationDuration)
    }))
  },
}
 Copy code 

So let's see _slidePrev() , utilize IntersectionObserver API We know that all four elements are just visible ,

img_2.png

Or is it not all visible . Calculate the displacement according to different conditions xDiff, Then compare with the current translateX Carry out operations , You can get the next position translateX. The red element in the figure represents the... In the code target, And the orange element means we want to end up in Swiper Container The leftmost element . because Swiper Container It's just right 4 Elements visible , So as long as target Move to the far right , The orange element must be on the far left .

img_3.png

img_4.png

The following figure shows after sliding , Entering the left boundary . At this time targetIndex yes 6, To make a cycle , Our goal is to make the index 14 The element of appears in Swiper Container Far right . however translateX The positioning of is from Swiper Container From the far left , That is, if the index is 11 The brown element appears on the far left , The rightmost element over there must have an index of 14 The elements of . From this, we can deduce the following formula to calculate finalTranslateX

if (translateXOpt <= this.leftBorder) {
  // targetIndex: 6
  // halfLen: 4
  // 6 + 1 - 4 + 8 = 11
  this.translateX = -(this.itemFullWidth * (targetIndex + 1 - this.halfLen + this.list.length));
  this.setDomTranslateX(this.translateX);
}
 Copy code 

img_5.png

There's a point to note , The boundary calculation should be put into setTimeout Medium wait transition-duration Only after being removed . Otherwise it will be because of translateX The process of changing from the right boundary to the left boundary is animated , Will appear 「 Turned a circle 」 Strange animation effects .

Click and slide right

The calculation method of right slip is basically the same as that of left slip , Here are two pictures to show xDiff, The calculation method will not be expanded .

img_6.png

img_7.png

The following figure shows after sliding , Entering the right boundary . At this time targetIndex yes 12, To make a cycle , Our goal is to make the index 4 The brown element appears in Swiper Container Leftmost , Move the length of an array forward . From this we can deduce the following formula :

if (translateXAbs >= this.rightBorder) {
  this.translateX = -(this.itemFullWidthValue * (targetIndex - this.list.length))
  this.setDomTranslateX(this.translateX)
}
 Copy code 

img_9.png

End .

Related links

copyright notice
author[NEXT_ FE],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/04/202204291306572347.html

Random recommended