• 575 React系列二


    一. ES6的class

    虽然目前React开发模式中更加流行hooks,但是依然有很多的项目依然是使用类组件(包括AntDesign库中);

    但是有很多的同学对ES6中的类不太熟悉,所以这里我还是补充一下;


    1.1. 类的定义

    在ES6之前,我们通过function来定义类,但是这种模式一直被很多从其他编程语言(比如Java、C++、OC等等)转到JavaScript的人所不适应。

    原因是,大多数面向对象的语言,都是使用class关键字来定义类的。

    而JavaScript也从ES6开始引入了class关键字,用于定义一个类。

    ES6之前定义一个Person类:

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    Person.prototype.running = function() {
      console.log(this.name + this.age + "running");
    }
    
    var p = new Person("why", 18);
    p.running();
    

    转换成ES6中的类如何定义呢?

    • 类中有一个constructor构造方法,当我们通过new关键字调用时,就会默认执行这个构造方法
      • 构造方法中可以给当前对象添加属性
    • 类中也可以定义其他方法,这些方法会被放到Person类的prototype上
    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    
      running() {
        console.log(this.name + this.age + "running");
      }
    }
    
    const p = new Person("why", 18);
    p.running();
    

    另外,属性也可以直接定义在类中:

    • height和address是直接定义在类中
    class Person {
      height = 1.88;
      address = "北京市";
    
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    
      studying() {
        console.log(this.name + this.age + "studying");
      }
    }
    

    01_JavaScript类的定义.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <script>
        // ES5中如何定义类
        // function Person(name, age) {
        //   this.name = name;
        //   this.age = age;
        // }
    
        // Person.prototype.running = function() {
        //   console.log(this.name, this.age, "running");
        // }
    
        // var p = new Person("why", 18);
        // console.log(p.name, p.age);
        // p.running();
    
        // ES6中通过class创建类
        class Person {
          // 构造方法
          constructor(name, age) {
            this.name = name;
            this.age = age;
          }
    
          // 定义方法
          running() {
            // 严格模式下全局作用域中函数中的 this 是 undefined
            // 这里的this没有帮绑定任何东西,隐式、显示都没有
            console.log(this);
            console.log(this.name, this.age, "running");
          }
        }
    
        const p = new Person("why", 18);
        console.log(p.name, p.age);
        p.running();
    
        // this绑定题目
        let func = p.running;
        // 严格模式下全局作用域中函数中的 this 是 undefined
        // func();
    
        var obj = {
          name: "kobe",
          age: 40
        }
        // func.call(obj);
    
        // 重新给func赋值
        func = func.bind(obj);
        func();
    
      </script>
    </body>
    
    </html>
    

    1.2. 类的继承

    继承是面向对象的一大特性,可以减少我们重复代码的编写,方便公共内容的抽取(也是很多面向对象语言中,多态的前提)。

    ES6中增加了extends关键字来作为类的继承。

    我们先写两个类没有继承的情况下,它们存在的重复代码:

    • Person类和Student类
    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    
      running() {
        console.log(this.name, this.age, "running");
      }
    }
    
    class Student {
      constructor(name, age, sno, score) {
        this.name = name;
        this.age = age;
        this.sno = sno;
        this.score = score;
      }
    
      running() {
        console.log(this.name, this.age, "running");
      }
    
      studying() {
        console.log(this.name, this.age, this.sno, this.score, "studing");
      }
    }
    

    我们可以使用继承来简化代码:

    • 注意:在constructor中,子类必须通过super来调用父类的构造方法,对父类进行初始化,否则会报错。
    class Student1 extends Person {
      constructor(name, age, sno, score) {
        super(name, age);
        this.sno = sno;
        this.score = score;
      }
    
      studying() {
        console.log(this.name, this.age, this.sno, this.score, "studing");
      }
    }
    
    const stu1 = new Student1("why", 18, 110, 100);
    stu1.studying();
    

    02_JavaScript类的继承.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <script>
        /**
         * 面向对象有三大特性: 封装继承多态
         * 继承: 1.减少重复的代码 2.多态的前提(鸭子类型)
         */
    
        class Person {
          constructor(name, age) {
            this.name = name;
            this.age = age;
          }
    
          running() {
            console.log("running");
          }
        }
    
        class Student extends Person {
          constructor(name, age, sno) {
            // 调用super,就会去执行父类的 constructor方法,子类中必须初始化父类对象
            super(name, age);
            this.sno = sno;
          }
        }
    
        const stu = new Student("why", 18, 110);
        console.log(stu.name, stu.age, stu.sno);
        stu.running();
    
    
        class Teacher extends Person {
          constructor(name, age, title) {
            // 子类中是必须初始化父类对象
            super(name, age);
            this.title = title;
          }
        }
    
        const teacher = new Teacher("kobe", 40, "教练");
        console.log(teacher.name, teacher.age, teacher.title);
        teacher.running();
    
        // class Student {
        //   constructor(name, age, sno) {
        //     this.name = name;
        //     this.age = age;
        //     this.sno = sno;
        //   }
    
        //   running() {
        //     console.log("running");
        //   }
        // }
    
        // class Teacher {
        //   constructor(name, age, title) {
        //     this.name = name;
        //     this.age = age;
        //     this.title = title;
        //   }
    
        //   running() {
        //     console.log("running");
        //   }
        // }
    
      </script>
    </body>
    
    </html>
    

    二. 案例练习

    2.1. 列表展示

    真实开发中,我们的数据通常会从服务器获取,比较常见的是获取一个列表数据,保存到一个数组中进行展示

    • 比如现在有一个电影列表,我们如何通过React进行展示呢?

    我们还是通过一个组件来完成:

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          movies: ["星际穿越", "大话西游", "盗梦空间", "少年派"]
        }
      }
    
      render() {
        // var movieLis = [];
        // for (var i in this.state.movies) {
        //   movieLis.push((<li>{this.state.movies[i]}</li>));
        // }
    
        return (
          <div>
            <h2>电影列表</h2>
            <ul>
              {
                this.state.movies.map((item, index) => {
                  return (<li>{item}</li>)
                })
              }
            </ul>
          </div>
        )
      }
    }
    
    ReactDOM.render(<App/>, document.getElementById("app"));
    

    01_案例练习-电影列表.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      
      <div id="app"></div>
    
      <!-- 1.引入依赖 -->
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <!-- 2.编写React代码 -->
      <script type="text/babel">
        class App extends React.Component {
          constructor() {
            super();
    
            this.state = {
              message: "Hello World",
              movies: ["大话西游", "盗梦空间", "星际穿越", "流浪地球"]
            }
          }
    
          render() {
            const liArray = [];
            for (let movie of this.state.movies) {
              liArray.push(<li>{movie}</li>);
            }
    
            return (
              <div>
                <h2>电影列表1</h2>
                <ul>
                  {liArray}
                </ul>
    
                <h2>电影列表2</h2>
                <ul>
                  {
                    this.state.movies.map((item) => {
                      return <li>{item}</li>
                    })
                  }
                </ul>
              </div>
            )
          }
        }
    
        ReactDOM.render(<App/>, document.getElementById("app"));
      </script>
    
    </body>
    </html>
    

    https://snippet-generator.app/


    2.2. 计数器案例

    电影列表的案例中并没有交互,我们再来实现一个计数器的案例:

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          counter: 0
        }
      }
    
      render() {
        return (
          <div>
            <h2>当前计数:{this.state.counter}</h2>
            <button onClick={this.increment.bind(this)}>+1</button>
            <button onClick={this.decrement.bind(this)}>-1</button>
          </div>
        )
      }
    
      increment() {
        this.setState({
          counter: this.state.counter+1
        })
      }
    
      decrement() {
        this.setState({
          counter: this.state.counter-1
        })
      }
    }
    
    ReactDOM.render(<App/>, document.getElementById("app"));
    

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
        
      <div id="app"></div>
    
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <script type="text/babel">
        class App extends React.Component {
          constructor(pops) {
            super(props);
    
            this.state = {
              counter: 0
            }
          }
    
          render() {
            return (
              <div>
                <h2>当前计数: {this.state.counter}</h2>
                <button onClick={this.increment}>+1</button>
                <button onClick={this.decrement.bind(this)}>-1</button>
                <img src="" alt=""/>
              </div>
            )
          }
    
          increment() {
            this.setState({
              counter: this.state.counter + 1
            })
          }
    
          decrement() {
            this.setState({
              counter: this.state.counter - 1
            })
          }
        }
    
        ReactDOM.render(<App/>, document.getElementById("app"));
      </script>
    
    </body>
    </html>
    

    三. JSX语法解析

    补充:类组件的类名、this探讨

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>哈哈</title>
    </head>
    
    <body>
      <div id="app"></div>
    
      <script src="./react/react.development.js"></script>
      <script src="./react/react-dom.development.js"></script>
      <script src="./react/babel.min.js"></script>
    
      <script type="text/babel">
        function getImageSize(url, size) {
          return url + `?param=${size}x${size}`
        }
    
        let self = null
    
        class App extends React.Component {
          constructor(props) {
            super(props);
            this.state = {
              age: 222
            }
          }
    
          render() {
            self = this
            console.log(this) // App,是个对象
            console.log(App) // 是个函数,类的本质是函数,通过typeof可测出
            console.log(typeof this) // object
            console.log(typeof App) // function
            console.log(this === App) // false
            console.log(this.state.age) // 222
    
            return (
              <div>
                111
              </div>
            )
          }
        }
    
        console.log(self === App) // false
        ReactDOM.render(<App />, document.getElementById("app"));
      </script>
    
    </body>
    
    </html>
    

    3.1. 认识JSX的语法

    我们先来看一段代码:

    • 这段element变量的声明右侧赋值的标签语法是什么呢?
      • 它不是一段字符串(因为没有使用引号包裹),它看起来是一段HTML原生,但是我们能在js中直接给一个变量赋值html吗?
      • 其实是不可以的,如果我们将 type="text/babel" 去除掉,那么就会出现语法错误;
      • 它到底是什么呢?其实它是一段jsx的语法;
    <script type="text/babel">
      const element = <h2>Hello World</h2>
      ReactDOM.render(element, document.getElementById("app"));
    </script>
    

    JSX是什么?

    • JSX是一种JavaScript的语法扩展(eXtension),也在很多地方称之为JavaScript XML,因为看起就是一段XML语法;
    • 它用于描述我们的UI界面,并且其完全可以和JavaScript融合在一起使用;
    • 它不同于Vue中的模块语法,你不需要专门学习模块语法中的一些指令(比如v-for、v-if、v-else、v-bind);

    为什么React选择了JSX?

    • React认为渲染逻辑本质上与其他UI逻辑存在内在耦合
      • 比如UI需要绑定事件(button、a原生等等);
      • 比如UI中需要展示数据状态,在某些状态发生改变时,又需要改变UI;
    • 他们之间是密不可分,所以React没有将标记分离到不同的文件中,而是将它们组合到了一起,这个地方就是组件(Component);
      • 当然,后面我们还是会继续学习更多组件相关的东西;
    • 在这里,我们只需要知道,JSX其实是嵌入到JavaScript中的一种结构语法;

    JSX的书写规范:

    • JSX的顶层只能有一个根元素,所以我们很多时候会在外层包裹一个div原生(或者使用后面我们学习的Fragment);
    • 为了方便阅读,我们通常在jsx的外层包裹一个小括号(),这样可以方便阅读,并且jsx可以进行换行书写;
    • JSX中的标签可以是单标签,也可以是双标签;
      • 注意:如果是单标签,必须以/>结尾;

    JSX的本质,我们后面再来讨论;


    3.2. JSX嵌入表达式

    如果我们jsx中的内容是动态的,我们可以通过表达式来获取:

    • 书写规则:{表达式}
    • 大括号内可以是变量、字符串、数组、函数调用等任意js表达式;

    3.2.1. jsx中的注释

    jsx是嵌入到JavaScript中的一种语法,所以在编写注释时,需要通过JSX的语法来编写:

    <div>
      {/* 我是一段注释 */}
      <h2>Hello World</h2>
    </div>
    

    3.2.2. JSX嵌入变量

    • 情况一:当变量是Number、String、Array类型时,可以直接显示
    • 情况二:当变量是null、undefined、Boolean类型时,内容为空;
      • 如果希望可以显示null、undefined、Boolean,那么需要转成字符串;
      • 转换的方式有很多,比如toString方法、和空字符串拼接,String(变量)等方式;
    • 情况三:对象类型不能作为子元素(not valid as a React child)
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          name: "why",
          age: 18,
          hobbies: ["篮球", "唱跳", "rap"],
          
          test1: null,
          test2: undefined,
          flag: false,
    
          friend: {
            name: "kobe",
            age: 40
          }
        }
      }
    
      render() {
        return (
          <div>
            {/* 我是一段注释 */}
            <h2>Hello World</h2>
          </div>
    
          <div>
            {/* 1.可以直接显示 */}
            <h2>{this.state.name}</h2>
            <h2>{this.state.age}</h2>
            <h2>{this.state.hobbies}</h2>
    
            
            {/* 2.不显示 */}
            <h2>{this.state.test1}</h2>
            <h2>{this.state.test1 + ""}</h2>
            <h2>{this.state.test2}</h2>
            <h2>{this.state.test2 + ""}</h2>
            <h2>{this.state.flag}</h2>
            <h2>{this.state.flag + ""}</h2>
            
            {/* 3.不显示 */}
            <h2>123{this.state.friend}</h2>
          </div>
        )
      }
    }
    
    ReactDOM.render(<App/>, document.getElementById("app"));
    

    ~

    补充:为什么null、undefined、Boolean在JSX中要显示为空内容呢?

    原因是在开发中,我们会进行很多的判断;

    • 在判断结果为false时,不显示一个内容;
    • 在判断结果为true时,显示一个内容;

    这个时候,我们可以编写如下代码:

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          flag: false
        }
      }
    
      render() {
        return (
          <div>
            {this.state.flag ? <h2>我是标题</h2>: null}
            {this.state.flag && <h2>我是标题</h2>}
          </div>
        )
      }
    }
    

    3.3.3. JSX嵌入表达式

    JSX中,也可以是一个表达式。

    这里我们演练三个,其他的大家在开发中灵活运用:

    • 运算表达式
    • 三元运算符
    • 执行一个函数
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          firstName: "kobe",
          lastName: "bryant",
          age: 20
        }
      }
    
      render() {
        return (
          <div>
            {/* 运算表达式 */}
            <h2>{this.state.firstName + " " + this.state.lastName}</h2>
            {/* 三元运算符 */}
            <h2>{this.state.age >= 18 ? "成年人": "未成年人"}</h2>
            {/* 执行一个函数 */}
            <h2>{this.sayHello("kobe")}</h2>
          </div>
        )
      }
    
      sayHello(name) {
        return "Hello " + name;
      }
    }
    

    3.3.4. jsx绑定属性

    很多时候,描述的HTML原生会有一些属性,而我们希望这些属性也是动态的:

    • 比如元素都会有title属性
    • 比如img元素会有src属性
    • 比如a元素会有href属性
    • 比如元素可能需要绑定class
      • 注意:绑定class比较特殊,因为class在js中是一个关键字,所以jsx中不允许直接写class
      • 写法:使用className替代
    • 比如原生使用内联样式style
      • style后面跟的是一个对象类型,对象中是样式的属性名和属性值;
      • 注意:这里会讲属性名转成驼峰标识,而不是连接符-;

    我们来演示一下属性的绑定:

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          title: "你好啊",
          imgUrl: "https://upload.jianshu.io/users/upload_avatars/1102036/c3628b478f06.jpeg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240",
          link: "https://www.baidu.com",
          active: false
        }
      }
    
      render() {
        return (
          <div>
            <h2 title={this.state.title}>Hello World</h2>
            <img src={this.state.imgUrl} alt=""/>
            <a href={this.state.link} target="_blank">百度一下</a>
            <div className={"message " + (this.state.active ? "active": "")}>你好啊</div>
            <div className={["message", (this.state.active ? "active": "")].join(" ")}>你好啊</div>
            <div style={{fontSize: "30px", color: "red", backgroundColor: "blue"}}>我是文本</div>
          </div>
        )
      }
    }
    

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <div id="app"></div>
    
      <div style="color: red; font-size: 30px;"></div>
    
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <script type="text/babel">
        function getSizeImage(imgUrl, size) {
          return imgUrl + `?param=${size}x${size}`
        }
    
        class App extends React.Component {
          constructor(props) {
            super(props);
    
            this.state = {
              title: "标题",
              imgUrl: "http://p2.music.126.net/L8IDEWMk_6vyT0asSkPgXw==/109951163990535633.jpg",
              link: "http://www.baidu.com",
              active: true
            }
          }
    
          render() {
            const { title, imgUrl, link, active } = this.state;
            return (
              <div>
                {/* 1.绑定普通属性 */}
                <h2 title={title}>我是标题</h2>
                <img src={getSizeImage(imgUrl, 140)} alt=""/>
                <a href={link} target="_blank">百度一下</a>
    
                {/* 2.绑定class */}
                <div className="box title">我是div元素</div>
                <div className={"box title " + (active ? "active": "")}>我也是div元素</div>
                <label htmlFor=""></label>
    
                {/* 3.绑定style */}
                <div style={{color: "red", fontSize: "50px"}}>我是div,绑定style属性</div>
              </div>
            )
          }
        }
    
        ReactDOM.render(<App />, document.getElementById("app"));
      </script>
    
    </body>
    
    </html>
    

    3.3. jsx事件监听

    3.3.1. 和原生绑定区别

    如果原生DOM原生有一个监听事件,我们可以如何操作呢?

    • 方式一:获取DOM原生,添加监听事件;
    • 方式二:在HTML原生中,直接绑定onclick;

    我们这里演练一下方式二:

    • btnClick()这样写的原因是onclick绑定的后面是跟上JavaScript代码;
    <button onclick="btnClick()">点我一下</button>
    <script>
      function btnClick() {
      console.log("按钮发生了点击");
    }
    </script>
    

    在React中是如何操作呢?

    我们来实现一下React中的事件监听,这里主要有两点不同

    • React 事件的命名采用小驼峰式(camelCase),而不是纯小写;
    • 我们需要通过{}传入一个事件处理函数,这个函数会在事件发生时被执行;
    class App extends React.Component {
      render() {
        return (
          <div>
            <button onClick={this.btnClick}>点我一下(React)</button>
          </div>
        )
      }
    
      btnClick() {
        console.log("React按钮点击了一下")
      }
    }
    

    3.3.2. this绑定问题

    在事件执行后,我们可能需要获取当前类的对象中相关的属性:

    • 比如我们这里打印:this.state.message
      • 但是这里会报错:Cannot read property 'state' of undefined
      • 原因是this在这里是undefined
    • 如果我们这里直接打印this,也会发现它是一个undefined
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          message: "你好啊,李银河"
        }
      }
    
      render() {
        return (
          <div>
            <button onClick={this.btnClick}>点我一下(React)</button>
          </div>
        )
      }
    
      btnClick() {
        console.log(this);
        console.log(this.state.message);
      }
    }
    

    ~

    为什么是undefined呢?

    • 原因是btnClick函数并不是我们主动调用的,而且当button发生改变时,React内部调用了btnClick函数;
    • 而它内部调用时,并不知道要如何绑定正确的this;

    如何解决this的问题呢?

    方案一:bind给btnClick显示绑定this

    在传入函数时,我们可以主动绑定this:

    • 这里我们主动将btnClick中的this通过bind来进行绑定(显示绑定)
    • 那么之后React内部调用btnClick函数时,就会有一个this,并且是我们绑定的this;
    <button onClick={this.btnClick.bind(this)}>点我一下(React)</button>
    

    但是呢,如果我有两个函数都需要用到btnClick的绑定:

    • 我们发现 bind(this) 需要书写两遍;
    <button onClick={this.btnClick.bind(this)}>点我一下(React)</button>
    <button onClick={this.btnClick.bind(this)}>也点我一下(React)</button>
    

    这个我们可以通过在构造方法中直接给this.btnClick绑定this来解决:

    • 注意查看 constructor 中我们的操作:this.btnClick = this.btnClick.bind(this);
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          message: "你好啊,李银河"
        }
    
        this.btnClick = this.btnClick.bind(this);
      }
    
      render() {
        return (
          <div>
            <button onClick={this.btnClick}>点我一下(React)</button>
            <button onClick={this.btnClick}>也点我一下(React)</button>
          </div>
        )
      }
    
      btnClick() {
        console.log(this);
        console.log(this.state.message);
      }
    }
    

    ~

    方案二:使用 ES6 class fields 语法

    你会发现我这里将btnClick的定义变成了一种赋值语句:

    • 这是ES6中给类定义属性的方法,称之为class fields语法;
    • 因为这里我们赋值时,使用了箭头函数,所以在当前函数中的this会去上一个作用域中查找;
    • 而上一个作用域中的this就是当前的对象;
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          message: "你好啊,李银河"
        }
      }
    
      render() {
        return (
          <div>
            <button onClick={this.btnClick}>点我一下(React)</button>
            <button onClick={this.btnClick}>也点我一下(React)</button>
          </div>
        )
      }
    
      btnClick = () => {
        console.log(this);
        console.log(this.state.message);
      }
    }
    

    ~

    方案三:事件监听时传入箭头函数(推荐)

    因为 onClick 中要求我们传入一个函数,那么我们可以直接定义一个箭头函数传入:

    • 传入的箭头函数的函数体是我们需要执行的代码,我们直接执行 this.btnClick()
    • this.btnClick()中通过this来指定会进行隐式绑定,最终this也是正确的;
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          message: "你好啊,李银河"
        }
      }
    
      render() {
        return (
          <div>
            <button onClick={() => this.btnClick()}>点我一下(React)</button>
            <button onClick={() => this.btnClick()}>也点我一下(React)</button>
          </div>
        )
      }
    
      btnClick() {
        console.log(this);
        console.log(this.state.message);
      }
    }
    

    02_jsx绑定事件和this处理.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <div id="app"></div>
    
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <script type="text/babel">
        class App extends React.Component {
          constructor(props) {
            super(props);
            this.state = {
              message: "你好啊",
              counter: 100
            }
    
            this.btnClick = this.btnClick.bind(this);
          }
    
          render() {
            return (
              <div>
                {/* 1.方案一: bind绑定this(显示绑定) */}
                <button onClick={this.btnClick}>按钮1</button>
                <button onClick={this.btnClick}>按钮2</button>
                <button onClick={this.btnClick}>按钮3</button>
    
                {/* 2.方案二: 定义函数时, 使用箭头函数 */}
                <button onClick={this.increment}>+1</button>
    
                {/* 2.方案三(推荐): 直接传入一个箭头函数, 在箭头函数中调用需要执行的函数 【隐式绑定】*/}
                <button onClick={() => { this.decrement("why") }}>-1</button>
              </div>
            )
          }
    
          btnClick() {
            console.log(this.state.message);
          }
    
          // increment() {
          //   console.log(this.state.counter);
          // }
          // 箭头函数中永远不绑定this
          // ES6中给对象增加属性: class fields
          increment = () => {
            console.log(this.state.counter);
          }
    
          decrement(name) {
            console.log(this.state.counter, name);
          }
        }
    
        ReactDOM.render(<App />, document.getElementById("app"));
      </script>
    
    </body>
    
    </html>
    

    3.3.3. 事件参数传递

    在执行事件函数时,有可能我们需要获取一些参数信息:比如event对象、其他参数

    情况一:获取event对象

    • 很多时候我们需要拿到event对象来做一些事情(比如阻止默认行为)
    • 假如我们用不到this,那么直接传入函数就可以获取到event对象;
    class App extends React.Component {
      constructor(props) {
    
      render() {
        return (
          <div>
            <a href="http://www.baidu.com" onClick={this.btnClick}>点我一下</a>
          </div>
        )
      }
    
      btnClick(e) {
        e.preventDefault();
        console.log(e);
      }
    }
    

    ~

    情况二:获取更多参数

    • 有更多参数时,我们最好的方式就是传入一个箭头函数,主动执行的事件函数,并且传入相关的其他参数;
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          names: ["衣服", "鞋子", "裤子"]
        }
      }
    
      render() {
        return (
          <div>
            <a href="http://www.baidu.com" onClick={this.aClick}>点我一下</a>
    
            {
              this.state.names.map((item, index) => {
                return (
                  <a href="#" onClick={e => this.aClick(e, item, index)}>{item}</a>
                )
              })
            }
          </div>
        )
      }
    
      aClick(e, item, index) {
        e.preventDefault();
        console.log(item, index);
        console.log(e);
      }
    }
    

    03_jsx绑定事件-传递参数.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <button class="btn">按钮</button>
      <script>
        document.getElementsByClassName("btn")[0].addEventListener("click", (e) => {
          console.log(e);
        })
      </script>
    
      <div id="app"></div>
    
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <script type="text/babel">
        class App extends React.Component {
          constructor(props) {
            super(props);
    
            this.state = {
              movies: ["大话西游", "海王", "流浪地球", "盗梦空间"]
            }
    
            this.btnClick = this.btnClick.bind(this);
          }
    
          render() {
            return (
              <div>
                <button onClick={this.btnClick}>按钮</button>
    
                <ul>
                  {
                    this.state.movies.map((item, index, arr) => {
                      return (
                        // onClick的属性值是函数,事件对象由这个函数传递
                        <li className="item"
                          onClick={e => { this.liClick(item, index, e) }}
                          title="li">
                          {item}
                        </li>
                      )
                    })
                  }
                </ul>
              </div>
            )
          }
    
          // 和原生的一样
          btnClick(event) {
            console.log("按钮发生了点击", event);
          }
    
          liClick(item, index, event) {
            console.log("li发生了点击", item, index, event);
          }
        }
    
        ReactDOM.render(<App />, document.getElementById("app"));
      </script>
    
    </body>
    
    </html>
    
  • 相关阅读:
    文件类型的判断
    VS 2003 源码配置管理(subversion+apache)
    DataView
    sql server 挂起的文件操作
    关于权限设计的轻量级实现
    各种类型文件在SQL Server中存储的解决方案
    免费或开源的项目管理工具
    UML中的用例(Use Case)概念分析及实例
    大对象的存储
    用js实现同一页面多个运动效果
  • 原文地址:https://www.cnblogs.com/jianjie/p/14263980.html
Copyright © 2020-2023  润新知