Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react实现表单事件 #31

Open
lulujianglab opened this issue Nov 1, 2018 · 0 comments
Open

react实现表单事件 #31

lulujianglab opened this issue Nov 1, 2018 · 0 comments

Comments

@lulujianglab
Copy link
Owner

相信使用过React.js的小伙伴都应该知道其数据双向绑定的灵活性,在处理表单,人机交互方面都具能发挥极大的优势,而且实现起来也比较方便

最近在项目中刚好用到了这系列操作,下面以类似于单选框、复选框和下拉框为例介绍他们在ant-design-pros中的具体实现方式

单选事件

在项目中我们经常会遇到类似单选事件的小功能,比如点击或悬浮的元素高亮,页面上有很多的item元素,要实现点击或者悬浮到哪个就哪个高亮

用jq实现的话,就是选中的元素给加个addClass的事件,添加active的样式,然后它的兄弟元素removeClass,去掉active样式

同样的,用react实现,我们可以用相同的思路,比如用一个currentIndex,通过它来判断是在哪个元素实现切换的,而currentIndex的值又可以通过选中元素的某个元素属性来动态改变

效果图

image

代码

class Radio extends PureComponent {
  state= {
    currentIndex: null,
    value: null
  }

  setCurrentIndex = (e) => {
    this.setState({
      currentIndex: parseInt(e.currentTarget.getAttribute('index'), 10)
    })
  }

  handleChange = (e) => {
    this.setState({
      value: e.target.value
    })
  }

  render () {
    const arr = ['京东超市', '天猫超市', '京东生鲜', '京东到家', '果蔬好', '盒马生鲜', '无人超市', '每日生鲜']
    const itemList = arr.map((item, index) => {
      return (
        <li 
          key={index} 
          className={`${styles.item} ${this.state.currentIndex === index ? styles.active : ''}`} 
          index={index} 
          onClick={this.setCurrentIndex}
        >
          {item}
        </li>
      )
    })
    return (
      <Card title="单选列表" bordered={false} className={styles.main}>
        <div className={styles.content}>
          <div className={styles.top}>
            <div className={styles.name}>点击或悬浮选中的li高亮:</div>
            <ul className={styles.list}>{itemList}</ul>
          </div>
          <div className={styles.bottom}>
            <div className={styles.name}>您的性别为:</div>
            <div className={styles.list}>
              <label className={styles.item}><input type="radio" name='gender' value="男生" onChange={this.handleChange}/>男生</label>
              <label className={styles.item}><input type="radio" name='gender' value="女生" onChange={this.handleChange}/>女生</label>
            </div>
            <div className={styles.sex}>性别: {this.state.value}</div>
          </div>
        </div>     
      </Card>
    )
  }
}

总的来说,就是生成这些li的时候给元素添加一个index标志位,然后通过相应的点击事件,把这个index用e.currentTarget.getAttribute('index')取出来,然后去设置currentTarget的值,再通过赋给选中的css的active样式就可以了

复选事件

在页面中,有时候会根据用户的一些操作更新属性值,但不同的对象间的操作就涉及到对多个值的状态管理,这些可变的状态通常都保存在组件的状态属性中,并且只能用setState()方法更新

复选事件和单选事件类似,也需要通过监听各个标签元素的点击或者悬浮等事件来实现

效果图

image

代码

class Checkbox extends PureComponent {
  state = {
    fruit: [],
    value: []
  }

  handleChange  = (e) => {
      let item = e.target.value
      let items = this.state.fruit.slice()
      let index = items.indexOf(item)
      index === -1 ? items.push(item) : items.splice(index, 1)
      this.setState({fruit: items})
  }

  onclickIcon = (e) => {
    let item = parseInt(e.currentTarget.getAttribute('index'), 10)
    let items = this.state.value.slice()

    let index = items.indexOf(item)
    index === -1 ? items.push(item) : items.splice(index,1)
    this.setState({
      value: items
    })
  }

