Hello,React

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. </head>
  7. <body>
  8. <!-- 准备好一个容器 -->
  9. <div id="test"></div>
  10. <!-- React 核心库(必须先于 react-dom.development.js 引入) -->
  11. <script type="text/javascript" src="../js/react.development.js"></script>
  12. <!-- 提供操作 DOM 的 react 扩展库 -->
  13. <script type="text/javascript" src="../js/react-dom.development.js"></script>
  14. <!-- 解析 JSX 语法代码转为 JS 代码的库 -->
  15. <script type="text/javascript" src="../js/babel.min.js"></script>
  16. <script type="text/babel">
  17. // 创建虚拟 DOM
  18. const VDOM = <h1>Hello,React</h1>
  19. // 渲染虚拟 DOM 到页面
  20. ReactDOM.render(VDOM, document.getElementById('test'))
  21. </script>
  22. </body>
  23. </html>

图片.png

虚拟 DOM 的两种创建方式

虚拟 DOM 本质上是 Object 类型的对象。
虚拟 DOM 比较轻,真实 DOM 比较重,因为 虚拟 DOM 是在 React 内部使用,无需真实 DOM 上那么多属性。
虚拟 DOM 对象最终都会被 React 转换为真实的 DOM
JSX 方式

<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>

    <!-- React 核心库(必须先于 react-dom.development.js 引入) -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 提供操作 DOM 的 react 扩展库 -->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 解析 JSX 语法代码转为 JS 代码的库 -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <script type="text/babel">
        // 创建虚拟 DOM
        const VDOM = (
            <h1 id="title">
                <span>Hello,React</span>
            </h1>
        )
        // 渲染虚拟 DOM 到页面
        ReactDOM.render(VDOM, document.getElementById('test'))
    </script>
</body>

图片.png


纯 JS 方式

<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>

    <!-- React 核心库(必须先于 react-dom.development.js 引入) -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 提供操作 DOM 的 react 扩展库 -->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 不需要 babel 库了 -->

    <!-- 改回 text/javascript -->
    <script type="text/javascript">
        // 创建虚拟 DOM
        // React.createElement(标签名, 标签属性, 标签内容)
        const VDOM = React.createElement('h1', { id: 'title', class: 'myClass' }, 'Hello,React')
        // 渲染虚拟 DOM 到页面
        ReactDOM.render(VDOM, document.getElementById('test'))
    </script>
</body>

图片.png

jsx 语法规则

  • 定义虚拟 DOM 时,不能写引号
  • 标签中混入 JS 表达式时要用 {}
  • 样式的类名指定用的是 className,而不是 class
  • 内联样式,要用 style={{key:value, key:value}} 的形式写
  • 虚拟 DOM 只能一个根标签
  • 标签必须闭合
  • 标签首字母的不同情况
    • 若标签首字母小写,则将该标签转为 HTML 中的同名元素,若 HTML 中无同名元素,则报错。
    • 若标签首字母大写,则渲染对应的组件,若组件没有定义,则报错。 ```html <!DOCTYPE html>

<a name="CycyE"></a>
# 面向组件编程
以下内容都是面向组件编程。
<a name="sgccr"></a>
# 模块化 & 组件化的理解
模块的理解:向外提供特定功能的 JS 程序,一般就是一个 JS 文件<br />拆成模块的原因:随着业务逻辑增加,代码越来越多且越来越复杂<br />模块的作用:复用 JS,简化 JS 的编写,提高 JS 的运行效率<br />模块化:当应用的 JS 都是以模块来编写的,这个应用就是一个模块化的应用

---

组件的理解:用来实现局部功能效果的代码和资源的集合 (HTML / CSS / JS / image 等)<br />用组件的原因:一个界面的功能太复杂<br />组件的作用:复用编码,简化项目编码,提高运行效率<br />组件化:当应用是以多组件的方式实现的,这个应用就是一个组件化的应用
<a name="sIWT7"></a>
# 组件
<a name="Wee9l"></a>
## 函数式组件
```html
<body>
    <!-- 准备好一个“容器” -->
    <div id="test"></div>

    <!-- 引入react核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入react-dom,用于支持react操作DOM -->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <script type="text/babel">
        // 创建函数式组件(首字母必须大写,不然会被 jsx 解析成标签)
        function MyComponent() {
            // 此处的 this 是 undefined
            // 因为 babel 编译后开启了严格模式 (strict)
            console.log(this);
            return <h1>函数定义的组件适用于简单组件</h1>
        }

        // 渲染组件到页面
        ReactDOM.render(<MyComponent />, document.getElementById('test'))
    </script>

</body>

