react合成事件的使用

使用react + webpack4 + antd-mobile + scss 参见:https://github.com/yangdongMC/react-mobile.git
效果图如下(gif图被压缩,请见谅):
这里写图片描述

需求大致是这样:

  1. 一个导航栏可以左右(横向)滑动,
  2. 操作后,再点击任意一个,可以保持在可视区,

第一步好实现,一个父元素让其overflow-x:scroll,子元素(ul)长度为:导航栏个数*固定值,但是第二步在react中如何实现?

先回顾一下在jquery时代是怎么实现的:
$('.parent').animate({scrollLeft:($('.parent li.active').index()-2)*$width},500);
在真实dom操作时,找到overflow-x:scroll;的元素,因为只有它有该css样式,它的scrollLeft才会生效,不然一值是0,然后找到点击那个的index,一系列减乘,此时animate动画又秀了一波

但是,这是react,单向数据流,但是导航栏的位置的移动跟数据单项还是双向好像关系不大,又不想用jquery来实现,react事件合成SyntheticEvent貌似可以解决,先了解一下合成事件的定义、如何用?

1.React合成事件一套机制:React并不是将click事件直接绑定在dom上面,而是采用事件冒泡的形式冒泡到document上面,然后React将事件封装给正式的函数处理运行和处理。
2.如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免这类DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。
3.当用户在为onClick添加函数时,React并没有将Click时间绑定在DOM上面。
4.而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装交给中间层SyntheticEvent(负责所有事件合成)
5.所以当事件触发的时候,对使用统一的分发函数dispatchEvent将指定函数执行。

class Test extends Component {
    constructor() {
        super(arguments);
        this.onReactClick.bind(this);
    }
    componentDidMount() {
        const parentDom = ReactDOM.findDOMNode(this);
        const childrenDom = parentDom.queneSelector(".button");
        childrenDom .addEventListen('click', this.onDomClick, false);
    }
    onDomClick() {  // 事件委托
        console.log('Javascript Dom click');
    }
    onReactClick() {  // react合成事件
        console.log('React click');
    }
    render() {
        <div>
            <button className="button" onClick={this.onReactClick()}>点击</button>
        </div>
    }
}
上述代码执行结果:
Javascript Dom click
React click

下面是导航栏实现方法:

import React from 'react';
import ReactDOM from 'react-dom';
import fetch from 'node-fetch';
import { baseUrl } from '../../utils/config';
import './index.scss';
import classnames from 'classnames';
import eventProxy from '../../utils/eventProxy';

class CateGroys extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            platform: props.platform,
            categroys: [],
            defaultActive: '',
            currentIdx: 0,
            width: document.body.clientWidth / 5
        };
    }

    fetchCategroy = (platform) => {
        fetch(`${baseUrl}/platforms/${platform}/categorys`).then(response => response.json()
        ).then(json => {
            const { data } = json;
            this.setState({
                ...this.state,
                categroys: data.data,
                defaultActive: data.data.length ? data.data[0].id : ''
            })
        })
    }

    componentDidMount() {
        this.fetchCategroy(this.state.platform);
        //注册滚动事件
        const parent = ReactDOM.findDOMNode(this);
        const $child = parent.querySelector('.categroysNav');

        parent.addEventListener('click', this.parentDOMscroll, false);

    }

    //获取index
    idx = (arr, text) => {
        let i = '';
        arr.map((item, index) => {
            if (item.title === text) {
                return i = index;
            }
        })
        return i;
    }
    //父原生dom
    parentDOMscroll = (event) => {
        //兼容写法安卓、苹果
        let path = event.path || (event.composedPath && event.composedPath());
        path.map((item, index) => {
            if (item['className'] === 'categroysNav') {
                path[index].scrollLeft = (this.idx(this.state.categroys, event.target.innerText) - 2) * this.state.width;
            }
        });
    }

    //静态方法,获取不到this
    static getDerivedStateFromProps(props, state) {
        if (props.platform !== state.platform) {
            //如果platform更新,那么就要对它的兄弟组件table数据请求参数进行修改
            eventProxy.trigger('platform', props.platform);
            //通过returnstate.platform的值进行更新
            return {
                platform: props.platform
            }
        } else {
            return null
        }

    }
    //通过静态方法中修改类platform,再在下面方法中更新categroy请求
    //上面的静态方法先执行
    componentDidUpdate(prevProps, prevState) {
        if (prevProps.platform !== this.state.platform) {
            this.fetchCategroy(this.state.platform)
        }

    }

    //categroy nav click
    handlerNav = (id, index) => {
        this.setState({
            ...this.state,
            defaultActive: id,
            currentIdx: index
        });
        //$('.rank_filtrate_classify_over').animate({scrollLeft:($('.rank_filtrate_classify_over li.active').index()-2)*$width},500);
        //发布订阅事件
        eventProxy.trigger('category', id)

    }

    render() {
        return <div >
            <div className="categroysNav">
                <ul style={{ width: `${this.state.categroys.length * 68}px` }}>
                    {
                        this.state.categroys.length ? this.state.categroys.map((item, index) => <li onClick={() => this.handlerNav(item.id, index)} key={item.id} className={classnames({ 'active': this.state.defaultActive == item.id })}><span>{item.title}</span></li>) : <li>暂无数据</li>
                    }
                </ul>
            </div>
        </div>
    }
}
export default CateGroys
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值