  render() {
    const listArr = ['羽绒服', '裙子', '帽子', '围巾']
    return (
      <Card title="多选列表" bordered={false} className={styles.main}>
        <div className={styles.content}>
          <div className={styles.left}>
            <div className={styles.title}>Choose fruit : </div>
            <div className={styles.list}>
              <label className={styles.item}><input type="checkbox" name="fruit" value="apple"
                            onChange={this.handleChange}/>apple</label>
              <label className={styles.item}><input type="checkbox" name="fruit" value="banana"
                            onChange={this.handleChange}/>banana</label>
              <label className={styles.item}><input type="checkbox" name="fruit" value="pear"
                            onChange={this.handleChange}/>pear</label>
            </div>
            <div>Choosen : {this.state.fruit.join('-')}</div>
          </div> 
          <div className={styles.right}>    
            <div className={styles.tag}>点亮我的喜欢:</div>
            <ul className={styles.card}>
            {
              listArr.map((item,index) => {
                return (
                  <li 
                    key={index} 
                    className={styles.item} 
                    index={index} 
                    onClick={this.onclickIcon}
                  >
                    <svg 
                      className={`${styles.svg} ${this.state.value.indexOf(index) === -1? styles.icon : styles.iconColor}`} aria-hidden="true">
                      <use xlinkHref={this.state.value.indexOf(index) === -1? "#icon-lovetaoxin" : "#icon-shixintaoxin"}></use>
                    </svg>
                    <span to='#' target="_blank" className={styles.text}>{item}</span>
                  </li>
                )
              })
            }
            </ul> 
          </div> 
        </div>           
      </Card>
    )
  }
}

总的来说,我们通过在组件状态state中定义数组,存放选中的信息,主要是通过先在li元素中添加index标志位,然后通过相应事件的触发,把这个index用e.currentTarget.getAttribute('index')取出来,存放到state中定义的数组中

需要注意的是,在更新value时,必须使用setState函数,否则代码不会被重新渲染,在return中显示已选中的选项不会实时更新

下拉事件

下拉的实现方式和单选、复选有些类似,而且在ant-design中也有下拉Dropdown的组件,可以复用加以修改,可以直接看例子说明

效果图

image

代码

class NewDropdown extends PureComponent {
  state = {
    value: 'basketball'
  }

  handleChange = (e) => {
    this.setState({
      value: e.target.value
    })
  }

  handleMenuClick = ({ key }) => {
    if (key === 'radio') {
      router.push('/selector/radio');
      return;
    }
    if (key === 'checkbox') {
      router.push('/selector/checkbox');
      return;
    }
    if (key === 'dropdown') {
      return;
    }
  };

  render () {
    const menu = (
      <Menu className={styles.menu} selectedKeys={[]} onClick={this.handleMenuClick}>
        <Menu.Item key="radio">
          <Icon type="user" />
          <FormattedMessage id="menu.selector.radio" defaultMessage="radio" />
        </Menu.Item>
        <Menu.Item key="checkbox">
          <Icon type="setting" />
          <FormattedMessage id="menu.selector.checkbox" defaultMessage="checkbox" />
        </Menu.Item>
        <Menu.Item key="dropdown">
          <Icon type="close-circle" />
          <FormattedMessage id="menu.selector.dropdown" defaultMessage="dropdown" />
        </Menu.Item>
      </Menu>
    );
    return (
      <Card title="下拉列表" bordered={false} className={styles.main}>
        <div className={styles.content}>
          <div className={styles.left}>
            <label className={styles.select}>choose favorite sports:
              <select value={this.state.value} onChange={this.handleChange}>
                  <option value="running">running</option>
                  <option value="basketball">basketball</option>
                  <option value="skiing">skiing</option>
              </select>
            </label>
            <div className={styles.chosen}>chosen: {this.state.value}</div>
          </div>
          <div className={styles.right}>
            <Dropdown overlay={menu}>
              <span className={styles.action}>
                <span className={styles.name}>查看示例</span>
              </span>
            </Dropdown>
          </div>
        </div>
      </Card>
    )
  }
}

总的来说,是通过在组件状态中设置一个value值,并在return中的select标签中使用,上述实现的是一个默认选中的功能

在用react实现表单时,其原理都是相同的,利用一个组件状态state来存储选中信息,然后监听各个标签元素的点击、悬浮、切换等事件,并在响应函数中更新组件状态

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant