React停止该元素上的其他事件

时间:2017-02-17 15:57:38

标签: javascript html css reactjs events

我有一个音量元素,当用户将鼠标悬停在音量栏上时会显示音量条。这一切都适用于桌面。但是,要在移动设备上获得相同的功能,用户可以点击音量元素,同时切换静音点击事件。

当用户在移动设备上点击(即点按)该元素时,我想停止该静音事件。

我不想修改Mute或VolumeBar类来修复它,因为这些是我的库中开发人员使用的泛型类。

https://jsfiddle.net/jwm6k66c/2145/

  • 实际:触发静音点击事件并打开音量栏。
  • 预期:静音点击事件不会被触发,音量栏会打开。

打开控制台 - >进入移动视图(在chrome上按CTRL + SHIFT + M) - >单击音量按钮并观察控制台日志。

我尝试了什么:

当音量条的高度为0(即不可见)时,使用volumeControlOnClick来停止传播,但这并不会取消onClick。

我想要的是什么:

如果用户第一次在移动设备中点击了音量图标,则取消静音点击事件。相反,它应该只显示音量条。

const volumeControlOnClick = (e) => {
  const volumeBarContainer =
    e.currentTarget.nextElementSibling.querySelector('.jp-volume-bar-container');
  /* Stop propogation is for mobiles to stop
    triggering mute when showing volume bar */
  if (volumeBarContainer.clientHeight === 0) {
    e.stopPropagation();
    console.log("stop propogation")
  }
};

class Volume extends React.Component {
  constructor(props) {
    super(props);

    this.state = {};
  }
    render() {
    return (
        <div className="jp-volume-container">
        <Mute onTouchStart={volumeControlOnClick}><i className="fa fa-volume-up" /></Mute>
        <div className="jp-volume-controls">
          <div className="jp-volume-bar-container">
            <VolumeBar />
          </div>
         </div>
       </div>
    );
  }
};

class Mute extends React.Component {
    render() {
    return (
      <button className="jp-mute" onClick={() => console.log("mute toggled")} onTouchStart={this.props.onTouchStart}>
        {this.props.children}
      </button>
    );
  }
};

class VolumeBar extends React.Component {
    render() {
    return (
        <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>
        {this.props.children}
      </div>
    );
  }
};

React.render(<Volume />, document.getElementById('container'));

2 个答案:

答案 0 :(得分:1)

只要您使用气泡阶段,您可以使用标记表示您在处于鼠标事件之前处于触摸事件中。因此,将监听器附加到容器元素,如下所示:

let isTouch = false;

const handleContainerClick = () => isTouch = false;

const handleMuteClick = () => {
  if (isTouch == false) {
    console.log("mute toggled");
  }
};

const volumeControlOnClick = () => {
  isTouch = true;
};

class Volume extends React.Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  render() {
    return (
      <div className="jp-volume-container" onClick={handleContainerClick}>
        <Mute onTouchStart={volumeControlOnClick} onClick={handleMuteClick}><i className="fa fa-volume-up" /></Mute>
        <div className="jp-volume-controls">
          <div className="jp-volume-bar-container">
            <VolumeBar />
          </div>
        </div>
      </div>
    );
  }
};

class Mute extends React.Component {
  render() {
    return (
      <button className="jp-mute" onTouchStart={this.props.onTouchStart} onClick={this.props.onClick}>
        {this.props.children}
      </button>
    );
  }
};

class VolumeBar extends React.Component {
  render() {
    return (
      <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>
        {this.props.children}
      </div>
    );
  }
};

render(<Volume />, document.getElementById('container'));

如果你没有使用气泡阶段,那么你可以用上面相同的逻辑注册100ms的超时,在100ms之后你再次使你的flag变量为false。只需添加到touchStart处理程序:

setTimeout(() => {isTouch = false}, 100);

编辑尽管默认情况下Chrome 56中的触摸事件应该是被动的,但您可以从touchEnd事件中调用preventDefault()以防止点击处理程序触发。因此,如果您无法以任何方式修改Mute类的单击处理程序,但您可以添加touchEnd事件,而不是:

const handleTouchEnd = (e) => e.preventDefault();

const volumeControlOnClick = () => console.log("volumeControlOnClick");

class Volume extends React.Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  render() {
    return (
      <div className="jp-volume-container">
        <Mute onTouchStart={volumeControlOnClick} onTouchEnd={handleTouchEnd}><i className="fa fa-volume-up" /></Mute>
        <div className="jp-volume-controls">
          <div className="jp-volume-bar-container">
            <VolumeBar />
          </div>
        </div>
      </div>
    );
  }
};

class Mute extends React.Component {
  render() {
    return (
      <button className="jp-mute" onTouchStart={this.props.onTouchStart} onTouchEnd={this.props.onTouchEnd} onClick={() => console.log("mute toggled")}>
        {this.props.children}
      </button>
    );
  }
};

class VolumeBar extends React.Component {
  render() {
    return (
      <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>
        {this.props.children}
      </div>
    );
  }
};

render(<Volume />, document.getElementById('container'));

答案 1 :(得分:-1)

试试这个

 render() {
        return (
      <div className="jp-volume-container" onClick={handleContainerClick}>
        <Mute onTouchStart={volumeControlOnClick} onClick={handleMuteClick}><i className="fa fa-volume-up" /></Mute>
        <div className="jp-volume-controls">
          <div className="jp-volume-bar-container">
            <VolumeBar />
          </div>
        </div>
      </div>
    );
  }
};

class Mute extends React.Component {
  render() {
    return (
      <button className="jp-mute" onTouchStart={this.props.onTouchStart} onClick={this.props.onClick}>
        {this.props.children}
      </button>
    );
  }
};

class VolumeBar extends React.Component {
  render() {
    return (
      <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>
        {this.props.children}
      </div>
    );
  }
};

render(<Volume />, document.getElementById('container'));