JSX教程

1.JSX简介

JSX(JavaScript XML)是一种类似于XML的语法扩展,用于在JavaScript中编写类似于HTML的结构。它被广泛应用于React框架中,用于描述React组件的结构和UI。

JSX允许开发者在JavaScript代码中直接编写类似于HTML的标记,使得编写和阅读组件的结构更加直观和易于理解。在编译过程中,Babel等工具会将JSX代码转换为纯JavaScript代码,以便在浏览器中运行。

React框架是一个用于构建用户界面的JavaScript库。它采用了组件化开发的思想,允许开发者将界面拆分为独立、可重用的组件,并通过数据流动和状态管理来构建动态的用户界面。

在React中,使用JSX语法编写组件的结构和UI。JSX允许在组件中以声明式的方式描述界面的样式、交互和数据渲染逻辑。当React应用启动时,它会将JSX代码转换为对应的JavaScript函数调用,从而创建React元素树,并通过调用ReactDOM库中的方法将它们渲染到DOM中。

2.JSX书写规范

JSX与HTML有一定区别,书写时存在一些编写规范,此外还贴了一个HTML 转化为 JSX 代码的工具transform.tools/html-to-jsx

1. 只能返回一个根元素

JSX语法被转化为JavaScript代码时,会被转化为一个函数调用,而函数调用只能返回一个值。因此,JSX语法中只能有一个根元素,其他的元素必须作为根元素的子元素存在。如果有多个根元素,需要将它们包裹在一个父元素中。

例如对于下列代码,需要采用<div> 标签对多个元素进行包裹

javascript 复制代码
render() {
  return (
    <div>
      <h2>{this.state.count}</h2>
    	<button onClick={this.addCount}>+1</button>
    	<button onClick={this.subCount}>-1</button>
  	</div>
	)
}

如果你不想在标签中增加一个额外的 <div>标签,可以用 <> </> 元素来代替:该空标签被称作 Fragment。React Fragment 允许你将子元素分组,而不会在 HTML 结构中添加额外节点。

javascript 复制代码
render() {
  return (
    <>
      <h2>{this.state.count}</h2>
    	<button onClick={this.addCount}>+1</button>
    	<button onClick={this.subCount}>-1</button>
  </>
	)
}

2.标签必须自闭合

对于没有子元素的标签,使用自闭合的形式(在标签末尾加上斜杠),例如:<img src="image.jpg" alt="Image" />。

3.JSX注释

在JSX中添加注释,可以使用花括号{/* /}来包裹注释内容。例如:{/ 这是一个注释 */}。

javascript 复制代码
// 渲染内容
render() {
    return (
        <div>
            {/* jsx注释写法 */}
            <h2>{this.state.message}</h2>
        </div>
    )
}

4.JSX外层包裹小括号()

可以使用小括号()将最外层的jsx包裹起来,方便代码阅读

javascript 复制代码
return (
  <>
    <h1>海蒂·拉玛的代办事项</h1>
    <img 
      src="https://i.imgur.com/yXOvdOSs.jpg" 
      alt="Hedy Lamarr" 
      className="photo" 
    />
    <ul>
      <li>发明一种新式交通信号灯</li>
      <li>排练一个电影场景</li>
      <li>改进频谱技术</li>
    </ul>
  </>
);

3 JSX中花括号{}的意义

在编写JSX的过程中,有时候,可能想要在标签中添加一些 JavaScript 逻辑或者引用动态的属性。这种情况下,你可以在 JSX 的大括号内来编写 JavaScript。

在JSX中,{ }表示一个表达式的开始和结束。它用于在JSX中嵌入JavaScript代码。

