zoukankan      html  css  js  c++  java
  • 【react】基于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={{  size.width + 'px', height: size.height + 'px' }}
                onMouseOver={() => stopPlay()}
                onMouseLeave={() => autoPlay()}
            >
                {/* 图片展示轮播 */}
                <ul className={styles.picContent} id="picContent">
                    {data.map((item) =>
                        <li key={`rotate${item.key}`} style={{  size.width + 'px' }}>
                            <a href={item.action}>
                                <img style={{  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

  • 相关阅读:
    Atitit.eclise的ide特性abt 编译
    Atitit python3.0 3.3 3.5 3.6 新特性 Python2.7新特性1Python 3_x 新特性1python3.4新特性1python3.5新特性1值得关注的新特性1Pyth
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.eclipse 4.3 4.4  4.5 4.6新特性
    atitit.错误:找不到或无法加载主类 的解决 v4 qa15.doc
    Atitit RSA非对称加密原理与解决方案
    Atitti.数字证书体系cer pfx attilax总结
    Atitit ftp原理与解决方案
    Atitit qzone qq空间博客自动点赞与评论工具的设计与实现
    Atitit 软件国际化原理与概论
  • 原文地址:https://www.cnblogs.com/leftstan/p/15208856.html
Copyright © 2011-2022 走看看