preface

This article is about the pit record of The Vue mobile terminal project based on better-Scroll, mainly focusing on the problems caused by the better-Scroll plug-in in the project.

Of course, there will also be a section on other plugins and techniques.

Please refer to the table of contents below for details.

navigation

  • Why use Better Scroll

  • Better – scroll profiles

  • Specific on pit

    • Initialization complete but unable to scroll
    • Error in TAB page scrolling with Vant’s Tabs component
    • Switch TAB page to scroll to the top, occasionally invalid
    • On ios devices, the touch screen during scrolling causes the page to shake in a high degree
    • Basic common configurations for instantiation


  • Other step pits or technology
    • Use less features to reuse custom styled Vant components
    • SwiperJs to customize the rotation image, the loop property caused the image load failure
    • Some problems with using native Video tags in wechat






Why use Better Scroll

In fact, the core of the beginning was to solve:

The feature of wechat’s built-in browser to display web page information, resulting in page dynamic effect disorder

“.

As you can see, the wechat browser is really weird (and the bottom navigation bar on ios, for example). I was curious about why there was a default drop-down behavior and what it meant, so I immediately looked it up online. However, according to the results of the query does not seem to get a detailed and reasonable explanation, probably because wechat browser is embedded webView, and Webview in the small program application needs to have the default behavior of the drop-down refresh, although wechat browser does not need to pull down refresh, but still retains this mechanism… Emm… All right! There might be a better reason to keep the mechanic, though I haven’t found it yet, but the project needs to get done, so I started working on it. Of course, to solve this problem, going directly to disable the touchMove event of the page is obviously not a safe solution, so…







Better – scroll profiles

introduce

Iscroll scrolllibrary was actually known long before BS, but it has stopped maintenance. And Better Scroll is a plug-in to solve the mobile terminal scrolling scene rewritten based on IScroll, API compatible with IScroll, and optimized. Compact size and powerful function.


Rolling principle

Put a picture on the official website first, it will be more intuitive and clear.

The wrapper is the parent and the Content is the child. When the child exceeds the height of the parent, you can start scrolling.

This scrolling principle is very important, I just didn’t pay special attention to the leading in advance, so WHEN I used it directly, I found that no matter how I scroll, it didn’t work.

The underlying principle is to implement animations based on the requestAnimationFrame API.






Specific on pit

Initialization complete but unable to scroll

<div class="wrapper" ref="wrapper">
  <div class="content">
    <router-view />
  </div>
</div>
Copy the code
import Bscroll from "@better-scroll/core";

export default {
  mounted() {
    let scroll = new BScroll(this.$refs.wrapper, {}); }};Copy the code


There are many reasons why you can’t scroll after initialization, but the first one is very important: the timing of the instantiation.

1. BScrollThe instantiation of the$nextTickIn the callback function of.

mounted() {
  this.$nextTick((a)= > {
    let scroll = new BScroll(this.$refs.wrapper, {})
  })
}
Copy the code

This is because we can’t calculate whether to add scrolling until the DOM is rendered until we make sure we get the element we need to add scrolling, and the height of the scrolling parent and child elements.


2. The DOM hierarchy is incorrect

The ContentDOM must be the first child of the Wrapper. This is the official website to use the method to give the regulation, just follow.


3. The parent element is not set to a fixed height or the child element is not taller than the parent element

This one is easy to understand, simple and important. This is the fundamental reason why SCROLLING doesn’t work for me without reading the lead.

Be sure to give the parent a fixed height, because normally the height of the parent element is spread out by the child element, and scrolling is enabled when the child element is higher than the parent element, so the fixed height of the parent element is key.

.wrapper {
  weight: 100vw;
  height: 100vh;
}
Copy the code

When the content child reaches more than one screen, it scrolls naturally, while any element other than the Wrapper does not scroll.

So at this point, whether the page can scroll or not, wechat’s built-in browser drop-down behavior has been prevented, but the stomping continues.




Error in TAB page scrolling with Vant’s Tabs component

If you understand the principle of leading rolling, then this problem is basically not a problem.

In fact, at the beginning of the TAB page to see my performance is meng, I thought a good TAB page scrolling how the problem, fidgeting.

If you think about it for a moment, it’s as simple as dynamically changing the height of the child element when switching TAB pages, but the plugin doesn’t know that. When you first enter the page, the plug-in gets the height of the page, and everything is fine. The TAB page is a display switch for several divs. Switching the TAB page changes the content height, so let the plugin get it again. Looking for API – >