你可以在{}中放置以下类型的内容:

  • 1变量:你可以将JavaScript变量放在{}中,以在JSX中使用它们。例如:{myVariable}。
  • 表达式:你可以在{}中使用JavaScript表达式,例如数学运算、函数调用等。例如:{2 + 2}。
  • 函数:你可以在{}中调用JavaScript函数,并使用其返回值。例如:{myFunction()}。
  • 对象属性:你可以在{}中使用JavaScript对象的属性。例如:{myObject.property}。
  • 条件语句:你可以在{}中使用JavaScript的条件语句,例如if语句或三元运算符。例如:{condition ? trueValue : falseValue}。
  • JSX元素:你可以在{}中嵌套其他JSX元素,以构建复杂的JSX结构。例如:{
    Some JSX content }。

需要注意的是,{}中的内容会被当作JavaScript代码进行解析和执行,因此确保在{}中只放置合法的JavaScript代码。

4.JSX嵌入变量作为子元素

4.1 变量为Number、String、Array类型,可以直接渲染

xml 复制代码
 <script type="text/babel">
  class App extends React.Component {
      // 构建数据
      constructor() {
          super()
          this.state = {
              message: "hello world",
              score: 100,
              books: ['math', 'english', 'music']
          }
      }
      // 渲染内容
      render() {
          return (
              <div>
                  <h2>{this.state.message}</h2>
                  <h2>{this.state.score}</h2>
                  <h2>{this.state.books}</h2>
              </div>
          )
      }
  }
  const root = ReactDOM.createRoot(document.querySelector('#root'))
  root.render(<App/>)
</script>

需要注意的是,数组默认是可以直接渲染的,也就是说不需要采用map等方法也可以渲染,它会把内容默认连接在一起,显然这么做没有什么意义。

4.2变量为null、undefined、Boolean类型,内容为空

变量为上述三种类型,并且直接通过{ } 渲染时,会直接不显示内容。

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- react CDN引入 -->
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <!-- babel引入,用于处理jsx -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        class App extends React.Component {
            // 构建数据
            constructor() {
                super()
                this.state = {
                    message: "hello world",
                    score: 100,
                    books: ['math', 'english', 'music'],

                    nullVal: null,
                    unVal: undefined,
                    isOpen: true
                }
            }
            // 渲染内容
            render() {
                return (
                    <div>
                        <div>
                            <h1>变量为Number、String、Array类型</h1>
                            <h2>{this.state.message}</h2>
                            <h2>{this.state.score}</h2>
                            <h2>{this.state.books}</h2>
                        </div>
                        <div>
                            <h1>null、undefined、Boolean类型</h1>
                            <h2>{this.state.nullVal}</h2>
  													<h2>{this.state.nullVal+ ""}</h2>
                            <h2>{this.state.unVal}</h2>
                            <h2>{this.state.isOpen}</h2>
                        </div>
                    </div>
                )
            }
        }
        const root = ReactDOM.createRoot(document.querySelector('#root'))
        root.render(<App/>)
    </script>
</body>
</html>

如果必要情况下想要在页面显示null,undefined等,可以考虑采用"空字符串拼接","String数据类型转换"等等

对应的div结构如下,可以看到通过空字符串拼接处理后的h2标签可以正常显示null,其余则直接为空

4.3变量为Object类型,不可以直接作为子元素

如果要把Object类型直接放到{}中间,会直接报错。对于Object类型,需要选择其中具体的属性来进行展示。

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- react CDN引入 -->
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <!-- babel引入,用于处理jsx -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
      class App extends React.Component {
          // 构建数据
          constructor() {
              super()
              this.state = {
                  message: "hello world",
                  score: 100,
                  books: ['math', 'english', 'music'],

                  nullVal: null,
                  unVal: undefined,
                  isOpen: true,

                  Person: {
                      age: 18,
                      height: 172
                  }
              }
          }
          // 渲染内容
          render() {
              return (
                  <div>
                      <div>
                          <h1>Object类型</h1>
                          <h2>{this.state.Person}</h2>
                      </div>
                  </div>
              )
          }
      }
      const root = ReactDOM.createRoot(document.querySelector('#root'))
      root.render(<App/>)
  </script>
</body>
</html>

因此应该在对应的jsx代码处按下述方式对Object类型进行访问

