2 React

2019-12-07  本文已影响0人  ChenME

1. 安装脚手架工具;

npm install -g create-react-app

2. 通过 react 脚手架工具床架一个项目;

create-react-app hello_world

3. 启动项目;

cd hello_world
npm start

4. 父组件 App.js

import React, { Component, Fragment } from 'react';
import { CSSTransition } from 'react-transition-group';

import TodoItem from './TodoItem';
import './style.css';

class App extends Component {
  constructor(props) {
    super(props);

    this.onItemDel = this.onItemDel.bind(this);
    this.onSubmitEvent = this.onSubmitEvent.bind(this);
    this.onInputChangedEvent = this.onInputChangedEvent.bind(this);
    this.toggleAnim = this.toggleAnim.bind(this);

    this.state = {
      inputValue: "",
      list: [],
      isShow: true,
    }
  }

  render() {
    return (
      <Fragment>
        <div>
          {/* htmlFor:在 JSX 中为 input 框添加 focus */}
          <label htmlFor="insertWords">请输入内容</label>
          <input id="insertWords" className="input" value={this.state.inputValue} onChange={this.onInputChangedEvent} />
          <button onClick={this.onSubmitEvent}>提交</button>
        </div>
        <ul> {this.getItem()} </ul>

        <div>
          <label className={this.state.isShow ? "item-show" : "item-hide"}>动画效果</label>
          <button onClick={this.toggleAnim}>切换动画</button>
        </div>


        <div>
          <CSSTransition
            classNames='fade'
            in={this.state.isShow}
            timeout={2000}
            appear={true}
            unmountOnExit>
            <label >动画效果2</label>
          </CSSTransition>
          <button onClick={this.toggleAnim}>切换动画2</button>
        </div>
      </Fragment>
    );
  }

  componentDidMount() {
    // axios.get("/123/123").then(() => { alert("succ") }).catch(() => { alert("err") });
  }

  toggleAnim() {
    this.setState(() => ({ isShow: !this.state.isShow }))
  }

  /**
   * 输入发生改变
   * @param {obj} e 
   */
  onInputChangedEvent(e) {
    const value = e.target.value;
    this.setState(() => ({ inputValue: value }));
  }

  /**
   * 提交按钮
   */
  onSubmitEvent() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],
      inputValue: "",
    }));
  }

  /**
   * 获取列表项的内容
   */
  getItem() {
    return this.state.list.map((item, index) => {
      // delItem  将点击方法传递给子组件
      return <TodoItem key={item} content={item} index={index} delItem={this.onItemDel} />
    })
  }
  /**
   * 删除列表项
   * @param {int} index 
   */
  onItemDel(index) {
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
      return { list }
    })
  }
}

export default App;

5. 子组件 TodoItem.js

import React, { Component } from "react";
import PropTypes from 'prop-types';

class TodoItem extends Component {

    constructor(props) {
        super(props);
        this.onItemDel = this.onItemDel.bind(this);
    }

    render() {
        console.log('render')
        const { test, content } = this.props;
        return <li onClick={this.onItemDel}>{test} - {content}</li>

        // dangerouslySetInnerHTML:不将 HTML 标签转义成字符串输出出来
        // return <li  onClick={this.onItemDel} dangerouslySetInnerHTML={{ __html: content }}></li>
    }

    onItemDel() {
        // 调用父组件的方法
        const { delItem, index } = this.props;
        delItem(index);
    }

    shouldComponentUpdate(nextProps, nextState) {
        return nextProps.content !== this.props.content;
    }
}

// 类型校验
TodoItem.propTypes = {
    test: PropTypes.string.isRequired, // isRequired 表示是必传参数
    content: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // content 既可以是 String,也可以是 number
    index: PropTypes.number,
    onItemDel: PropTypes.func,
}

// 默认值
TodoItem.defaultProps = {
    test: 'This is default value!'
}

export default TodoItem;

6. style.css

.fade-enter,
.fade-appear {
    opacity: 0;
}

.fade-enter-active,
.fade-appear-active {
    opacity: 1;
    transition: opacity 2s ease-in;
}

.fade-enter-done,
.fade-appear-done {
    opacity: 1;
}

.fade-exit {
    opacity: 1;
}

.fade-exit-active {
    opacity: 0;
    transition: opacity 2s ease-in;
}

.fade-exit-done {
    opacity: 1;
}



.item-show {
    animation: item-show 2s ease-in forwards;
}

.item-hide {
    animation: item-hide 2s ease-in forwards;
}

@keyframes item-show {
    0% {
        opacity: 0;
        color: #ff639b;
    }

    50% {
        opacity: 0.5;
        color: #3fd677;
    }

    100% {
        opacity: 1;
        color: #3564ff;
    }
}

@keyframes item-hide {
    0% {
        opacity: 1;
        color: #3564ff;
    }

    50% {
        opacity: 0.5;
        color: #3fd677;
    }

    100% {
        opacity: 0;
        color: #ff639b;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读