ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【react】基于umi框架编写轮播图组件

2021-09-22 20:36:42  阅读:318  来源: 互联网

标签:const 轮播 com pics react width https ind umi


引言

基于该文仿写:web 完整轮播图——带只拖鞋去流浪 https://zhuanlan.zhihu.com/p/138232728

组件源码:https://gitee.com/leftstan/rotation.git

组件效果:https://www.jianguoyun.com/p/Dd81zscQzLDdCRiKuo4E

 

 

 

创建项目

创建一个umi2.x的项目

选择项目类型为app,不使用ts

npm create umi

 

安装依赖

yarn

 

运行项目

yarn start

 

组件调用

data为需要展示图片的数据

size轮播图组件尺寸

delay为播放时延(可选)

const data = [{   key: "1",   src: "https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/a532e33470d046b3f044d5ea49fc5e9e.png?thumb=1&w=1226&h=460&f=webp&q=90",   action: "https://www.mi.com" }, ... ]   <div>   {/* 轮播图数据 */}   {/* 轮播图尺寸, 单位px*/}   {/* 轮播时延 */}   <Rotation      data={data}      size={{ width: '1200', height: '480' }}      delay={2000}>    </Rotation> </div>

  

 

编写组件

 html布局为三部分内容

图片,导航按钮,上/下一页

        <div
            className={styles.content}
            style={{ width: size.width + 'px', height: size.height + 'px' }}
            onm ouseOver={() => stopPlay()}
            onm ouseLeave={() => autoPlay()}
        >
            {/* 图片展示轮播 */}
            <ul className={styles.picContent} id="picContent">
                {data.map((item) =>
                    <li key={`rotate${item.key}`} style={{ width: size.width + 'px' }}>
                        <a href={item.action}>
                            <img style={{ width: size.width + 'px', height: size.height + 'px' }} src={item.src} id={`rotate${item.key}`} />
                        </a>
                    </li>
                )}
            </ul>

            {/* 底部导航按钮跳转 */}
            <ul className={styles.dotButton}>
                {data.map((item, index) =>
                    <li
                        className={`${styles.dot} ${Math.abs(btn) === index ? styles.current : ''}`}
                        key={`btn${index}`} id={`btn${index}`}
                        onClick={() => jump(index)}
                    >
                    </li>
                )}
            </ul>

            {/* 上下页按钮 */}
            <div className={`${styles.btn} ${styles.left}`} onClick={() => {
                prev();
            }}><</div>
            <div className={`${styles.btn} ${styles.right}`} onClick={() => {
                next();
            }}>></div>
        </div>

  

无缝切换

需要在图片【盒子尾部】插入一份第一张图片;

当播放到【最后一张图】(数据最后一张),要跳转到第一张图时,执行动画操作跳转到我们插入到【盒子尾部】的【第一张图片的副本】

此时再播放下一张时,先无动画跳转到【第一张图片】,再执行动画操作跳转到【第二张图片】

 

使用react hooks定义需要用到的参数

useState进行定义

//图片数据
    const [data, setData] = useState(props.data);
    //图片尺寸
    const [size, setSize] = useState(props.size);
    //图片宽度
    const [width, setWidth] = useState(size.width > 0 ? size.width : 1200);
    //右下角导航按钮当前选项
    const [current, setCurrent] = useState(0);
    const [btn, setBtn] = useState(0);
    //自动播放计时器
    const [timer, setTimer] = useState();

 

useEffect中进行初始化

useEffect(() => {
        //获取单张图片宽度
        const wid = size.width > 0 ? size.width : 1200;
        setWidth(wid);
        //设置图片盒子宽度
        let pics = document.getElementById('picContent');
        pics.style.width = (data.length + 1) * width + 'px';
        // 将第一张图片 clone 到最后
        let firstLi = pics.firstChild.cloneNode(true);
        pics.appendChild(firstLi);
        //设置自动播放
        autoPlay();
    }, [])

 

下一页

    const next = () => {
        let pics = document.getElementById('picContent');
        let len = pics.children.length - 1;
        let ind = current;
        //无动画,从尾部跳转到第一张图片
        if (ind >= len) {
            ind = 0;
            pics.style.left = 0;
        }
        ind++;
        //跳转动画
        animate(pics, -width * ind);
        //更新导航按钮
        setCurrent(ind);
        ind >= len ? setBtn(0) : setBtn(ind);
        // console.log("next is: ", ind)
    }

 

底部导航按钮跳转

   const jump = (ind) => {
        let pics = document.getElementById('picContent');
        animate(pics, -width * ind);
        setCurrent(ind);
        setBtn(ind);
    }

 

动画效果

//动画对象,结束帧位置(目标位置)
    const animate = (obj, target) => {
        clearInterval(obj.timer);
        obj.timer = setInterval(() => {
            var leader = obj.offsetLeft;
            var step = 30;
            //设置不同动画方向
            step = leader < target ? step : -step;
            if (Math.abs(leader - target) >= Math.abs(step)) {
                leader += step;
                obj.style.left = leader + 'px';
            } else {
                obj.style.left = target + 'px';
                clearInterval(obj.timer);
            }
        }, 10)
    }

 

自动播放

react hooks与setInterval

在react hooks中直接使用setInterval无法达到预期的效果,需要使用useReducer

(具体缘由参考该文:https://www.cnblogs.com/qcloud1001/p/10408634.html)

//设置自动播放
    const autoPlay = () => {
        setTimer(setInterval(() => {
            dispatch('inc');
        }, props.delay));
    }
    //取消自动播放
    const stopPlay = () => {
        clearInterval(timer);
        setTimer(null);
    }
    const [count, dispatch] = useReducer((state, action) => {
        if (action === 'inc') {
            next();
        }
    }, 0);

  

  

参考资料:

https://v2.umijs.org/zh/guide/create-umi-app.html#%E5%88%9B%E5%BB%BA-umi-%E9%A1%B9%E7%9B%AE

https://zhuanlan.zhihu.com/p/138232728

https://www.cnblogs.com/qcloud1001/p/10408634.html

 

标签:const,轮播,com,pics,react,width,https,ind,umi
来源: https://www.cnblogs.com/leftstan/p/15208856.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有