网易音乐版轮播-react组件版本此版本轮播图为仿照网易云音乐PC播放器上首页的轮播。 网易的轮播特殊的地方就在于,如果
说明:
此版本轮播图为仿照网易云音乐PC播放器上首页的轮播。
网易的轮播特殊的地方就在于,如果你滑动不相邻的两张图片,其过渡效果并不是滑动过渡,而是一个跳出过渡,此方面原理与最开始设计轮播排版时候有极大关联。
此轮播为纯react环境下的es6写法,通过对state中数组的重组排列,配合样式。达到轮播的效果
无任何依赖,最终效果为封装成react组件开放接口并发布出去
注:此文章为正推,并在开发完成后进行总结优化。
一、搭建架构
此方面的文章应该很多,我就不必过多介绍,去github上找个react脚手架搭建一下基本项目框架即可。
我用的框架为改良过的一版本dva框架。react脚手架,github上很多,推荐自己选择一款进行改良,我用的并不一定适合你。
二、准备材料
1.大于4张尺寸相同图片。(本人为八张图片命名1-8) 2.react环境 3.网易云PC播放器
三、开发
先把首张图片和左右两侧能看见的图片位置摆好, 最开始的静态结构是这个样子的 新手注意:如发现代码刺眼,less、es6语法自行恶补
import React from 'react';
import styles from './Slide.less';
class Slide extends React.Component {
constructor(props) {
super(props);
this.state = {
dir: [
{ name: 'middle' },
{ name: 'start' },
{ name: 'normal' },
{ name: 'normal' },
{ name: 'normal' },
{ name: 'normal' },
{ name: 'normal' },
{ name: 'end' },
],
};
}
render() {
const { dir } = this.state;
return (
<div key={key} className={styles.root}>
{/* 外部容器*/}
<div className={styles.slideBox}>
{/* 内部循环*/}
{
dir.map((item, key) => {
return (
<div className={`${styles.slide} ${styles[item.name]}`}> // 此处偷懒
<img src={`./images/${key + 1}.png`} // 此处偷懒 alt="./images/404.png" />
<div // 蒙板
className={styles.masking}
>{''}</div>
</div>
);
})
}
</div>
</div>
);
}
}
export default Slide;
less如下
.root{
width: 100%;
background: #ccc;
.slideBox{
width: 50%;
height: 15vw;
margin: 0 auto;
position: relative;
background: #ccc;
.slide{
position: absolute;
img{
width: 100%;
}
.masking{ // 蒙板,有个灰度渐变的效果
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .15);
}
&.middle{ // 此为中间展示的那张
left: 10%;
bottom: 0%;
width: 80%;
z-index: 33;
}
&.start{ // 第一张则为左侧那张
left: 0%;
bottom: 0%;
width: 75%;
z-index: 22;
}
&.end{ // 最后一张及右侧那张
right: 0%;
bottom: 0%;
width: 75%;
z-index: 22;
}
&.normal{ // 此为隐藏图片的样式
left: 13%;
bottom: 0%;
width: 74%;
z-index: 11;
}
}
}
}
这样最开始的位置就摆好了。
隐藏图片的位置很重要,因为上面也说了,跨图片滑动时需要改成跳出效果。大概在如下位置,展示的那张图片完美的将其挡住。
接下来,进行事件添加。我们先不管轮播下方的一排导航点。先加上左右点击操作。
在蒙板层加上onClick操作,(也可以加在slide层) 如下:
<div
className={item.name === 'middle' ? '' : styles.masking}
onClick={() => this.slide(item.name, key)}
>{''}</div>
点击图片时的方法
slide(name, key) { // 图片点击逻辑
// 记录当前节点
this.setState({ current: key });
// 数组操作方法
this.imgArr(name);
}
数组操作方法
imgArr(name) { // 数组处理
let dirCopy = this.state.dir;
if (name === 'start') { // 点击左侧那张
const pop = dirCopy.pop(); // 从数组尾部弹出一个元素
dirCopy.unshift(pop); // 尾部元素添加到数组头部
} else if (name === 'end') { // 点击右侧那张
const shift = dirCopy.shift(); // 从数组头部弹出一个元素
dirCopy.push(shift); // 添加到数组尾部
}
this.setState({ dir: dirCopy }); // 保存重新排列的数组 并触发render
}
过渡样式添加
1.过渡样式主要有旋转时,蒙版层的渐变。 2.旋转时平滑的定位过渡。 3.旋转时层级的变化放在优化环节单独讲解。
.slide{
... , // 此处为原样式保留的意思(下面都以此规则显示)
transition: all 0.3s ease-in-out;
user-select: none; // 禁止用户选中(防止图片被选中时变色);
&:hover{ // 鼠标经过时显示小手样式
cursor: pointer;
}
}
.masking{
... ,
transition: all 0.3s 0.2s linear;
}
&.middle{
... ,
.masking{
background: transparent;
}
}
这个样子的话点击图片左右两侧时就可以初步旋转起来了。
到此为止的步骤所完成的样式轮播为最基础的‘旋转木马es6版本’,有需要的朋友已经可以在以上代码中进行优化总结,放在自己的项目中去。
菜单按钮开发 动态的根据图片的数量循环出菜单按钮的数量,代码跟图片循环类似。
<div className={styles.slideBox}>
... ,
{/* 导航按钮*/}
<div className={styles.point}>
{
this.state.dir.map((item, key) => { // 根据图片数量进行循环
return (
<span
key={key}
className={item.name === 'start' ? styles.hover : ''} // 给予当前显示的按钮样式变化
onMouseEnter={() => this.pointFunc(key - 1)} // 鼠标进入动画
>{}</span>
);
})
}
</div>
</div>
样式方面:
.point{
width: 100%;
position: absolute;
left: 0;
bottom: -23px;
z-index: 999;
text-align: center;
span{
display: inline-block;
width: 20px;
height: 3px;
background-color: #2E3033;
margin-left: 9px;
&.hover{
background-color: #7F8082;
}
&:hover{
cursor: pointer;
}
}
}
鼠标进入方法pointFunc();
pointFunc(index) { // 按钮点击
const { current } = this.state;
const dirCopy = this.state.dir;
if (index < current) { // 鼠标经过左侧的按钮
for (let i = 0; i < (current - index); i += 1) { // 判断距离
const shift = dirCopy.shift(); // 进行数组操作
dirCopy.push(shift);
}
} else if (index > current) { // 鼠标经过右侧的按钮
for (let i = 0; i < (index - current); i += 1) {
const pop = dirCopy.pop();
dirCopy.unshift(pop);
}
}
this.setState({ dir: dirCopy }); // 触发react-render重新渲染页面
this.setState({ current: index }); // 记录当前图片节点
}
加完按钮图片后效果如下:
这个时候,核心效果已经出来了,经过严谨的布局和动画调节后,最终达到了预期的网易播放器的特殊动画效果。(鼠标经过相邻的图片时为滑动,经过不相邻图片按钮的时候改为跳动效果)。
代码效果
注:样式方面还有需要优化的地方请自行调节
总结
在这个组件模式开发时代,如果你做的东西不能保留下来并且开放出去,我认为是一件可悲的事情。所以下一篇文章将把此react组件进行开放式处理,开放一些可调节接口、响应式处理,并且最后打包成npm包,以插件的形式开放出去。
转载自:https://juejin.cn/post/6844903566205779975