我可以在 Cordova 中运行 Fastclick ReactJS

Posted

技术标签:

【中文标题】我可以在 Cordova 中运行 Fastclick ReactJS【英文标题】:Can I Fastclick ReactJS running in Cordova 【发布时间】:2014-08-11 17:11:35 【问题描述】:

fastclick 可以与 ReactJS 的事件系统一起使用吗?通过 Cordova 在 iosandroid 上运行时似乎不需要。如果没有,是否有另一种获得相同结果的方法。我的应用没有双击功能,所以如果可能的话,我想全面消除这种延迟......

【问题讨论】:

【参考方案1】:

我们最近创建了一个类似于 fastclick 的 React 组件,只是它更简单并且需要手动回调。很短,所以我会在这里发布:

React.initializeTouchEvents(true)

var TouchClick = React.createClass(

  defaults: 
    touched: false,
    touchdown: false,
    coords:  x:0, y:0 ,
    evObj: 
  ,

  getInitialState: function() 
    return this.defaults
  ,

  handler: function() 
    typeof this.props.handler == 'function' && this.props.handler.apply(this, arguments)
  ,

  getCoords: function(e) 
    if ( e.touches && e.touches.length ) 
      var touch = e.touches[0]
      return 
        x: touch.pageX,
        y: touch.pageY
      
    
  ,

  onTouchStart: function(e) 
    this.setState( 
      touched: true, 
      touchdown: true,
      coords: this.getCoords(e),
      evObj: e
    )
  ,

  onTouchMove: function(e) 
    var coords = this.getCoords(e)
    var distance = Math.max( 
      Math.abs(this.state.coords.x - coords.x), 
      Math.abs(this.state.coords.y - coords.y) 
    )
    if ( distance > 6 )
      this.setState( touchdown: false )
  ,

  onTouchEnd: function() 
    if(this.state.touchdown)
      this.handler.call(this, this.state.evObj)
    setTimeout(function() 
      if ( this.isMounted() )
        this.setState(this.defaults)
    .bind(this), 4)
  ,

  onClick: function() 
    if ( this.state.touched )
      return false
    this.setState(this.defaults)
    this.handler.apply(this, arguments)
  ,

  render: function() 
    var classNames = ['touchclick']

    this.props.className && classNames.push(this.props.className)
    this.state.touchdown && classNames.push('touchdown')

    return React.DOM[this.props.nodeName || 'button'](
      className: classNames.join(' '),
      onTouchStart: this.onTouchStart,
      onTouchMove: this.onTouchMove,
      onTouchEnd: this.onTouchEnd,
      onClick: this.onClick
    , this.props.children)
  
)

只需将 handler 属性作为回调传递并将您的内容包装在其中。这也适用于同时具有触摸和点击事件的系统(如较新的 windows 8 笔记本电脑)。示例:

 <TouchClick handler=this.clickHandler className='app'>
   <h1>Hello world</h1>
 </TouchClick>

【讨论】:

我的意思是,这不是一个 wham-bam-thank-you-maam 类型的解决方案,它可以立即摆脱页面上所有内容的烦人点击延迟,是吗?这就是 Fastclick 的重点【参考方案2】:

它在我的 Cordova 应用程序中似乎运行良好,但我遇到了一个重大问题。

当使用 React+FastClick 点击一个元素,并且下一个渲染视图在相同位置包含一个可点击元素时,也会在第二个元素中注册一个 onTouchEnd 事件。

我放弃了 FastClick,因为我不想对齐按钮以避免不必要的行为,但我需要一些东西来替换它,因为点击延迟感觉很糟糕。

【讨论】:

我遇到了类似的问题,一个按钮会立即被点击,但在某些环境(Android 浏览器)中会在 300 毫秒后再次被点击。 react touch libs 中使用的点击事件插件添加了一个不错的 onTouchTap 回调,但它不适用于非触摸输入。制作一个 React 事件插件可能是要走的路。我还没有找到答案…… 感谢您提供的信息,事实上,在放弃 FastClick 之后,我仍然遇到了类似的“点击注册两次”问题,尽管应用程序的不同部分与以前不同。还没找到解决办法... @PirkkaEsko 所以 FastClick 不是您看到的onTouchEnd 问题的原因? 老实说,我不记得细节了,但我上面的评论表明 FastClick 不是根本原因,但可能与它们有关,因为行为发生了变化(问题发生在不同的移除 FastClick 后应用的一部分)。 我在 fastclick 和 react-tap-event-plugin 中都发现了这种行为。还没找到好的解决办法。【参考方案3】:

我在使用 David 的方法时遇到了问题,因此作为 FastClick 的替代方案,我使用 HammerJs 为事件实现了一个 mixin。 更多代码来设置事件,但工作正常。

var HammerClickMixin = React.createClass(
    componentWillMount: function() 
        this.listeneres = [];

    ,
    addTapEvent: function(element,callback) 
        var mc = new Hammer.Manager(element);
        mc.add(new Hammer.Tap( event: 'doubletap', taps: 2 ));
        mc.add(new Hammer.Tap( event: 'tap', taps: 1 ));
        mc.on('tap',callback);
        this.listeneres.push(mc);
    ,
    addDoubleTap : function(element,callback)
        var mc = new Hammer.Manager(element);
        mc.add(new Hammer.Tap( event: 'doubletap', taps: 2 ));
        mc.on('doubletap',callback);
        this.listeneres.push(mc);
    ,
    componentWillUnmount: function() 
        for(var i= 0; i < this.listeneres.length; i++)
            this.listeneres[i].destroy();
        
    
);

然后可以按如下方式使用:

 var Component = React.createClass(
          mixins: [HammerClickMixin],
          componentDidMount: function () 

              this.addTapEvent(this.refs.elementToClick.getDOMNode(),function()
                  //Handle fast hammer tap!

              );
          ,
          render: function () 
               return (
                        <div ref="elementToClick"/>                
                   );
          
      );

【讨论】:

【参考方案4】:

我在一个 Webpack 项目中让 FastClick 与 React 一起工作。有些事情看起来很挑剔,但它主要是有效的。 (更新:只有模拟点击隐藏复选框的切换开关有点挑剔——不管 React 是什么,这都是个问题)。这是我打开它的方法:

npm install -S fastclick

main.jsx:

import FastClick from 'fastclick';

window.addEventListener('load', () => 
  FastClick.attach(document.body);
);

因此,即使您不使用 Webpack 或 Browserify,我猜只要您可以运行加载事件侦听器,就可以了。

【讨论】:

这对我来说很完美。 FWIW,在我用 webpack 构建的同构反应应用程序中,我不得不使用 new webpack.NormalModuleReplacementPlugin(/fastclick$/i, 'node-noop') 在服务器构建上删除 fastclick 模块 @Federico 酷,如果我必须去同构,那就太好了! Soo... 我刚刚发现不幸的是,这个解决方案不能很好地使用 React 的 onClick 处理程序。它仅适用于您的通用 html 元素——锚点、按钮等。这是我发现的最好的:github.com/zilverline/react-tap-event-plugin 您看到了什么行为?我对onClick 处理程序没有任何问题。 您是否正在创建一个带有onClick 属性的 React 组件,但无论render() 返回什么,都没有将其传递给组件,以便最终在一个真正的 HTML 组件上结束?据我所知,React 组件上的 onClick 处理程序不会做任何事情,您必须将其传递给 HTML 元素。【参考方案5】:

你也可以使用 npm 中的react-fastclick(https://github.com/JakeSidSmith/react-fastclick):

npm i react-fastclick --save

使用它,您无需更改任何代码,而且效果非常好!您只需要求一次。

require('react-fastclick');

【讨论】:

【参考方案6】:

编辑

Facebook 决定 not add support for defining custom event types 并建议您使用类似 react-tappable 的内容,这样您就可以编写类似 &lt;Tappable onTap=&gt; 的内容。


Facebook 正在以TapEventPlugin 的形式开发解决方案,但它是won't be made available until they make some decisions。

如果您正在阅读本文,那么您可能正在从事一个等不及要等到他们弄清楚要如何发布它的项目。

这个 repo 适合你:https://github.com/zilverline/react-tap-event-plugin

当 Facebook 解决 #436 和 #1170 时,此 repo 将消失。

此解决方案适用于 React 0.14.x 和 15.x。

npm i -S react-tap-event-plugin

使用示例:

var React = require("react");
var ReactDOM = require("react-dom");
injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();

var Main = React.createClass(
  render: function() 
    return (
      <a
        href="#"
        onTouchTap=this.handleTouchTap
        onClick=this.handleClick>
        Tap Me
      </a>
    );
  ,

  handleClick: function(e) 
    console.log("click", e);
  ,

  handleTouchTap: function(e) 
    console.log("touchTap", e);
  
);

ReactDOM.render(<Main />, document.getElementById("container"));

请注意,使用注入器时,您可能只需要使用 onTouchTap(而不再使用 onClick)。

【讨论】:

仅供参考,onTouchTap 用作点击(对于非触摸屏)。 所以为了明确我现在应该使用 react-tap-event-plugin 还是 React-Tappable? 两者都有效,但 react-tappable 似乎是一个更合理的选择。没有猴子补丁。 谢谢,可能是这样,因为 react-tap-event-plugin 似乎因 react@15.3.2 而崩溃 只有移动浏览器才需要这个解决方案吗?

以上是关于我可以在 Cordova 中运行 Fastclick ReactJS的主要内容,如果未能解决你的问题,请参考以下文章

在离子2处失败'离子cordova运行android'

如何在Android后台服务中运行cordova插件?

PhoneGap/Cordova 应用程序是不是在 HTTP 下运行?

Ionic 2:Cordova 不可用。确保包含 cordova.js 或在设备/模拟器中运行(在模拟器中运行)

Cordova:在后台运行应用程序时的事件

Cordova 无法从 CLI 构建,但从 XCode xcworkspace 构建可以完美运行