JSX语法学习

JSX 基本概念

JSXJavaScript XML 的简写,表示了在 JavaScript 中书写 XML 格式的代码。它是 React 的核心内容,它可以让我们在 React 中创建元素更加简单,更加直观,提高开发效率。

  • 什么是JSX?
    • JS 扩展语法,可以在 JS 中书写 XML 语法
  • JSX的优点?
    • 可以更加 简洁、直观、高效 的声明 UI 界面

演示

我们可以在 babel 的网站,在线测试 babeljs ,这个网站可以把 JSX 代码转换成 JS 代码

image-20220607171437890

注意JSXJavaScript语法扩展,它无法在浏览器中直接使用,在 create-react-app 脚手架中内置了 @babel/plugin-transform-react-jsx 插件来解析它,成为 JavaScript 的标准语法。

JSX 基本使用

  • 导入 react-dom
  • 使用 JSX 创建元素
  • 使用 react-dom 渲染
import ReactDom from 'react-dom';

const element = (
  <div id="box">
    <h1>JSX</h1>
    <ul>
      <li>tom</li>
      <li>jack</li>
      <li>tony</li>
    </ul>
  </div>
);

ReactDom.render(element, document.getElementById('root'));

上述代码运行成功,现在 React17x 可以不必导入React包,因为在 babel 转换的时候自动导入了创建 React 元素的依赖。但是如果你使用 React16x 那么你还需要手动导入 React ,如何验证?安装下低版本的 React 包即可。

总结

  • 导入 react-dom 使用 JSX 创建元素 使用 react-dom 渲染元素
  • 17x 版本的 React 不需要导入, 低版本 是需要导入的。

补充

  • vscode settings.json 加上 在 react 中使用 ement 语法提示创建标签
"emmet.includeLanguages": {
    "javascript": "javascriptreact"
}

JSX 的注意事项

使用细节

  • 特殊属性写法 className htmlFor
  • 没有内容的节点可以使用 单标签
  • 必需有根节点,可以使用 <></> 幽灵标签,其实是 <React.Fragment></React.Fragment> 简写
  • 如果 JSX 有换行,最好使用 () 包裹

代码示例

  • 特殊属性
// class ---> className    for ---> htmlFor  特殊属性
<div className="box">
  <label htmlFor="ck"></label>
  <input id="ck" type="checkbox" />
</div>
  • 可单标签
// <span className="icon-edit"></span> 没内容可以写成单标签形势
<span className="icon-edit" />
  • 有根节点
// 1. 使用 React.Fragment 代码片段
import React from 'react';
import ReactDom from 'react-dom';
const element = (
  <React.Fragment>
    <div>header</div>
    <div>footer</div>
  </React.Fragment>
);
ReactDom.render(element, document.getElementById('root'));
// 2. 使用<></>可以避免没必要的标签产生 简写 React.Fragment
import ReactDom from 'react-dom';
const element = (
  <>
    <div>header</div>
    <div>footer</div>
  </>
);
ReactDom.render(element, document.getElementById('root'));
  • 用小括号
// 有换行的时候最好使用()可以让标签对其,避免没必要的错误
const element = (
  <>
    <div>header</div>
    <div>footer</div>
  </>
);

JSX 嵌入表达式

JSX中使用{ }嵌入JS表达式,注意不能使用语句。

  • 展示数据
  • 进行运算
  • 三元运算
  • 使用函数
  • 使用 JSX
  • 使用注释
import React from 'react';
import ReactDom from 'react-dom';

// 数据
const data = {
  name: 'tom',
  age: 18,
};

// 函数
const up = () => {
  return data.name.toUpperCase();
};

// jsx表达式
const list = (
  <ul>
    <li>jack</li>
    <li>tony</li>
  </ul>
);

const element = (
  <div>
    {/* 1. 使用数据  注释推荐快键键(ctrl+/)  */}
    <div>姓名:{data.name}</div>
    <div>年龄:{data.age}</div>
    {/* 2. 使用运算 */}
    <div>明年几岁:{data.age + 1}</div>
    {/* 3. 使用三元 */}
    <div>是否成年:{data.age > 16 ? '是' : '否'}</div>
    {/* 4. 使用函数 */}
    <div>姓名大写:{up()}</div>
    {/* 5. 使用JSX(jsx也是表达式) */}
    <div>朋友:{list}</div>
  </div>
);

ReactDom.render(element, document.getElementById('root'));

JSX 条件渲染

  • 使用分支语句 if/else 完成条件渲染
  • 使用 三元运算符 完成条件渲染
  • 使用 逻辑运算符 完成条件渲染

if/else 条件渲染

const loading = true;

// 不能在JSX中写语句,但,可以充分利用JS能力
const getContent = () => {
  if (loading) {
    return <div>正在加载...</div>;
  } else {
    return <div>数据加载完毕,这是显示数据</div>;
  }
};

const element = <div>{getContent()}</div>;

三元运算符 完成条件渲染

const loading = true;

const element = (
  <div>
    {loading ? <div>正在加载...</div> : <div>数据加载完毕,这是显示数据</div>}
  </div>
);

逻辑运算 完成条件渲染

const loading = true;

const element = (
  <div>
    {loading && <div>正在加载...</div>}
    {loading || <div>数据加载完毕,这是显示数据</div>}
  </div>
);

JSX 列表渲染

  • 可以渲染 JSX 数组
  • 使用 map 渲染列表
  • 直接在 JSX 中使用 map 渲染列表
  • key 属性使用

