essential information
Official introduction
Swiper is the free and most modern mobile touch slider with hardware accelerated transitions and amazing native behavior. It is intended to be used in mobile websites, mobile web apps, and mobile native/hybrid apps.
file
- introduce: https://swiperjs.com/get-star…
- API: https://swiperjs.com/api/
- Demo: https://swiperjs.com/demos/
- Git: https://github.com/nolimits4w…
Usage scene – transition effect
- Rotation chart
practice
target
Implement a special-shaped rotation chart. Support gesture left and right sliding to switch the center diagram.
Principle of realizing special-shaped rolling
Center page (class:swiper-slide-active
)scale:1
, other pages (class:swiper-slide
) scale
(0<x<1
)To achieve the effect of the center page in the user’s visual center.scale
The blank area is eliminated by the configuration item of the swiper (adjusting each swiper) + CSS style (overall element fine tuning).
Code reference (part)
index.vue:
<div class="gallery-wrapper">
<!-- Slider main container -->
<div class="swiper-container">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div
class="swiper-slide"
v-for="(item,index) in images"
:key="`${item.src}-index`"
>
<img
v-lazy="item.src"
:key="item.src"
class="image-content"
<v-touch
tag="div"
@tap="onTap(index)"
>
<img
class="scale-icon"
/>
</v-touch>
<!-- <div class="swiper-lazy-preloader">loading...</div> -->
</div>
</div>
</div>
</div>
style.less:
.swiper-container {
width: 100%;
height:100%;
}
.swiper-container > .swiper-wrapper{
/**Active pictures have shadows*/
overflow-y:visible;
/**
*Adjust the offset for the swiper
*Pre / next container frame leakage: 20
*Margin of design draft: 17.5
* 17.5 + 20 = 37.5px
*/
// margin-left:-0.375rem;
}
.swiper-slide {
position:relative;
box-sizing: border-box;
padding:0.3rem 0.3rem 0.9rem 0.3rem;
display: flex;
align-items: center;
justify-content: center;
transition: 300ms;
width:3rem;
height:4.25rem;
transform: scale(0.74);
background-image:url('../../../assets/art-picture/pic-border.png');
background-repeat: no-repeat;
background-position:center ;
background-size:100% 100%;
img[lazy="loading"] {
width: 0.3rem;
height:0.3rem;
}
}
.swiper-slide:not(.swiper-slide-active){
/**
*Calculate the margin error caused by scale
*Zoom of design draft: 0.74 container width / screen width of design draft currently playing: 300 / 375
*Error generated by scale: 300 * (1-0.74) = 78px
*Standard value 17.5
*Elimination error: 78 / 2 - 17.5 / 2 = 30.25px;
*/
// margin-left:-0.3025rem;
// margin-right:-0.3025rem;
/**
*Calculate the error caused by background shadow when vertically centered
*Actual position: 365 * 0.74/2 = 135.5
*Current position: 425 * 0.74/2 = 157.25
*Error: (157.25 - 135.5) / 2 = 11.1px
*/
margin-top:-0.111rem;
}
.swiper-slide-active{
transform: scale(1);
width: 3rem !important;
height:4.25rem !important;
/**
*Eliminate the error of margin calculation on the current playback container
*Margin effect: 78 / 2 - 30.25
*Elimination error: 17.5 - (78 / 2 - 30.25) = 8.75px
*/
// margin-left:0.0875rem !important;
// margin-right:0.0875rem !important;
}
js:
...
//Some configurations that need to be changed
get parameters() {
const parameters = {
spaceBetween: -0.225 * this.rootFontSize,
slidesOffsetBefore: 0.375 * this.rootFontSize,
slidesOffsetAfter: -0.375 * this.rootFontSize,
width: 3 * this.rootFontSize,
height: 4.25 * this.rootFontSize,
observer: true // handle async
};
if (this.images.length === 1) {
parameters.spaceBetween = 0;
}
return parameters;
}
public mounted() {
this.initRootFontSize();
this.initSwiper({
initialSlide: this.index
});
}
// get rem(root font-size)
public initRootFontSize() {
const html = document.getElementsByTagName('html')[0];
const rootFontSizeStr = html.style.fontSize;
this.rootFontSize = parseFloat(rootFontSizeStr);
}
public initSwiper(params= {}) {
const mySwiper = new Swiper('.swiper-container', {
slidesPerView: 1,
loop: false,
preloadImages: false, // preload images:false
lazy: false, // lazy load images
on: {
slideChange: this.onSlideChange,
sliderMove: () => {
if (this.slideStatus !== 'fadeInOut') {
this.slideStatus = 'fadeInOut';
}
},
touchEnd: () => {
this.slideStatus = 'fadeOut';
},
},
...this.parameters,
...params
});
this.mySwiper = mySwiper;
}
...
Trampled pit
Problems with scale:
- Although scale will reduce the element size, the original size space will not be released. Can refer tozoom vs transform:scaleThis creates a scaling gap between the elements
slidesPerView: Number
If the configuration property is set to a numerical value, it is likely that the central page will not appear well in the central pageloop:true
When, the third node will be copied. In other words, there are 10 items in the list, and there will be 3 * 10 = 30 nodes. When there are many nodes, it will affect the performanceloop:true
When switching between the beginning and the end, clicking swiper will not trigger the click event. Click will not be triggered on the swiper slideon:tap(swiper,event)
This is triggered by clicking on any page. However, if the event test on the PC is excellent (including the path attribute), there is only istrud on the real machine. You can’t know which element the user specifically ordered
Solution I
- use
margin-left: x<0
;margin-right<0
To eliminate zoom spacing [there will be problems with horizontal and vertical screen switching] slidesPerView:'auto'
Better use- prohibit
loop:true
- use
on:tap
Need to be careful, real machine testing is indispensable
Perfect realization of abnormity (support horizontal and vertical screen switching)
Although the negative margin is set through the above margin to achieve the special-shaped effect visually, the problem of changing the style is found during the horizontal and vertical screen switching.
Reason: the way you modify the swiper wrapper and slider by using CSS style will not be counted by swiperjs, resulting in problems in the calculation of translate.
Solution 1: center the activity card by yourself
{
slidesPerView: 1,
loop: false,
preloadImages: false, // preload images:false
lazy: false, // lazy load images
}
Solution 2: how to remove sclae margin without CSS style
After use, it is found that this will be set to the slider: space between. You can use this instead of the previous CSS margin setting, and the distance will be calculated by swiepr.
Centeredslides is left by default. How to solve the centering effect of the first card?
Therefore, after calculating the value, you can set it:
{
spaceBetween: -0.3025 * this.rootFontSize,
slidesOffsetBefore: 0.375 * this.rootFontSize,
slidesOffsetAfter: -0.375 * this.rootFontSize,
}
Why set slidesoffsetafter?
If it is not set, the border bug will appear when dragging left and right.
Solution 3: screen size adaptation (screen of different models | horizontal and vertical screen switching)
- The value swiper set in solution 2 only supports Px, so REM must be set → px
- You need to get the latest REM and update the swiper when the horizontal and vertical screens are switched
public mounted() {
this.initRootFontSize();
this.initSwiper();
window.addEventListener('resize', this.resizeHandler, false);
}
public initRootFontSize() {
const html = document.getElementsByTagName('html')[0];
const rootFontSizeStr = html.style.fontSize;
this.rootFontSize = parseFloat(rootFontSizeStr);
}
public resizeHandler() {
this.initRootFontSize();
/** update swiper params */
this.mySwiper.params.spaceBetween = -0.3025 * this.rootFontSize;
this.mySwiper.params.slidesOffsetBefore = 0.375 * this.rootFontSize;
this.mySwiper.params.slidesOffsetAfter = -0.375 * this.rootFontSize;
this.mySwiper.update();// Key APIs
}
In this way, the layout display is no problem, but for special-shaped cards, the width and height of inactive cards may change. If you have strict requirements on the width and height of the slider, you need to specify the width and height in the configuration:
{
height:4.25 *
this.rootFontSize,
width:3 * this.rootFontSize,
}
You can extract functions that change configuration:
//Some configurations that need to be changed
get parameters() {
return {
spaceBetween: -0.225 * this.rootFontSize,
slidesOffsetBefore: 0.375 * this.rootFontSize,
slidesOffsetAfter: -0.375 * this.rootFontSize,
width: 3 * this.rootFontSize,
height: 4.25 * this.rootFontSize,
observer: true // handle async
};
}
public initSwiper(params= {}) {
const mySwiper = new Swiper('.swiper-container', {
slidesPerView: 1,
loop: false,
preloadImages: false, // preload images:false
lazy: false, // lazy load images
on: {
slideChange: this.onSlideChange
},
...this.parameters,
...params
});
this.mySwiper = mySwiper;
}
public resizeHandler() {
this.initRootFontSize();
/** update swiper params */
Object.keys(this.parameters).forEach(key => {
const value = this.parameters[key];
this.mySwiper.params[key] = value;
});
this.mySwiper.update();
}
Solution 4: asynchronously loading data and card layout
Usually, the list is obtained from the interface and then set. You may encounter the problem of abnormal card layout display. At this time, you can try the following in the configuration:
{
observer:true
}
This will update the element layout.
Solution 5: after the above four steps are completed, the leaflet shows the problem of leaning to the left
//Handle the style problem of pasting left when there is only one picture
if (images.length === 1) {
this.mySwiper.params.spaceBetween = 0;
this.mySwiper.update();
}
summary
Solutions to achieve the perfect opposite sex:
- spaceBetween/slidesOffsetBefore/slidesOffsetAfter
- observer: true
optimization
- v-lazy
- v-touch