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()方法和箭头函数将数组中的每个元素映射为
-
元素,并将它们渲染为列表。
javascriptrender() { 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>
javascriptgetBooks() { 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属性的值,可以参考下列代码的写法:
javascriptconst 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中,我们可以这样创建一个简单的
元素:iniconst 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代码:
iniconst 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来表示,它会是这样的:
cssconst 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的具体信息: