React Swipeable-如何包装?

时间:2018-10-24 13:12:52

标签: javascript html reactjs swipe swipe-gesture

我在react中构建了自己的表组件。 我想添加更多配置,例如可滑动行

问题在于,React Swipeable的所有NPM插件都是包装,这些包装将 WRAP 我的组件。

tr标记不能用div或td包裹任何其他html标记。

在底行,我如何使Row组件(tr为可滑动)?

这是我的代码:

let RowComp = <Row key={index} cols={this.props.cols} row={row} onRowClick={this.onRowClick}/>;

if(this.props.onRowSwipe){
  return (
    <Swipe key={index} onSwipeRight={() => this.props.onRowSwipe(row)}>
      {RowComp}
    </Swipe>
  );
}
return RowComp;

当然,我得到了反应,警告不能包装tr。 我能做什么? 我如何使我可以滑动?

非常感谢:)

2 个答案:

答案 0 :(得分:0)

我在应用程序中尝试过类似的操作。没有任何本机滑动事件,但是有三个事件可让您解决问题:onTouchStartonTouchMoveonTouchEnd。在下面,您可以看到我的可滑动菜单的实验实现: 如您所见,我在App.js组件中创建了三个函数:handleTouchStarthandleTouchMovehandleTouchEnd

  • handleTouchStart函数将事件作为道具接收,并保存初始的X和Y位置
  • handleTouchMove函数再次将事件作为道具接收,并找到当前位置和初始位置之间的差异。
  • 最后,handleTouchEnd函数检查X和Y的差异并显示或隐藏菜单。

很遗憾,您无法从onTouchEnd事件访问最后一个位置,这就是为什么必须使用onTouchMove事件的原因。

您还必须检查是否发生了很小的垂直移动。这就是为什么我还要检查Y位置之间的差异,但您需要绝对值的原因

如果X差为负,则表示您向左移动。如果X差为正,则表示您向右移动。

您还必须在不同的设备上进行大量测试,以定义初始X位置和最终X位置之间的理想差异

最后,我将函数作为道具传递给组件并将它们绑定到三个事件。

App.js(父组件)

import React, { Component } from "react";
import styled from "styled-components";
import Header from "components/Header";
import Navbar from "components/Navbar";
import SideMenu from "components/SideMenu";
import MainContent from "components/Content";

const AppWrapper = styled.section`
  height: 100vh;
  width: 100vw;
  display: grid;
  grid-template-rows: 70px auto;
  @media (max-width: 884px) {
    grid-template-columns: 60vw auto;
  }
  @media (min-width: 885px) {
    grid-template-columns: 200px auto;
  }
`;

class App extends Component {
  swipe = {
    firstPositionX: null,
    firstPositionY: null,
    positionDifferenceX: null,
    positionDifferenceY: null
  };
  constructor(props) {
    super(props);
    this.state = {
      sideMenuDisplay: window.innerWidth >= 885 ? true : false
      // movement: -60
    };
  }



  componentDidMount() {
    window.addEventListener("resize", this.updateSideMenuDisplay);
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateSideMenuDisplay);
  }

  updateSideMenuDisplay = () => {
    this.setState({ sideMenuDisplay: window.innerWidth >= 885 ? true : false });
  };

  toggleSideMenu = () => {
    this.setState(prevState => ({
      sideMenuDisplay: !prevState.sideMenuDisplay
    }));
  };



  handleTouchStart = e => {
    this.swipe.firstPositionX = e.touches[0].screenX;
    this.swipe.firstPositionY = e.touches[0].screenY;
  };

  handleTouchMove = e => {
    this.swipe.positionDifferenceX =
      e.touches[0].screenX - this.swipe.firstPositionX;
    this.swipe.positionDifferenceY =
      e.touches[0].screenY - this.swipe.firstPositionY;
  };

  handleTouchEnd = () => {
    if (Math.abs(this.swipe.positionDifferenceY) <= 150) {
      this.setState(
        prevState => ({
          sideMenuDisplay:
            prevState.sideMenuDisplay === false
              ? this.swipe.positionDifferenceX > 50
              : !(this.swipe.positionDifferenceX < -50)
        }),
        () => {
          this.swipe.firstPositionX = null;
          this.swipe.positionDifferenceX = null;
          this.swipe.firstPositionY = null;
          this.swipe.positionDifferenceY = null;
        }
      );
    }
  };

  render() {
    const sideMenuDisplay = this.state.sideMenuDisplay;
    return (
      <AppWrapper>
        <Header display={sideMenuDisplay} />
        <Navbar onClick={this.toggleSideMenu} display={sideMenuDisplay} />
        <SideMenu

  }
}

export default App;  display={sideMenuDisplay}
          onTouchStart={this.handleTouchStart}
          onTouchMove={this.handleTouchMove}
          onTouchEnd={this.handleTouchEnd}
        />
        <MainContent
          display={sideMenuDisplay}
          onTouchStart={this.handleTouchStart}
          onTouchMove={this.handleTouchMove}
          onTouchEnd={this.handleTouchEnd}
        />
      </AppWrapper>
    );
  }
}

export default App;

SideMenu.js(子组件)

import React, { Component } from "react";
import SideMenuElement from "./SideMenuElement";
import MembersIcon from "./MembersIcon";
import DashboardIcon from "./DashboardIcon";
import {
  SideMenuSection,
  SideMenuItems,
  SideMenuElementLogo,
  AppMobileLogo
} from "./styles";
import logoIcon from "static/logo@3x.png";

class SideMenu extends Component {
  constructor(props) {
    super(props);
    this.state = { selectedItem: "dashboard" };
  }

  selectItem = item => {
    this.setState({ selectedItem: item });
  };

  render() {
    const selectedItem = this.state.selectedItem;

    return (
      <SideMenuSection
        display={`${this.props.display}`}
        onTouchStart={this.props.onTouchStart}
        onTouchMove={this.props.onTouchMove}
        onTouchEnd={this.props.onTouchEnd}
      >
        <SideMenuItems>
          <SideMenuElementLogo>
            <AppMobileLogo src={logoIcon} alt="App Logo" />
          </SideMenuElementLogo>

          <SideMenuElement
            item="dashboard"
            icon={DashboardIcon}
            selected={selectedItem === "dashboard"}
            onClick={this.selectItem}
          >
            Dashboard
          </SideMenuElement>

          <SideMenuElement
            item="members"
            icon={MembersIcon}
            selected={selectedItem === "members"}
            onClick={this.selectItem}
          >
            Members
          </SideMenuElement>
        </SideMenuItems>
      </SideMenuSection>
    );
  }
}

export default SideMenu;

答案 1 :(得分:0)

感谢您的答复。 我终于想通了。 我自以为是可以合法包装tr的东西吗?

答案是:身体

我用react-swipe-component组件将tr包裹在一个tbody节点上,并且一切都像魔术一样,没有任何警告。

import Swipe from 'react-swipe-component';

<Swipe key={index} nodeName="tbody" onSwipeRight={() => this.props.onRowSwipe(row)}>
  {RowComp}
</Swipe>

仍然非常感谢您的评论:)