css 复制代码
<div>
  <h1>Object类型</h1>
  <h2>{this.state.Person.age}</h2>
  <h2>{this.state.Person.height}</h2>
</div>

5.JSX嵌入表达式

在本章的演示中,通过this.state初始化了组件的状态,包含了firstName、lastName、books、score1、score2和Person等属性。

javascript 复制代码
constructor() {
      super()
      this.state = {
        firstName: 'Hao',
        lastName: 'Wei',
        books: ['math', 'english', 'music'],

        score1: 80,
        score2: 95,

        Person: {
          age: 18,
          height: 172
        }
      }
}

对应的完整渲染函数 如下:,具体的每一部分分别在下方分别讲述。在render方法中,使用了大括号{}来插入JSX表达式,将变量、运算、方法调用等动态内容渲染到组件中。使用了const关键字定义了一些局部变量,将this.state中的数据进行解构和组合。使用map()方法和箭头函数将数组中的每个元素映射为

  • 元素,并将它们渲染为列表。

    javascript 复制代码
    render() {
      const { firstName, lastName } = this.state
      const { score1, score2 } = this.state
      const { books } = this.state
      const fullName = firstName + lastName
    
      const liELs = books.map(book => <li>{book}</li>)
                              return (
        <div>
        <div>
        <h1>JSX插入表达式</h1>
        <h2>{firstName + '' + lastName}</h2>
      <h2>{fullName}</h2>
      <h2>{3 + 5}</h2>
      </div>
      <div>
      <h1>JSX插入三元运算符</h1>
      <h2>{score1 > 90 ? '优秀':'良好'}</h2>
      <h2>{score2 > 90 ? '优秀':'良好'}</h2>
      </div>
      <div>
      <h1>JSX调用方法</h1>
      <ul>{liELs}</ul>
      <ul>{books.map(book => <li>{book}</li>)}</ul>
                     <ul>{this.getBooks()}</ul>
                     </div>
                     </div>
                    )
    }

    5.1 运算表达式

    JSX内可以使用运算表达式。

    css 复制代码
    <div>
      <h1>JSX插入表达式</h1>
      <h2>{firstName + '' + lastName}</h2>
      <h2>{fullName}</h2>
      <h2>{3 + 5}</h2>
    </div>

    5.2 三元运算符

    css 复制代码
    <div>
      <h1>JSX插入三元运算符</h1>
      <h2>{score1 > 90 ? '优秀':'良好'}</h2>
      <h2>{score2 > 90 ? '优秀':'良好'}</h2>
    </div>

    5.3 引用函数

    getBooks方法中,你使用this.state.books.map()将书籍数组转换为

  • 元素的数组,并将其作为方法的返回值。

    在jsx的{}中,可以直接调用方法

    css 复制代码
    <div>
      <h1>JSX调用方法</h1>
      <ul>{liELs}</ul>
      <ul>{books.map(book => <li>{book}</li>)}</ul>
      <ul>{this.getBooks()}</ul>
    </div>
    javascript 复制代码
    getBooks() {
      const liEls = this.state.books.map(book => <li>{book}</li>)
      return liEls
    }

    6.JSX绑定className属性

    下列代码讲述了两种不同的方式来绑定className属性。

    在JavaScript部分,定义了一个名为App的React类组件。在构造函数中,使用super()调用父类的构造函数,然后通过this.state初始化了组件的状态,包含了message和isActive两个属性。

    在render方法中,使用了大括号{}来插入JSX表达式,动态渲染组件的UI。首先,使用解构赋值从this.state中获取isActive的值。

    接下来,展示了两种不同的方式来绑定className属性。

    • a. 方法一:使用模板字符串

    创建了一个名为h2Class的变量,使用模板字符串的方式将多个类名拼接在一起,并根据isActive的值决定是否添加active类名。

    • b. 方法二:使用样式数组

    创建了一个名为h2ClassArray的数组,初始值为['abc', 'cba'],然后根据isActive的值决定是否将'active'添加到数组中。最后,使用join()方法将数组元素拼接为一个字符串,并赋值给h2Class2变量。

    在return语句中,通过使用大括号{}将变量h2Class和h2Class2嵌入到className属性中,实现了动态绑定类名。

    最后,使用ReactDOM.createRoot方法创建了一个根节点,并使用root.render方法将组件渲染到根节点上。

    整体而言,这段代码实现了一个简单的React应用。App组件的render方法根据isActive的值,动态绑定了不同的类名到两个

    元素的className属性上。 通过这种方式,可以在组件的渲染过程中根据状态数据来控制类名的动态变化,从而实现样式的动态切换。

    xml 复制代码
    <script type="text/babel">
    class App extends React.Component {
    // 构建数据
    constructor() {
    super()
    this.state = {
    message: 'Hello',
    isActive: false
    }
    }
    // 渲染内容
    render() {
    const { isActive } = this.state
    {/*1.className属性绑定方法一:模版字符串*/}
    const h2Class = `abc cba ${isActive? 'active':''}`
    {/*2.className属性绑定方法二:样式数组*/}
    const h2ClassArray = ['abc', 'cba']
    if (isActive) {
    h2ClassArray.push('active')
    }
    const h2Class2 = h2ClassArray.join(" ")
    return (
    <div>
    <h2 className={h2Class}>{this.state.message}</h2>
    <h2 className={h2Class2}>{this.state.message}</h2>
    </div>
    )
    }
    }
    const root = ReactDOM.createRoot(document.querySelector('#root'))
    root.render(<App/>)
    </script>

    7.JSX绑定元素的内联样式style属性

    展示了如何在JSX中绑定style属性,并设置不同的样式。

    在render方法中,使用了大括号{}来插入JSX表达式,动态渲染组件的UI。首先,使用解构赋值从this.state中获取styleObj的值。

    <h2>元素中,使用了两种方式来设置样式:

    • a. 方法一:直接在style属性中写入样式对象

    使用双大括号{{ }},外层大括号表示JSX表达式,内层大括号表示样式对象。直接在style属性中写入color: 'blue',即将文字颜色设置为蓝色。

    • b. 方法二:将样式对象作为变量

    将styleObj作为变量,通过style={styleObj}将样式对象传递给style属性

    在return语句中,将上述两个<h2>元素嵌入到
    元素中,实现了两个不同样式的文本显示。

    最后,使用ReactDOM.createRoot方法创建了一个根节点,并使用root.render方法将组件渲染到根节点上。

    App组件的render方法根据状态数据动态设置了两个<h2>元素的样式。通过直接在style属性中写入样式对象或使用变量传递样式对象,可以在组件的渲染过程中灵活地设置元素的内联样式。

    xml 复制代码
    <script type="text/babel">
      class App extends React.Component {
        // 构建数据
        constructor() {
          super()
          this.state = {
            message: "hello world",
            styleObj: { color: "red", fontSize: "30px" }
          }
        }
        // 渲染内容
        render() {
          const {styleObj} = this.state
          return (
            <div>
            <h2 style={{color: 'blue'}}>{this.state.message}</h2>
      			<h2 style={styleObj}>{this.state.message}</h2>
     			 </div>
    )
    }
    }
    </script>

    此外,如果想要根据条件动态创建样式对象,并将其作为style属性的值,可以参考下列代码的写法:

    javascript 复制代码
    const isActive = true;
    const dynamicStyles = {
      color: isActive ? 'green' : 'red',
      fontSize: isActive ? '18px' : '14px'
    };
    
    return <div style={dynamicStyles}>Hello, JSX!</div>;

    8.JSX的本质

    jsx实际上是对React.createElement函数的调用,是一种语法糖。JSX(JavaScript XML)是一种JavaScript的扩展语法,它允许我们在JavaScript代码中编写类似XML的标记,用于描述React元素的结构。在jsx中,我们可以使用类似HTML的语法来创建React元素。

    例如,在jsx中,我们可以这样创建一个简单的
    元素:

    ini 复制代码
    const element = <div>Hello, JSX!</div>;

    这个jsx代码看起来类似HTML,但实际上,这是JavaScript代码。

    8.1 jsx编译过程:

    当使用jsx语法时,它并不是直接在浏览器中执行的,而是需要经过编译的过程。在编译阶段,jsx代码会被转换为普通的JavaScript代码。

    转换的过程主要是通过Babel这样的工具来完成。Babel是一个广泛使用的JavaScript编译器,可以将高级JavaScript代码(包括jsx)转换为ES5代码,以便在现代和旧版浏览器中执行。

    jsx转换为React.createElement:

    在jsx编译过程中,jsx代码会被转换为React.createElement函数的调用。例如,上面的jsx代码会被转换为如下形式的JavaScript代码:

    ini 复制代码
    const element = React.createElement("div", null, "Hello, JSX!");

    React.createElement函数接收三个参数:元素类型(标签名或组件),属性对象(包含元素的属性),和子元素。在这个例子中,React.createElement创建了一个
    元素,不带任何属性,并且包含文本内容"Hello, JSX!"。

    这样,我们可以看到,jsx实际上是对React.createElement函数的调用,它将帮助我们简化创建React元素的过程,使代码更加易读和直观。

    总结:jsx是React的一种语法扩展,它允许我们在JavaScript代码中编写类似XML的标记,用于描述React元素的结构。在编译阶段,jsx代码会被转换为React.createElement函数的调用,帮助我们更方便地创建React元素,使代码更加易读和维护。这也是为什么我们可以使用jsx来创建React组件。

    Babel官网babeljs.io/ 也提供了代码转换的工具,可以看到jsx实时转换为react原生写法的过程。

    8.2案例演示

    xml 复制代码
    <script>
      class App extends React.Component {
        // 构建数据
        constructor() {
          super();
          this.state = {
            message: "hello world",
          };
        }
        // 渲染内容
        render() {
          // react原生创建元素的方式
          const element = /*#__PURE__*/ React.createElement(
            "div",
            null,
            /*#__PURE__*/ React.createElement(
              "div",
              {
                className: "header",
              },
              "header"
            ),
            /*#__PURE__*/ React.createElement(
              "div",
              {
                className: "content",
              },
              /*#__PURE__*/ React.createElement(
                "div",
                null,
                "\u5185\u5BB9\u4E00"
              ),
              /*#__PURE__*/ React.createElement(
                "div",
                null,
                "\u5185\u5BB9\u4E8C"
              )
            ),
            /*#__PURE__*/ React.createElement(
              "div",
              {
                className: "footer",
              },
              "footer"
            )
          );
          console.log("element元素(虚拟DOM对象)", element);
          return element;
        }
      }
    // 2. 创建root并渲染App组件
    const root = ReactDOM.createRoot(document.querySelector("#root"));
    root.render(React.createElement(App, null));
    </script>

    定义了一个React类组件 App,它有一个构造函数用于初始化组件的状态(state),并且定义了一个render方法,用于渲染组件的内容。在render方法中,使用了React.createElement方法来创建React元素。

    上面你展示的原生React元素创建方式与使用JSX创建的效果是等效的,但是使用JSX可以大大简化代码。

    对于上面你使用原生方式创建的element元素,如果用JSX来表示,它会是这样的:

    css 复制代码
    const element = (
      <div>
        <div className="header">header</div>
        <div className="content">
          <div>内容一</div>
          <div>内容二</div>
        </div>
        <div className="footer">footer</div>
      </div>
    );

    这样的写法更加直观和易读,而且更符合类似HTML的结构。因此,jsx的本质是一种语法糖,它可以更方便地描述React元素的结构,最终在构建应用时会被转换为原生的React元素创建方式。

    log控制台打印虚拟DOM element的具体信息:

相关推荐
学习使我快乐013 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19953 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈4 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水5 小时前
简洁之道 - React Hook Form
前端
正小安7 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch9 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光9 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   9 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   9 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d