图片.png
执行了 ReactDOM.render( 之后,发生了什么

  1. React 解析组件标签,找到了 MyComponent 组件。
  2. 发现该组件是使用函数定义的,随后调用该函数,将返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中。

    类式组件

    ```html

执行了 ReactDOM.render(<MyComponent/> 之后,发生了什么

1. React 解析组件标签,找到了 MyComponent 组件。
1. 发现该组件是使用类定义的,随后 new 该类的实例,并通过该实例调用到原型上的 render 方法。
1.  将render() 返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中。
<a name="LjOel"></a>
# 组件实例的属性
<a name="ilTk9"></a>
## state
```javascript
<script type="text/babel">
  // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
  class MyComponent extends React.Component {

    // 构造器方法只被调用一次,创建一个实例对象
    constructor(props) {
      super(props)
      // 初始化状态
      this.state = { isHot: true, wind: '微风' }
      //解决 changeWeather() 中 this 指向问题
      // 前面的 changeWeather 是实例的属性,后面的 changeWeather 是在原型上的方法
      this.changeWeather = this.changeWeather.bind(this)
    }

    // render 调用 1 + n 次。
    // 1 次是初始化的时候,n 次是状态更新的次数
    render() {
      // ES6 的写法
      const { isHot, wind } = this.state
      return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind} </h1>
    }

    // changeWeather 调用 n 次,n 是点击的次数
    changeWeather() {
      // 这个 changeWeather() 放 Weather 的原型对象上,供实例使用
      // 由于 changeWeather() 是作为 onClick 的回调,所以不是通过实例调用的,是直接调用
      // 类中的方法默认开启了局部的严格模式,所以 changeWeather() 中的 this 为 undefined
      console.log(this)
      // 状态必须通过 setState 进行更新,且更新是一种合并,不是替换。
      // 这里对象里没有写 wind,wind 保持原来的值不变
      this.setState({ isHot: !this.state.isHot })
    }
  }

  // 渲染组件到页面
  ReactDOM.render(<MyComponent />, document.getElementById('test'))
</script>

state 的简写方式

<script type="text/babel">
  // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
    class MyComponent extends React.Component {

    // 初始化状态
    state = { isHot: true, wind: '微风' }

    render() {
      // ES6 的写法
      const { isHot, wind } = this.state
      return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind} </h1>
    }

    // 自定义方法, 要用 赋值语句的形式 + 箭头函数
    changeWeather = () => {
      console.log(this)
      this.setState({ isHot: !this.state.isHot })
    }
    }

  // 渲染组件到页面
  ReactDOM.render(<MyComponent />, document.getElementById('test'))
</script>

props

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <!-- 准备好一个“容器” -->
    <div id="test1"></div>
    <div id="test2"></div>
    <div id="test3"></div>

    <!-- 引入 react 核心库 -->
    <!-- 相当于拥有了 React -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作 DOM -->
    <!-- 相当于拥有了 ReactDOM -->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 引入 babel,用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!-- 引入 prop-types,用于对组件标签属性进行限制 -->
    <!-- 相当于拥有了 propTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">

        // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
        class Person extends React.Component {

            render() {
                // ES6 的语法
                const { name, sex, age } = this.props
                return (
                    <ul>
                      <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age + 1}</li>
                              </ul>
                )
            }
        }

        // 对标签属性进行 类型 和 必要性 限制
        Person.propTypes = {
            // 限制 name 必须传值,且必须为字符串类型,否则控制台报错
            name: PropTypes.string.isRequired,
            // 限制 sex 为字符串
            sex: PropTypes.string,
            // 限制 age 为数值
            age: PropTypes.number,
            // 限制 speak 为函数,注意是:func
            speak: PropTypes.func
        }

        // 指定默认标签属性值(如果不写的话)
        Person.defaultProps = {
            // sex 默认值为男
            sex: '男',
            // age 默认值为 18
            age: 18
        }

        // 渲染组件到页面
        ReactDOM.render(<Person name="Tom" sex="女" age={19} />, document.getElementById('test1'))

        // 批量传递 props
        const p = { name: "Merry", sex: "男", age: 30 }
        // 这里 {...p} 是 React 的特殊用法,不是对象的复制
        ReactDOM.render(<Person {...p} />, document.getElementById('test2'))
        // ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>, document.getElementById('test2'))


        // 由于对标签属性进行了限制,所有该写法在浏览器的 Console 报 warning
        // ReactDOM.render(<Person sex="男" age="19" />, document.getElementById('test3'))

        ReactDOM.render(<Person name="郝飞宇" speak={speak} />, document.getElementById('test3'))

        function speak() {
            console.log("我说话了")
        }
    </script>

</body>

</html>

props 的简写方式

