什么是 JSX

  1. Facebook 起草的 JS 扩展语法,本质是一个 JS 对象,会被 babel 编译,最终会被转换为 React.createElement
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/react/18.2.0/umd/react.production.min.js"></script>
        <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
        <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/babel-standalone/6.26.0/babel.min.js"></script>
      </head>
      <body>
        <div id="root"></div>
        <div id="root2"></div>
        <script type="text/babel">
          const h1 = (
            <h1>
              Hello World <span>span元素</span>
            </h1>
          );
          ReactDOM.render(h1, document.getElementById("root2"));
    
          // 两种方式等价
          const _h1 = React.createElement(
            "h1",
            {},
            "Hello World",
            React.createElement("span", {}, "span元素")
          );
          ReactDOM.render(_h1, document.getElementById("root"));
        </script>
      </body>
    </html>
    
  2. 它用于描述 UI 界面,并且其完全可以和 JavaScript 融合在一起使用;

为什么 React 选择了 JSX

  1. React 认为渲染逻辑本质上与其他 UI 逻辑存在内在耦合;

    1. 比如 UI 需要绑定事件 (button、a 原生等等)
    2. 比如 UI 中需要展示数据状态,在某些状态发生改变时,又需要改变 UI
  2. 他们之间是密不可分,所以 React 没有将标记分离到不同的文件中,而是将它们组合到了一起,这个地方就是组件 (Component)

JSX 的书写规范

  1. JSX 的顶层只能有一个根元素,所以很多时候会在外层包裹一个 div 原生,或者使用如下方式;

    1. 使用 <React.Fragment></React.Fragment> 后,并不会被渲染出来,类似 vue 中的 template 标签;
    2. 使用 <></> 后,并不会被渲染出来,类似 vue 中的 template 标签;
  2. 为了方便阅读,通常在 JSX 的外层包裹一个小括号 (),这样可以方便阅读,并且 jsx 可以进行换行书写;

  3. JSX 中的标签可以是单标签,也可以是双标签 (如果是单标签,必须以 /> 结尾)

JSX 语法解析

在 JSX 中嵌入表达式

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

    1. 书写规则:{ 表达式 }
    2. 大括号内可以是 变量、字符串、数组、函数调用 等任意 js 表达式
  2. jsx 中的注释;

    <div>
      {/* 我是一段注释 */}
      <h2>Hello World</h2>
    </div>
    
  3. JSX 嵌入变量:

    1. 情况一:当变量是 Number、String、Array 类型时,可以直接显示;
    2. 情况二:当变量是 null、undefined、Boolean 类型时内容为空,如果希望可以显示,那么需要转成字符串;
    3. 情况三:对象类型不能作为子元素 (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.不显示,not valid as a React child 报错 */}
            <h2>123{this.state.friend}</h2>
          </div>
        )
      }
    }
    
    ReactDOM.render(<App/>, document.getElementById("app"));
    
  4. 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;
      }
    }
    
  5. jsx 绑定属性:很多时候,描述的 HTML 原生会有一些属性,而我们希望这些属性也是动态的;

    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>
        )
      }
    }
    

JSX 事件监听

  1. 事件绑定:

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

    1. this 指向 丢失问题
      • 原因是 事件函数 并不是我们主动调用的,而且 React 内部调用了 事件函数 函数;
      • 而它内部调用时,并不知道要如何绑定正确的 this
    2. 解决 this 指向 的问题
      • 方案一bind 改变 this 指向
        class App extends React.Component {
          constructor(props) {
            super(props);
        
            this.state = {
              message: "你好啊"
            }
        
            // 可以通过在构造方法中直接给 this.btnClick 绑定 this,避免在 jsx 中多次使用 bind
            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 语法;
        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>
            )
          }
        
          // ES6 中给类定义属性的方法,称之为 class fields 语法
          btnClick = () => {
            console.log(this);
            console.log(this.state.message);
          }
        }
        
      • 方案三:事件监听时传入箭头函数(推荐);
        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);
          }
        }
        
  3. 事件参数传递

    1. 情况一:获取 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);
        }
      }
      
    2. 获取更多参数:传入一个箭头函数,主动执行的事件函数,并且传入相关的其他参数
      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);
        }
      }
      

JSX 条件渲染

  1. 条件判断语句

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          isLogin: true,
        };
      }
    
      render() {
        let titleJsx = null;
        if (this.state.isLogin) {
          titleJsx = <h2>欢迎回来~</h2>;
        } else {
          titleJsx = <h2>请先登录~</h2>;
        }
    
        return <div>{titleJsx}</div>;
      }
    }
    
  2. 三元运算符

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          isLogin: true,
        };
      }
    
      render() {
        return (
          <div>
            <h2>{this.state.isLogin ? "欢迎回来~" : "请先登录~"}</h2>
            <button onClick={(e) => this.loginBtnClick()}>
              {this.state.isLogin ? "退出" : "登录"}
            </button>
          </div>
        );
      }
    
      loginBtnClick() {
        this.setState({
          isLogin: !this.state.isLogin,
        });
      }
    }
    
  3. 与运算符

    {this.state.isLogin ? <h2>{this.state.username}</h2>: null}
    
    {this.state.isLogin && <h2>{this.state.username}</h2>}
    
  4. v-show 效果 (自己手动实现)

    render() {
      const { isLogin, username } = this.state;
      const nameDisplay = isLogin ? "block" : "none";
    
      return (
        <div>
          <h2 style={{ display: nameDisplay }}>{username}</h2>
          <button onClick={(e) => this.loginBtnClick()}>
            {isLogin ? "退出" : "登录"}
          </button>
        </div>
      );
    }
    

JSX 列表渲染

  1. 列表渲染

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          movies: [ "盗梦空间", "大话西游", "流浪地球", "少年派", "食神", "美人鱼", "海王" ],
        };
      }
    
      render() {
        return (
          <div>
            <h2>电影列表</h2>
            <ul>
              {this.state.movies.map((item) => {
                return <li>{item}</li>;
              })}
            </ul>
          </div>
        );
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("app"));
    
  2. 列表的 key,在列表展示的 jsx 中添加一个 key,用于虚拟 dom 更新;

案例:图片定时更换

import React from 'react';
import ReactDOM from 'react-dom';
import src1 from "./assets/1.jpg";
import src2 from "./assets/2.jpg";
import src3 from "./assets/3.jpg";
import "./index.css";

const container = document.getElementById('root');
const srcs = [src1, src2, src3]; // 保存图片路径的数组
let index = 0; // 显示的图片索引
let timer; // 计时器

function render() {
  ReactDOM.render(<img src={srcs[index]} alt="" />, container);
}

/**
 * 启动计时器,每隔一段时间,切换图片
 */
function start() {
  stop();
  timer = setInterval(() => {
    index = (index + 1) % 3; //改变index
    render();
  }, 2000);
}

/**
 * 停止计时器
 */
function stop() {
  clearInterval(timer);
}

render();
start();

container.onmouseenter = function () {
  stop();
}

container.onmouseleave = function () {
  start();
}
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 什么是 JSX
    1. 1.1. 为什么 React 选择了 JSX
    2. 1.2. JSX 的书写规范
  2. 2. JSX 语法解析
    1. 2.1. 在 JSX 中嵌入表达式
    2. 2.2. JSX 事件监听
    3. 2.3. JSX 条件渲染
    4. 2.4. JSX 列表渲染
  3. 3. 案例:图片定时更换