Ps: If it is a layout level application, remember to store the instantiated Scroll in the Store.

export default {
  computed: {
    ...mapState({
      scroll: (state) = > state.layout.scroll,
    }),
  },
  methods: {
    tabChange() {
      this.$nextTick((a)= > {
        this.scroll.refresh(); }); ,}}};Copy the code

Again, you need to call refresh in the $nextTick callback for the same reason.




Switch TAB page to scroll to the top, occasionally invalid

In the whole project, I used the Tabs component in three pages. However, this problem did not appear when I made the first Tab page. But when I finished all the pages, the first Tab page I made started to work…

Specifically, after switching the TAB page, you cannot scroll to the top, and the preset active time becomes slow, as if it has been stopped halfway.

export default {
  methods: {
    tabChange() {
      this.scroll.scrollTo(0.0.500); // Parameter: x coordinate y coordinate dynamic effect time animation function

      this.$nextTick((a)= > {
        this.scroll.refresh(); }); ,}}};Copy the code

I’m thinking that scrolling to the top has nothing to do with calculating the height of the page, so the scrolling action can theoretically be performed before scroll.refresh() without any problems.

Despite this, my repeated attempts to change the execution order of scrollTo and Refresh have had no effect. Amazingly, the other tabs don’t have any bugs, and if I remove the active time parameter, the bug will disappear.

this.scroll.scrollTo(0.0); // There are no bugs
Copy the code

The only thing I’ve done is change the configuration options for instantiating Better-Scroll:

{
  useTransition: false.// I added this property
}
Copy the code

However, I actually have to need this configuration, as discussed in a later section. This option basically switches the page scrolling effect from CSS transition to JS. The intention is to optimize the page scrolling performance with the default CSS configuration.

I suspect that the scrollTo method executed after a configuration change conflicts with the Refresh method, that scrolling is interrupted by refresh, and so on, so I focus on how to get the scrollTo method executed after refresh.

tabChange() {
  this.$nextTick((a)= > {
    this.scorll.refresh();
    this.scorll.scrollTo(0.0.500); / / is invalid
  });
};
Copy the code
tabChange() {
  this.$nextTick(async() = > {this.scorll.refresh();
    await this.scorll.scrollTo(0.0.500); / / is invalid
  });
};
Copy the code

Finally, I remembered seeing one

The $nextTick() method returns a promise without returning the call function

If I create a Macro task and let scrollTo execute after the $nextTick callback ends, it will be a micro task.

tabChange() {
  setTimeout((a)= > {
    this.scroll.scrollTo(0.0.500)},0)

  this.$nextTick((a)= > {
    this.scroll.refresh()
  })
}
Copy the code

It was a success

Although the problem was finally solved, it is still unclear what causes the failure of scrollTo method and whether my conjecture is correct.

From a thinking point of view, to switch a TAB page, you should execute the refresh function to redefine the page information required by the BS instance, and then the scrollTo function to scroll the page to the appropriate position. The most likely cause of this bug is that scrolling is disabled when the refresh function is triggered while the page is in a scrolling state due to the incorrect order of execution.

Whether there is a more elegant solution, as well as the exploration of bugs and so on to supplement in the future.




On ios devices, the touch screen during scrolling causes the page to shake in a high degree

In the early stage of the project, I didn’t notice this problem at all. When I reviewed the whole project, I found that the scrolling effect of this page was not ideal. I always felt strange, but I couldn’t put my name to it.

I logged out of the phone’s home screen, opened the Settings, and started swiping. That fluid feeling… Cutting back and swiping quickly discovered the problem – people don’t wait for the last slide animation to finish before they swipe the next one, they usually click and swipe continuously, and the page doesn’t have any problems. But on ios, the touch screen will make the page scroll height shake once during sliding. Continuous sliding creates continuous jitter, which is a serious problem…

I have checked the issue on the official website and made the following suggestions:

{
  useTransition: true; // Use this configuration
}
Copy the code

Ok… After all, CSS is also flawed, we can not lose the performance of the experience, so much more smooth sliding.

This problem is relatively simple to solve, the key is how to find the problem. Sometimes simple Google or Baidu will not give you a satisfactory answer. At this time, the issue on the official website or some foreign platforms (Stack Overflow) may be very helpful and efficient.




Basic common configurations for instantiation

import BScroll from "@better-scroll/core";

export default {
  mounted() {
    this.$nextTick((a)= > {
      let scroll = new BScroll(this.$refs.wrapper, {
        // Found page can't trigger click events add them
        click: true.tap: true.// * Trigger the type of scroll event, 3 is real-time trigger
        probeType: 3.// allow y scrolling
        scrollY: true.// Excessive rebound effect when scrolling to both ends of the page, default is true
        bounce: false.// Use javascript to implement scrolling
        useTransition: false.// * Allows the tag name regex to fire the default event
        preventDefaultException: {
          tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO|VIDEO|IMG)$/,}}); }); }};Copy the code
  • There are two key points here. One isprobeType

This property is simply the frequency at which the listening event is triggered. In the project I needed to capture the direction of the slide screen in real time to make the top navigation slideDown effect. So at first I found that there was no response from the scroll event listening, I thought it was an API update. Scroll event will not trigger when probeType is 1…

Then the specific effect of the corresponding value, you can go to the API documentation to see, not to repeat. However, in general, probeType 3 is still required in most cases to fulfill the complex requirements of a project.

  • The other one ispreventDefaultException

Literally, this is a regular expression. There is a preventDefault property in the configuration and the default is true. This property disables most of the default behaviors, and it is not recommended to change this option. But we can restore the default behavior of some of the tags with the preventDefaultException property. This is also important, and the official default is

{ tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO)$/,}Copy the code

These. Because I used img and video tags in the project. Images require long press recognition, and video’s default controls require default behavior, so simply put the label name into the regular expression.






Other step pits or technology

Use less features to reuse custom styled Vant components

Often there will be some strange design in the project, and the existing UI library will not be able to be used directly. For example, the TAB page design in my project, they call it immersive.

A normal TAB page would look like this:

Title page | | label

The three areas do not interfere with each other, but there is linkage.

And here’s what we did:

Yes, in a certain tags show: the content of half | | tag page title with an immersive backgrounds.

The new TAB structure must look like this:

In this way, you can customize the style of the entire header + content area.

After a little bit of modification and try, finally completed the modification of the style. (At the same time, pay attention to the correct position of the bar action effect at the bottom of the label), the code is as follows:

/deep/ .van-tabs__wrap {
  position: absolute;
  width: 90vw;
  height: 42px;
  top: 100px + 48px;
  transform: translate(5vw);
}
/deep/ .van-hairline--top-bottom::after {
  border: 0;
  border-bottom: 1px solid rgba(51, 51, 51, 0.1);
}
/deep/ .van-tabs__nav {
  justify-content: space-between;
}
/deep/ .van-tab {
  width: 60px;
  flex: 0;
  flex-basis: 70px;
}
Copy the code

It is important, then, that the component styles modified in this way should be applied to all the tabs in the project to prevent the same requirements from appearing on other pages in the future. This string of style code is obviously redundant to copy in each component.

This string of code can be neatly put into a namespace using the ability of less encapsulation.

// global.less #custom-vant { .absolute_tab { /deep/ .van-tabs__wrap { position: absolute; width: 90vw; height: 42px; top: 100px + 48px; transform: translate(5vw); } /deep/ .van-hairline--top-bottom::after { border: 0; Border-bottom: 1px solid rgba(51, 51, 51, 0.1); } /deep/ .van-tabs__nav { justify-content: space-between; } /deep/ .van-tab { width: 60px; flex: 0; flex-basis: 70px; }}}Copy the code

When used, the style code is very succinct:

@import url(".. /.. /assets/css/global.less");

.tabs {
  #custom-vant.absolute_tab(a); }Copy the code

Remember to include global LESS files when using it. In the same way, you can define global variables such as theme colors.

// global.less
#theme_color {
  @purple: rgba(73.56.141.1);
  @gray: rgba(153.153.153.1);
  // ...
}
Copy the code
@import url(".. /.. /assets/css/global.less");
.box {
  background: #theme_color[ @purple ];
}
Copy the code

About the use of less, the document above has been very detailed, so more use skills are welcome to discuss learning.




SwiperJs to customize the rotation image, the loop property caused the image load failure

Swiper’s rotation graphics are really powerful and can achieve a lot of effects. But the documentation is really not very good…

The quickest way to do this is to look at the sample code on the official website and use it directly. But that’s not always the way to go, and the design can be a bit off. In short, the project has a round casting requirement as follows:

Our requirement is not exactly the same as the example on the official website, because the first and second banners are not fully displayed, and half of them are hidden outside. This is easy to do, just pull the div out of the screen and center it.

The problem is, the wheel feed graph needs to loop indefinitely. When I added the loop attribute, the first n graphs of the first graph failed to load.

So you can only see four incoming images. I originally thought that because of the way I introduced it, I changed the image address to a static path, and the online address was useless.

<div class="swiper-container">
  <div class="swiper-wrapper">
    <div class="swiper-slide" v-for="(item, index) in swiperList" :key="index">
      <VanImage class="swiper-img" :src="..." fit="cover" />
    </div>
  </div>
</div>
Copy the code
export default {
  mounted() {
    this.$nextTick((a)= > {
      new Swiper(".swiper-container", {
        slidesPerView: 3.// You can see 3 banners
        spaceBetween: 8.// The gap between the images
        centeredSlides: true.// Whether to center the display
        loop: true.// loop display}); }); }};Copy the code

Finally, I noticed a strange detail, the undisplayable Image, showing the default Image of the Vant component Image, and the Image has a very thin border, as if there is an Image underneath, hidden by the Image in the default Alt attribute. It’s amazing.

I later abandoned the Vant component and replaced it with a native IMG component, and the bug was fixed. Perhaps because of the infinite loop, the duplicate image is a copy of the HTML fragment, no JS code, and the Vant component does not receive the address of the image, so it defaults to the image with the Alt attribute. It looks like the image load failed.

It seems likely that incompatibilities will occur when different components are combined. So be careful when you choose to use it.


By the way, the style of item in the rotation chart should also be written by yourself. Go to the official website directly to see the example, the style can be used directly.

// The surrounding banner image is scaled by 0.8 and is written in CSS
.swiper-slide {
  / /...

  /* Center slide text vertically */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transition: 300ms;
  transform: scale(0.8);
}
.swiper-slide-active..swiper-slide-duplicate-active {
  transform: scale(1);
}
Copy the code

Also, when using Swiper in a VUE project, you need to manually introduce swiper styles, which is another common reason why styles don’t work.

// less
@import url(".. /.. /.. /node_modules/swiper/css/swiper.min.css");
Copy the code




Some problems with using native Video tags in wechat

The root of the problem is a series of disgusting problems caused by the different kernel of Andiord and wechat browser on ios.

  • Android wechat browser kernel is X5
  • Ios wechat browser kernel is chrome kernel

Ios side performance is actually very good, the key is to android side compatible processing.

Top priority! Do not add this property:

<video x5-video-player-type="h5" />
Copy the code

Don’t! This is a big hole, don’t try to make compatibility based on this property. This property means to declare same-tier H5 player enabled.

If you have a good compatibility solution based on the same layer H5 player, you can discuss it.

The rest are compatible properties that implement inline playback. The commonly used properties are roughly as follows

<video
  preload="auto"
  x5-video-orientation="portraint"
  x5-video-player-fullscreen="true"
  x5-playsinline=""
  playsinline=""
  webkit-playsinline=""
  x-webkit-airplay
  controls="controls"
  class="video"
  ref="video"
  src="https://hxy-web1.oss-cn-hangzhou.aliyuncs.com/meiye/wuqihua_vlog_v5.mp4"
  style="object-fit:fill"
/>
Copy the code

Added default control components, portrait processing, full screen playback, and inline playback compatibility.

It is also important to note that poster is generally not recommended for a more consistent user experience. Directly locate a picture and button in the same position, click and play the video directly.

Finally, there is one unsolved problem:

The video of wechat browser of Android terminal will have inexplicable black edges, which will appear up and down, or left and right according to the width and height ratio. The thickness is also different, but it will not disappear.

I consulted the community, but did not find a reasonable reply. I don’t know if you have a good way to solve this problem.






conclusion

The article doesn’t have too much technical depth and basically describes the pitfalls of applying a technical point to a project in very generic terms. There will be many not rigorous and mature place, also welcome everybody to discuss together. This article is also contributed to the use of Better-Scroll colleagues, encountered the same problem can be used for reference and discussion.

Please let me know if there is any forwarding (of course there is no, I’m gone…).

Ps: this article is first published in my blog, although it is still under construction, I need your encouragement and support, please click a “like” if it is helpful to you.

See you next time.