<script type="text/babel">
  // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
  class Person extends React.Component {

    constructor(props) {
      //构造器是否接收 props,是否传递给 super,
      // 取决于:我们是否希望在构造器中通过 this 访问 props
      super(props)
      // 如果没有将 props 传递给 super,那么下面的 this.props 将为 undefined
      // 除此之外,和不写构造器相比,无其他差别
      console.log('constructor', this.props);
    }

    // 对标签属性进行 类型 和 必要性 限制
    static propTypes = {
      // 限制 name 必须传值,且必须为字符串类型,否则控制台报错
      name: PropTypes.string.isRequired,
      // 限制 sex 为字符串
      sex: PropTypes.string,
      // 限制 age 为数值
      age: PropTypes.number,
      // 限制 speak 为函数,注意是:func
      speak: PropTypes.func
    }

    // 指定默认标签属性值(如果不写的话)
    static defaultProps = {
      // sex 默认值为男
      sex: '男',
      // age 默认值为 18
      age: 18
    }

        render() {
      // ES6 的语法
      const { name, sex, age } = this.props
      // props 是只读的,不能修改。this.props.name = "h" 将会报错

      return (
                <ul>
            <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age + 1}</li>
                </ul>
            )
        }
    }

    // 渲染组件到页面
    // age 用的是默认值 18,sex 用的是默认值 男
    ReactDOM.render(<Person name="Tom" />, document.getElementById('test1'))

</script>

函数式组件使用 props

<script type="text/babel">
  // 创建函数式组件(首字母必须大写,不然会被 jsx 解析成标签)
  function Person(props) {
    const { name, sex, age } = props
    return (
      <ul>
        <li>姓名:{name}</li>
        <li>性别:{sex}</li>
        <li>年龄:{age + 1}</li>
            </ul>
        )
  }

  // 对标签属性进行 类型 和 必要性 限制
  Person.propTypes = {
    // 限制 name 必须传值,且必须为字符串类型,否则控制台报错
    name: PropTypes.string.isRequired,
    // 限制 sex 为字符串
    sex: PropTypes.string,
    // 限制 age 为数值
    age: PropTypes.number,
    // 限制 speak 为函数,注意是:func
    speak: PropTypes.func
  }

  // 指定默认标签属性值(如果不写的话)
  Person.defaultProps = {
    // sex 默认值为男
    sex: '男',
    // age 默认值为 18
    age: 18
  }

  // 渲染组件到页面
  // age 用的是默认值 18,sex 用的是默认值 男
  ReactDOM.render(<Person name="Tom" />, document.getElementById('test1'))

</script>

refs

应该尽可能减少 ref 的使用
字符串形式的 ref

<script type="text/babel">
  // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
  class Demo extends React.Component {

    //展示左侧输入框的数据
        showData1 = () => {
      const { input1 } = this.refs
      alert(input1.value)
    }

    render() {
      return (
        <div>
          <input ref="input1" type="text" placeholder="点击按钮提示数据" />
          <button onClick={this.showData1}>点我提示左侧的数据</button>
                </div>
            )
        }
  }

  ReactDOM.render(<Demo />, document.getElementById("test1"))

</script>

回调函数形式的 ref

<script type="text/babel">
  // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
  class Demo extends React.Component {

    //展示左侧输入框的数据
    showData1 = () => {
      const { input1 } = this
      alert(input1.value)
    }

    render() {
      return (
        <div>
            {/* 在非首次调用 render 时,该回调函数会被调用两次
                  第一次的 currentNode 值为 null
              第二次的 currentNode 值为 节点
              但对我们几乎无影响
                    */}
            <input ref={(currentNode) => { this.input1 = currentNode }} type="text" placeholder="点击按钮提示数据" />
                <button onClick={this.showData1}>点我提示左侧的数据</button>
            </div>
      )
    }
  }

  ReactDOM.render(<Demo />, document.getElementById("test1"))

</script>

createRef 的使用

<script type="text/babel">
    // 创建类式组件(首字母必须大写,不然会被 jsx 解析成标签)
    class Demo extends React.Component {

        // React.createRef 调用后可以返回一个容器, 该容器可以存储被 ref 所标识的节点, 
        // 该容器是“专人专用”的, 即一个容器只可以存储一个节点
        myRef1 = React.createRef()

        //展示左侧输入框的数据
        showData1 = () => {
            alert(this.myRef1.current.value)
        }

        render() {
            return (
                <div>
                    <input ref={this.myRef1} type="text" placeholder="点击按钮提示数据" />
                    <button onClick={this.showData1}>点我提示左侧的数据</button>
                </div>
            )
        }
    }

    ReactDOM.render(<Demo />, document.getElementById("test1"))

</script>

React 中的事件处理

使用方法

  1. 通过 onXxx 属性指定事件处理函数(注意大小写 onClick、onBlur)
  • React 使用的是自定义(合成)事件,而不是使用的原生 DOM 事件。为了更好的兼容性
  • React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素)。为了更高效
  1. 通过 event.target 得到发生事件的 DOM 元素对象。不要过度使用 ref ```javascript