React-swiper
+ react-intersection-observer
实现图片在可视范围内时加上其对应动图
一、前言 ⭐️
最近项目里遇到一个需求⚽️:在一个页面里需同时展示
5
张动图😎。那么。。。为了提高性能,防止卡顿,前端就需要进行单页面多动效优化处理啦🤔,处理方式如下:🌸
- 页面一来先展示
5
张静态图片,只有当某张静态图片进入可视范围内时,才给其加上其对应的动图;未在可视范围内的,就不加上其对应的动图。
二、实现效果 ⭐️
三、实现步骤 ⭐️
1、安装react-intersection-observer
用react-intersection-observer判断是否在可视范围内。
yarn add react-intersection-observer
或者
npm install react-intersection-observer --save
2、安装swiper
实现图片轮播,我安装的是
swiper3
版本,版本根据需求选择即可。
「React
-swiper
的运用 可查看我的另外一篇博客」
npm i swiper@3
或者
yarn add swiper@3
3、到package.json
里去判断是否安装成功
4、对应代码 ⭐️
我分为了三大点:「小萝卜儿们🥕依据这三个点查看对应代码哟」
- 一、【判断是否在可视范围内】
- 采用react-intersection-observer判断5张图片中的哪一张图片出现在可视范围内了。
- 二、【图片匀速轮播】
- 「项目需要」让5张图片实现匀速向下滚动的效果。
- 三、【是否展示动图】
- 对应索引值的图片出现在可视范围内了,就给其加上对应动图。
scenesPage.jsx
import React, { useEffect, useState } from "react";
import { InView } from 'react-intersection-observer'; // 【判断是否在可视范围内】
import Swiper from "swiper"; // 【图片匀速轮播】—— 引入swiper,实现轮播
import { SvgaPlayer } from '@spark/animation'; // 公司内部的组件【动图】
import {RES_PATH} from '../../sparkrc.js';
import "./scenesPage.less"; // 引入样式【根据自己需求编写】
function ScenesPage() {
// 【是否展示动图】—— 在state里设置变量currentIndex,初始值为0,改变变量的方法名为setCurrentIndex
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
// 【图片匀速轮播】—— 初始化swiper
new Swiper('.swiper-container1', {
direction: 'vertical', // 垂直方向
freeMode: true, // 设置为true则变为free模式
freeModeMomentum : false, // free模式下,若设置为false则关闭动量,释放slide之后立即停止不会滑动。【详情参考官网,对应位置截图放在最后面啦】
// speed: 6000, // 匀速时间【在这儿不要加匀速时间,避免在第一页继续往上拉或最后一页继续往下拉出现大片空白区域的情况出现】
onTouchEnd: function (swiper, event) { // 回调函数,当释放slider时执行。【详情参考官网,对应位置截图也放在最后面啦】
let t1 = swiper.translate;
setTimeout(
function () {
// console.log(swiper);
let t2 = swiper.translate;
console.log(t1);
console.log(t2);
// 判断slide「上滑」、「下拉」、「点击」
// if (t1 < t2) {
// console.log('上滑');
// } else if (t1 > t2) {
// console.log('下拉');
// } else {
// console.log('点击');
// }
if (t1 > t2 && swiper.isBeginning) { // 在第一页继续向前拖动则toast提示
// console.log('下拉');
Toast('精彩内容已为你呈现咯,请往下滑动选择喔~', 1000);
}
if (t1 < t2 && swiper.isEnd) { // 在最后一页继续向后拖动则toast提示
// console.log('上滑');
Toast('您已浏览全部场景,快选择场景生成你的专属标签吧~', 1000);
}
}, 30);
}
});
}, []);
// 场景静图和动图-最好写在utils/constans.js里封装成公共的,避免代码冗余
const scenes = [{
imgSrc:`${RES_PATH}场景/场景一.png`,
motionGraph: `${RES_PATH}svga/场景1.svga`,
},{
imgSrc:`${RES_PATH}场景/场景二.png`,
motionGraph: `${RES_PATH}svga/场景2.svga`,
},{
imgSrc:`${RES_PATH}场景/场景三.png`,
motionGraph: `${RES_PATH}svga/场景3.svga`,
},{
imgSrc:`${RES_PATH}场景/场景四.png`,
motionGraph: `${RES_PATH}svga/场景4.svga`,
},{
imgSrc:`${RES_PATH}场景/场景五.png`,
motionGraph: `${RES_PATH}svga/场景5.svga`,
}]
return (
<div className="scenesPage">
{/* 【图片匀速轮播】—— Swiper */}
<div className="swiper-container swiper-container1">
<div className="swiper-wrapper swiper-wrapper1">
{
scenes.map((item, index) => {
return (
<div className="swiper-slide swiper-slide1"} key={index}>
{/* 【判断是否在可视范围内】—— 需要判断哪些内容是否在可视范围内,就把这些内容写在InView里面 */}
<InView as="div" onChange={(inView, entry) => {
console.log(`第${index + 1}张图 出现:`, inView);
if (inView) { // inView:true-在可视范围内;false-不在可视范围内
setTimeout(() => { // 定时器可加可不加,根据实际需求来
// 【是否展示动图】—— 改变变量currentIndex的值为index,相当于:currentIndex = index(赋值)
setCurrentIndex(index);
}, 500)
}
}}>
{/* 静图 */}
<img src={item.imgSrc} alt="" />
</InView>
{
// 【是否展示动图】动图 —— currentIndex等于index,就展示对应静图的动图;否则,不展示
currentIndex == index && <SvgaPlayer
className="motionGraph"
src={item.motionGraph}
/>
}
</div>
)
})
}
</div>
</div>
</div>
);
}
export default ScenesPage;
scenesPage.less
@import "../../../node_modules/swiper/dist/css/swiper.css"; /* 【图片匀速轮播】*/
/* 公共方法 【图片匀速轮播】 */
.swiper-container {
width: 100%;
height: 100vh;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
/* 非公共方法 */
.scenesPage {
position: relative;
.swiper-slide1 {
width: 750px;
height: 1334px;
position: relative;
img,.motionGraph {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 100%;
height: 100%;
object-fit: cover;
}
}
/*【图片匀速轮播】*/
.swiper-container1>.swiper-wrapper1 {
-webkit-transition-timing-function: linear; /*之前是ease-out*/
-moz-transition-timing-function: linear;
-ms-transition-timing-function: linear;
-o-transition-timing-function: linear;
transition-timing-function: linear;
margin: 0 auto;
}
}
sparkrc.js
module.exports ={
"RES_PATH": "/src/assets/",
}
当当当当~大功告成🌶
【补充1】swiper3
-freeModeMomentum
属性
【补充2】swiper3
-onTouchEnd
属性
官网:https://3.swiper.com.cn/api/callbacks/2014/1217/89.html