移動端APP列表點透事件處理方法

來源:互聯網
上載者:User

標籤:lin   settime   效能   解決方案   tip   const   script   比較   方法   

關於點透事件這裡不再贅述,如果不清楚的可以上網搜一搜,或者看小火柴的這篇文章。

這裡是自己在做移動端時,在列表滑動的時候,遇到的點透問題。出現這個問題的來由是因為在轉場的時候,各個手機的轉場效果不一樣,有的比較好,但是在有些低端機上,轉場顯得有點卡,於是就把過渡效果去掉了,因此就是直接的路由切換。【具體事件具體分析,可能我遇到的問題並不適合你,這裡只是貼出來共用】

先看下面兩張圖片:


點擊列表頁的按鈕會切換到下一個頁面,但是在下一個頁面上的每一個條目都是可以點擊的,這時就會觸發了下一個頁面的彈窗,事實上我們並不想直接顯示這個彈窗,而是要等待使用者點擊。

你可能在項目中的列表頁寫了如下的一段代碼:

render() {    return (        <ul className="list">            {                 list.map((l, index) => {                    return (                        <li key={ `list${index}` } onClick={ () => doSomething() }>                            { `item${index}` }                        </li>                    )                })              }        </ul>    );}

在一個列表中的每個項目上綁定了點擊事件,但是當點擊之後切換到下一頁。當時移動端的點擊事件都會有300ms的延遲,因此在切換了頁面之後,瀏覽器會再次判斷點擊的行為,此時如果下一個頁面都有可以觸發點擊的元素,這時候就觸發了下一個頁面的點擊行為。

於是,你可能會這麼做,將onClick事件換成onTouchEnd事件

<li     key={ `list${index}` }     onTouchStart= { event => event.preventDefault() }    onTouchEnd={ () => doSomething() }>    { `item${index}` }</li>

但是,每次滑動的時候,其實你也觸發了onTouchEnd事件,於是每次滑動你都會點擊進入到下一頁。於是你又想,加上一個onTouchStart事件,然後阻止掉預設事件,尼瑪發現滑都滑不動了。

因此針對常用的幾種解決點透事件的方法,我想了幾種解決方案:

方案一:自己類比Tap事件

大致的代碼如下:

var list = document.querySelector('#list');var dragState = {};list.addEventListener('touchstart', function(event) {    var touch = event.touches[0];    dragState.startTime = new Date();    dragState.startLeft = touch.pageX;    dragState.startTop = touch.pageY;    dragState.startTopAbsolute = touch.clientY;});list.addEventListener('touchmove', function(event) {    var touch = event.touches[0];    dragState.currentLeft = touch.pageX;    dragState.currentTop = touch.pageY;    dragState.currentTopAbsolute = touch.clientY;});list.addEventListener('touchend', function() {    var dragDuration = new Date() - dragState.startTime;    var offsetLeft = dragState.currentLeft - dragState.startLeft;    var offsetTop = dragState.currentTop - dragState.startTop;    if (dragDuration < 300) {        var fireTap = Math.abs(offsetLeft) < 10 && Math.abs(offsetTop < 10);        if (isNaN(offsetLeft) || isNaN(offsetTop)) {            fireTap = true;        }        if (fireTap) {            alert('tap');        }    }    dragState = {};});

判斷水平位移差和垂直位移差都小於10像素,並且touchstarttouchend的時間差小於300ms時,即認為觸發了Tap事件。

方案二:加入轉場動畫

既然是因為轉場動畫在某些機型上比較卡的原因造成的,那麼如果不是太考慮效能的話,可以加上轉場動畫,關於react中的轉場動畫,時間大概在300ms就好,可以看我之前對於轉場代碼的研究:react-css3-transition-group

方案三:在目標頁面加入遮罩層

在目標頁面加上一層透明的彈層,使上一個頁面的點擊在此彈層上失效,具體做法為使用一個高階組件,在高階組件中添加一個定時器,在每個頁面載入的時候產生一個彈層,400ms之後消失彈層即可。

import React from 'react';const styles = {    modal: {        width: '100%',        height: '100%',        position: 'absolute',        top: 0,        left: 0,        right: 0,        bottom: 0,        zIndex: 20,        backgroundColor: 'transparent'    }};const ComponentWrapper = MyComponent => {    const ComponentTemplate = React.createClass({        getInitialState() {            return {                modal: true            };        },        componentDidMount() {            this.modalInter = setTimeout(() => {                this.setState({ modal: false });            }, 400);        },        componentWillUnmount() {            this.hideTips();            this.modalInter && clearTimeout(this.modalInter);        },        render() {            return (                <Page style={ this.props.style }>                    <MyComponent { ...this.props } container={ this } />                    { this.state.modal && <div style={ styles.modal }></div> }                </Page>            )        }    });    return ComponentTemplate;};export default ComponentWrapper;

另外在0.13.3版本的react還支援mixins的時候,可以添加如下代碼:

import React from 'react';import ReactDOM from 'react-dom';const styles = {    modal: {        width: '100%',        height: '100%',        position: 'absolute',        top: 0,        left: 0,        right: 0,        bottom: 0,        zIndex: 20,        backgroundColor: 'transparent'    }};const clickThroughMixin = {    getInitialState() {        return {            clickThroughModal: true        }    },    componentDidMount() {        this._renderModal();        this.modalInter = setTimeout(() => {            this._modalTarget && ReactDOM.unmountComponentAtNode(this._modalTarget);            this._modalTarget.remove();        }, 400);    },    componentWillUnmount() {        this.modalInter && clearTimeout(this.modalInter);    },    _renderModal() {        if (!this._modalTarget) {            this._modalTarget = document.createElement('div');            this._container = this._getContainerDOMNode().appendChild(this._modalTarget);            ReactDOM.unstable_renderSubtreeIntoContainer(                this, (<div style={ styles.modal }></div>), this._modalTarget            );        }    },    _getContainerDOMNode() {        const node = ReactDOM.findDOMNode(this), body = document.body;        return node ? node.parentNode || body : body;    }};export default clickThroughMixin;

移動端APP列表點透事件處理方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.