React

React

简介

用于构建用户界面的JavaScript库,声明式、组件化、一次学习,随处编写,高效,单向数据流,使用虚拟dom及Dom Diff算法最小化页面重绘。

依赖

react.js: React的核心库

react-dom.js: 提供操作DOM的react扩展库

babel.min.js: 解析JSX语法代码为纯JS语法代码的库

hello

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <div id ="main"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">//jsx ---> js
    //1.创建虚拟dom
    var vdom = <h1>Hello React!</h1>
    //2.渲染虚拟dom到页面
    ReactDOM.render(vdom,document.getElementById('main'))
</script>
</body>
</html>

JSX

javascript xml, react定义了一种类似于xml的js扩展语法,xml+js,用来创建react虚拟dom对象,语法规则,当遇见尖括号时,解析为标签,当遇见大括号时,解析为js,浏览器不能直接解析jsx代码,需要babel转换为js代码才可以运行,使用jsx需要给脚本标签加上type="text/babel",声明需要babel进行处理。

语法

ReactDOM.rander(virtualDOM,containerDOM)

将虚拟的DOM渲染成真实DOM

示例

<html lang="zh">
<head>
    <meta charset="UTF-8">

    <title>Document</title>
</head>
<body>
    <div id = "dom1"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <script type="text/babel">
    
    const names = ['jQuery','Zepto','Angular','React','Vue']

    const ul =(
        <ul>
        {names.map((name,index) => <li key={index}>{name}</li>)}
        </ul>)

    ReactDOM.render(ul,document.getElementById('dom1'))
    </script>
</body>
</html>

模块化

向外提供特定功能的js程序,一般为一个js文件,用于复用js,简化js的编写,提高js运行的效率。

组件化

用来实现特定功能效果的代码集合,即一个页面的版块,包含组件的html、css、js、所有资源。

面向组件编程

组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <div id ="main"></div>
    <div id ="main2"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
    //1.定义组件
    var vdom = <h1>Hello React!</h1>
    function Component() {
        return <h2>这个标签来自一个组件</h2>
    }
    //无状态组件使用函数方式创建、效率更高


		//类的方式具备状态
    class Component2 extends React.Component{
        
        render(){
            return <h2>这个标签来自一个组件类</h2>
        }
    }
    //2.渲染组件标签
    ReactDOM.render(<Component />,document.getElementById('main'))
    ReactDOM.render(<Component2 />,document.getElementById('main2'))
</script>
</body>
</html>

组件属性

state

State属性是组件的状态属性,页面中组件的重新渲染由此属性控制,其值是一个对象,可以包含多个数据。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <div id ="main"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
    //1.定义组件


    class News extends React.Component{
        
        constructor(props){
            super(props)
            
            this.state = {
                isState:false
            }//初始化状态

            //绑定新方法this
            this.handleClick = this.handleClick.bind(this)
            //必须赋值 否则 函数中的state是空值
        }//调用父类构造

        //新增方法 this 为空
        handleClick(){
            console.log(this)
            const isState = !this.state.isState
            
            this.setState({isState})
        }

        //重写方法
        render(){

            const {isState} = this.state
            return <h2 onClick={this.handleClick}>{isState?'发布新闻':'没有新闻'}</h2>
        }
    }
    //2.渲染组件标签
    ReactDOM.render(<News />,document.getElementById('main'))
</script>
</body>
</html>
  1. 构造器初始化状态、绑定状态
  2. render方法读取状态
  3. 事件函数中修改状态

props

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <div id ="man"></div>
    <div id ="woman"></div>


    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
    //1.创建虚拟dom
    function Persion(props) {
        return(
            <ul>
            <li>姓名:{props.name}</li>
            <li>年龄:{props.age}</li>
            <li>性别:{props.sex}</li>
            </ul>
        )
    }
    Persion.defaultProps = {
        sex: 'man',
        age: 18
    }//默认值
    
    Persion.propTypes={
        name: PropTypes.string.isRequired,
        age: PropTypes.number
    }//数据校验及数据是否为空

    const p1 = {
        name: 'Wang',
        age: 18,
        sex: 'girl'
    }
    const p2 = {
        name: 'Lee',
        age: 'cdef',
        sex: 'girl'
    }

        class Persion2 extends React.Component{

            render(){
                return(<ul>
                    <li>姓名:{this.props.name}</li>
                    <li>年龄:{this.props.age}</li>
                    <li>性别:{this.props.sex}</li>
                    </ul>)
            }
        }
    //2.渲染虚拟dom到页面

    //ReactDOM.render(<Persion name={p1.name} age={p1.age} sex={p1.sex} />,document.getElementById('man'))
    ReactDOM.render(<Persion2 {...p1} />,document.getElementById('man')) //三点运算符
    ReactDOM.render(<Persion name={p2.name} age={p2.age}/>,document.getElementById('woman'))


