zoukankan      html  css  js  c++  java
  • React编写一个移动H5的纵向翻屏组件

    前言

    • 由于工作需要,需要做一版在手机上查看的H5的广告页。广告页面基本都是一块内容占满一屏,然后上滑下滑就翻页,所以需要一个这样的翻页功能。

    代码实现

    • 废话不多说,直接上代码
    /**
     * 一个放置多个满屏页面的容器,支持上下滑动
     */
    // ScrollBox.jsx
    import React, { Component } from 'react';
    
    import './ScrollBox.less';
    
    class ScrollBox extends Component {
    
        state = {
            pageIndex: 0, // 当前在第几屏,从0开始算
        }
    
        startY = 0; // touch的起始Y坐标
    
        handleTouchMove = (e) =>  {
            const y = e.changedTouches[0].clientY;
            const deltaY = y - this.startY;
            const height = this.root.offsetHeight;
            const len = this.props.list.length;
            const pageIndex = this.state.pageIndex;
            if(pageIndex === 0 && deltaY > 0) {
                return;
            }
            if(pageIndex === len - 1 && deltaY < 0) {
                return;
            }
            this.scrollBox.style.top = `${-(height * pageIndex - deltaY)}px`;
        }
    
        handleTouchStart = (e) => {
            this.startY = e.changedTouches[0].clientY;
        }
    
        handleTouchEnd = (e) => {
            const { list = [] } = this.props;
            let { pageIndex } = this.state;
            const y = e.changedTouches[0].clientY;
            const deltaY = y - this.startY;
            const len = list.length;
            if(deltaY > 50) {
                if(pageIndex > 0) {
                    pageIndex -= 1;
                }
            } else if(deltaY < -50) {
                if(pageIndex < len - 1) {
                    pageIndex += 1;
                }
            }
            this.setState({
                pageIndex
            }, () => {
                this.anmateFunc();
            })
        }
    
        anmateFunc = () => {
            const currentStr = this.scrollBox.style.top;
            let current = 0;
            if(currentStr) {
                current = Number(currentStr.slice(0, currentStr.length - 2));
            }
            const height = this.root.offsetHeight;
            const target = -(height * this.state.pageIndex);
            const delta = target - current;
            const part = delta / 20;
    
            const moveOnce = (i) => {
                this.scrollBox.style.top = `${current + (i * part)}px`;
                if(++i < 21) {
                    ((index) => {
                        setTimeout(() => {
                            moveOnce(index);
                        }, 10);
                    })(i)
                }
            }
            moveOnce(1);
        }
    
        componentDidMount() {
            this.root = document.getElementById('root');
            this.root.addEventListener('touchstart', this.handleTouchStart);
            this.root.addEventListener('touchend', this.handleTouchEnd);
            this.root.addEventListener('touchmove', this.handleTouchMove);
        }
    
        componentWillUnmount() {
            this.root.removeEventListener('touchstart', this.handleTouchStart);
            this.root.removeEventListener('touchend', this.handleTouchEnd);
            this.root.removeEventListener('touchmove', this.handleTouchMove);
        }
    
        render() {
            const { list = [] } = this.props;
            const { pageIndex } = this.state;
            return (
                <div 
                    className="ScrollBox"
                    ref={scrollBox => this.scrollBox = scrollBox}
                >
                    {
                        list.map((child, index) => {
    
                            return (
                                <div className={`page ${pageIndex === index ? 'active' : ''}`} style={{ background: colors[index] }} key={`page-${index}`}>
                                    <div style={{ fontSize: '1rem' }} className={`animate ${index % 2 === 0 ? 'animate-slideLeft' : 'animate-slideRight'}`}>
                                        {
                                            child
                                        }
                                    </div>
                                </div>
                            )
                        })
                    }
                </div>
            )
        }
    }
    
    const colors = ['red', 'orange', 'yellow', 'green'];
    
    export default ScrollBox;
    
    // ScrollBar.less
    .ScrollBox {
        position: absolute;
        top: 0;
        left: 0;
        .page {
             100vw;
            height: 100vh;
        }
    
          // 当页面滑到可视区域时,可以添加一个active的类,方便做动画的管理,只有当页面出现到可视区域才加上动画效果,否则就不加。因为广告页大多是需要动画效果的
        .active {
            .animate {
                animation-timing-function: ease-in-out;
                animation-duration: 0.6s;
                animation-iteration-count: 1;
                &-slideLeft {
                    animation-name: slideLeft;
                }
                &-slideRight {
                    animation-name: slideRight;
                }
        
                @keyframes slideLeft {
                    0% {
                        transform: translateX(100%);
                    }
                    100% {
                        transform: translateX(0);
                    }
                }
                @keyframes slideRight {
                    0% {
                        transform: translateX(-100%);
                    }
                    100% {
                        transform: translateX(0);
                    }
                }
            }
        }
    }
    
    // 使用
    <ScrollBox
       list={['page1', 'page2', 'page3', 'page4']}
    />
    

    小结

    • 先记一下,以后如果有更好的思路再优化,先暂时用着
  • 相关阅读:
    ORACLE 循环
    C#生成指定数目的互不相同的随机数(转)
    Oracle自治事务的介绍
    螺旋矩阵--我的实现方法
    一个体育生的编程之路(一)
    判断十二星座——我的算法,大家看是不是比较简便
    简单的排序算法——插入排序,选择排序,交换排序(冒泡排序,快速排序)
    使用VC和DirectShow从摄像头中读取图像(一)
    1999那个追着打我的女生
    我自己写的几个C++常用方法
  • 原文地址:https://www.cnblogs.com/aloneMing/p/13576119.html
Copyright © 2011-2022 走看看