可以渲染 JSX 数组

// 1. const list = ['tom', 'jack', 'tony'] 把数组转换成如下JSX数组
const list = [<li>tom</li>, <li>jack</li>, <li>tony</li>];
// 2. 把JSX嵌入在UL标签中
const elemet = <ul>{list}</ul>;

使用 map 渲染列表

// 1. 数据
const list = ['tom', 'jack', 'tony'];
// 2. 转jsx数组
const list2 = list.map((item) => <li>{item}</li>);
// 3. 使用
const element = <ul>{list2}</ul>;

直接在 JSX 中使用 map 渲染列表

// 1. 数据
const list = ['tom', 'jack', 'tony'];
// 2. 使用 map调用其实也是js表达式
const element = (
  <ul>
    {list.map((item) => (
      <li>{item}</li>
    ))}
  </ul>
);

key 属性使用

// Warning: Each child in a list should have a unique "key" prop.
// 1. 数据
const list = ['tom', 'jack', 'tony'];
// 2. 使用
const element = (
  <ul>
    {list.map((item) => (
      <li key={item}>{item}</li>
    ))}
  </ul>
);

JSX 样式 - style 方式

  • style 接受一个采用小驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串
  • style 中的 key 采用小驼峰命名是为了与 JS 访问 DOM 节点的属性保持一致
  • React 会自动添加 ”px” 后缀到内联样式为数字的属性后,其他单位需要手动添加

演示代码

  • 需求:去掉上一个列表案例 ul 的点,加上背景样式,设置字体大小,给第一个 p 设置两倍字体大小
import ReactDom from 'react-dom'

// 1. 数据
const list = [
  { id: 100, name: 'tom', age: 15 },
  { id: 101, name: 'jack', age: 18 },
  { id: 102, name: 'tony', age: 20 }
]

+// 2. 样式
+const styleObject = {
+  listStyle: 'none',
+  backgroundColor: 'pink',
+  fontSize: 20
+}

// 3. 使用
const element = (
+  <ul style={styleObject} >
    {list.map(item => {
      return (
        <li key={item.id}>
+          <p style={{fontSize: '2em'}}>姓名:{item.name}</p>
          <p>是否成年:{item.age > 16 ? '是' : '否'}</p>
        </li>
      )
    })}
  </ul>
)

ReactDom.render(element, document.getElementById('root'))

JSX 样式 - className 方式

在多数情况下,应使用 className 属性来引用外部 CSS 样式表中定义的 class

  • className 设置类名,和 class 属性要求一样只能是字符串
  • 如果需要根据数据设置类名,可以使用 { } 嵌入 JS 表达式实现

演示代码:

  • 需求:在元素 button上根据 isActive 数据的值添加 active 类名

index.css 代码

.button {
  width: 100px;
  height: 40px;
  border: 1px solid #eee;
  color: #999;
  border-radius: 4px;
  display: inline-block;
  text-align: center;
  line-height: 40px;
  box-shadow: 2px 2px 10px #ccc;
  cursor: pointer;
  user-select: none;
}

.button.active {
  background: #069;
  color: #fff;
  border-color: #069;
}

.button.block {
  display: block;
  width: 100%;
}

index.js 代码

import ReactDom from 'react-dom';
// 在src下新建index.css文件,导入进来即可
import './index.css';

const isActive = false;

const element = (
  <span className={`button ${isActive ? 'active' : ''}`}>按钮</span>
);

ReactDom.render(element, document.getElementById('root'));

JSX 样式 - 动态 className

  • 在使用 className 的时候遇见多个类名动态绑定,可以模仿 vue 使用对象的方式
  • vue 中绑定类名的时候使用 {类名:布尔} 用布尔值决定是否加上这个类名

例如:在元素 button上根据 isActive 数据的值添加 active 类名,isBlock 数据的值添加 block 类名

import ReactDom from 'react-dom';
import './index.css';

// 数据
const isActive = false;
const isBlock = false;

// 类名对象
const classObject = {
  button: true,
  active: isActive,
  block: isBlock,
};

// 转换成字符串
const className = Object.keys(classObject)
  .filter((key) => classObject[key])
  .join(' ');

const element = <span className={className}>按钮</span>;

ReactDom.render(element, document.getElementById('root'));

JSX 样式 - classnames 库

使用 JS 原生的能力处理多个类名的动态绑定,当然这样的需求已经有 classnames 库给我们解决了。

安装导入 classnames

# 安装
npm i classnames
# 或者 
yarn add classnames
// 导入
import classNames from 'classnames'

认识 classnames API

// 1. 使用字符串
classNames('foo', 'bar'); // foo bar
// 2. 使用对象
classNames({ foo: true, bar: true }); // foo bar
// 3. 使用数组
classNames(['foo', 'bar']); // foo bar
// 4. 混合使用
classNames('foo', { bar: true }); // foo bar

例如还是上面那个需求:在元素 button上根据 isActive 数据的值添加 active 类名,isBlock 数据的值添加 block 类名

import ReactDom from 'react-dom';
// 1. 导入classnames
import classNames from 'classnames';
import './index.css';

// 2. 数据
const isActive = true;
const isBlock = true;

// 3. 产生类名
const className = classNames('button', {
  active: isActive,
  block: isBlock,
});

const element = <span className={className}>按钮</span>;

ReactDom.render(element, document.getElementById('root'));

欢迎留言