</script>
</body>
</html>

打包运算 ...p1即可将p1中的值全部对应赋值给Persion组件/function fn(...list)调用fn(1,2,3) 此时为打包

refs和事件处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
    <div id ="main"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
    //1.创建虚拟dom
   class Com extends React.Component{

       constructor(props){
           super(props)

           this.showInput = this.showInput.bind(this)
           this.handleBlur = this.handleBlur.bind(this)
           //将组件绑定到函数
       }

       handleBlur(event){
           alert(event.target.value)
       }
       showInput(){
        const input = this.input
           alert(input.value)
       }
       
    render(){
        return(
            <div>
                <input type="text" ref="content"/>&nbsp;&nbsp;
                <input type="text" ref={(input) => this.input = input}/>&nbsp;&nbsp;
                //dom绑定到组件
                <button onClick={this.showInput}>提示输入</button>
                <input placeholder="失去焦点提示内容" onBlur={this.handleBlur}/>
                //事件绑定
            </div>
        )
    }
   }
    //2.渲染虚拟dom到页面
    ReactDOM.render(<Com/>,document.getElementById('main'))
</script>
</body>
</html>

组件界面开发流程

  1. 拆分组件:拆分界面,抽取组件
  2. 实现静态组件:使用组件实现静态页面效果
  3. 实现动态组件
    • 动态显示初始化数据
    • 实现交互功能
//第一阶段
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>

<div id ="main"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">

    class App extends React.Component{

        render(){
            return(
                <div>
                    <h1>This is To Do List</h1>
                    <Add />
                    <List />
                </div>
            )
        }
    }
    
    class Add extends React.Component{

        render(){
            return(
                <div>
                    <input type="text"/>
                    < button> Add #4</button>
                </div>
            )
        }
    }

    class List extends React.Component{

        render(){
            return(
                <ul>
                    <li>aaa</li>
                    <li>aaa</li>
                    <li>aaa</li>
                    <li>aaa</li>
                    <li>aaa</li>
                </ul>
            )
        }
    }
    ReactDOM.render(<App/>,document.getElementById('main'))
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>

<div id="main"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">

    class App extends React.Component {

        /**
         * 数据需要放在哪个组件,独占数据放到组件,共享数据放到父组件
         * @returns {*}
         */
        constructor(props) {
            super(props)

            this.state = {
                todos: ['eat', 'sleep', 'coding']
            }
            this.addTodo = this.addTodo.bind(this)
        }

        addTodo(todo) {

            const {todos} = this.state
            todos.unshift(todo)
            this.setState({todos})
        }

        render() {
            const {todos} = this.state
            return (
                <div>
                    <h1>This is To Do List</h1>
                    <Add count={todos.length} addTodo={this.addTodo}/>
                    <List todos={todos}/>
                </div>
            )
        }
    }

    class Add extends React.Component {

        constructor(props) {
            super(props)

            this.add = this.add.bind(this)

        }

        add() {
            const todo = this.todoInput.value.trim()
            if (!todo) {
                alert("不能为空!")
                return
            }
            this.props.addTodo(todo)
            this.todoInput.value
            //读取数据
            //校验数据
            //添加
        }

        render() {
            return (
                <div>
                    <input type="text" ref={input => this.todoInput = input}/>
                    < button onClick={this.add}> Add #{this.props.count + 1}</button>
                </div>
            )
        }
    }

    Add.propTypes = {
        count: PropTypes.number.isRequired,
        addTodo: PropTypes.func.isRequired
    }

    class List extends React.Component {

        render() {
            return (
                <ul>
                    {this.props.todos.map((todo, index) => <li key={index}>{todo}</li>)}
                </ul>
            )
        }
    }

    List.propTypes = {
        todos: PropTypes.array.isRequired,
    }
    ReactDOM.render(<App/>, document.getElementById('main'))
</script>
</body>
</html>
//示例 阻止默认行为  组件取值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
<div id="main"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
    //1.创建虚拟dom
    class LoginForm extends React.Component {
        constructor(props) {
            super(props)

            this.handleSubmint = this.handleSubmit.bind(this)
            this.handleChange = this.handleChange.bind(this)

        }

        handleChange(event) {
            const pwd = event.target.value
            this.setState({pwd})
        }

        handleSubmit(event) {

            const name = this.nameInput.value
            const {pwd} = this.state
            event.preventDefault()
            alert(`用户名:${name}   密码:${pwd}`)


        }

        render() {
            return (
                <form action="/test" onSubmit={this.handleSubmint}>
                    用户名:<input type="text" ref={input => this.nameInput = input}/>
                    密码:<input type="password" onChange={this.handleChange}/>
                    <input type="submit" value="登录"/>
                </form>
            )
        }
    }

    ReactDOM.render(<LoginForm/>, document.getElementById('main'))
</script>
</body>
</html>

组件生命周期

组件生命周期

  1. 组件的三个生命周期状态:
  • Mount:插入真实 DOM
  • Update:被重新渲染
  • Unmount:被移出真实 DOM
  1. 生命周期流程:
  • 第一次初始化显示: ReactDOM.render(, containDom)
    • constructor()
    • componentWillMount() : 将要插入回调
    • render() : 用于插入虚拟DOM回调
    • componentDidMount() : 已经插入回调
  • 每次更新state: this.setState({})
    • componentWillReceiveProps(): 接收父组件新的属性
    • componentWillUpdate() : 将要更新回调
    • render() : 更新(重新渲染)
    • componentDidUpdate() : 已经更新回调
  • 删除组件: ReactDOM.unmountComponentAtNode(div): 移除组件
    • componentWillUnmount() : 组件将要被移除回调
  1. 常用的方法
  • render(): 必须重写, 返回一个自定义的虚拟DOM
  • constructor(): 初始化状态, 绑定this(可以箭头函数代替)
  • componentDidMount() : 只执行一次, 已经在dom树中, 适合启动/设置一些监听
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>

<div id="main"></div>

<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">

    class Life extends React.Component {

        constructor(props) {
            super(props)

            this.state = {
                opacity: 1
            }
            this.distroyComponent = this.distroyComponent.bind(this)
        }

        distroyComponent() {
            ReactDOM.unmountComponentAtNode(document.getElementById('main'))
        }

        componentWillUnmount() {
            clearInterval(this.intervalId)
        }

        componentDidMount() {
            this.intervalId = setInterval(function () {
                let {opacity} = this.state
                console.log("running")
                opacity -= 0.1
                if (opacity <= 0) {
                    opacity = 1
                }
                this.setState({opacity})
            }.bind(this), 200)
        }

        //render为渲染
        render() {

            const {opacity} = this.state
            return (
                <div>
                    <h2 style={{opacity}}>{this.props.msg}</h2>
                    <button onClick={this.distroyComponent}>结束</button>
                </div>
            )
        }
    }

    ReactDOM.render(<Life msg="This is Msg"/>, document.getElementById('main'))

</script>
</body>
</html>

虚拟DOM与DOM Diff算法

虚拟DOM

一个虚拟DOM(元素)是一个一般的js对象, 准确的说是一个对象树(倒立的)
虚拟DOM保存了真实DOM的层次关系和一些基本属性,与真实DOM一一对应
如果只是更新虚拟DOM, 页面是不会重绘的

Virtual DOM 算法的基本步骤

用JS对象树表示DOM树的结构;然后用这个树构建一个真正的DOM树插到文档当中
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异
把差异应用到真实DOM树上,视图就更新了

进一步理解

Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。
可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)。

脚手架

posted @ 2018-09-13 00:21  图图突tu  阅读(246)  评论(0编辑  收藏  举报