如果你需要将大量 HTML 代码移植到 JSX 语法,可以使用 一款在线的免费的代码转换器工具。
JSX 最早是由 facebook 起草的一个规范。
JSX 是 JavaScript 的语法扩展,可让您在 JavaScript 文件中编写类似 HTML 的标记。JSX 是一种嵌入式的类似 XML 的语法。
JSX 并没有扩展 JS 的语法,他只是缩略了 JS 的写法,其本质就是 JS 的语法糖。
JSX 语法:
等等。
- 添加自定义属性遵循 HTML5 的规则,需要使用
data-
前缀开头作为属性名并赋值。
- JSX 比 HTML 更严格一些,JSX 要求标签被显式关闭。例如:
必须写成的自关闭标签
。
- JSX 文件的类型:
- 使用 JSX 语法的文件必须以
.jsx
作为文件的后缀名。
- 如果用到了 TypeScript 则必须用
.tsx
作为文件的后缀名。
- JSX 的代码注释:
- JSX 的代码注释需要写在花括号
{}
中。
- JSX 与 JavaScript 表达式:
- 在 JSX 中可以使用 JavaScript 表达式,表达式需要写在花括号
{}
中。
- 在 JSX 中可以使用 三元运算(
? :
) 表达式来实现按条件加载的逻辑。
- JSX 允许在模板中插入数组,数组会自动展开所有成员。
- JSX 特定属性:(二选一)
- 可以指定为字符串字面量——属性值加上引号;
- 也可以在属性值中使用大括号插入一个 JavaScript 表达式。
1、JSX 代码注释
JSX 的注释代码需要写在花括号 {}
中:
const content = (
{/*注释...*/}
<h1>hello world</h1>
);
2、JSX 赋予数组的特性
JSX 允许在模板中插入数组,数组会自动展开所有成员
var arr = [
<h1>123</h1>,
<h2>321</h2>,
];
const content = (
<div>{arr}</div>
);
3、JSX 属性的特性
你可以通过使用引号,来将属性值指定为字符串字面量:
<script type="text/babel">
const element = <div tabIndex="0"></div>;
</script>
也可以使用大括号,来在属性值中插入一个 JavaScript 表达式:
<script type="text/babel">
const element = <img src={user.avatarUrl}></img>;
</script>
【注意】在对于同一属性不能同时使用这两种符号。
二、TSX
TS 的 JSX
想要使用 JSX 必须做两件事:
- 给文件一个 .tsx 扩展名
- 启用 jsx 选项
1、TypeScript 的 3 种 JSX 模式
TypeScript具有三种JSX模式:preserve、react 和 react-native。
你可以通过在命令行里使用--jsx
标记或tsconfig.json
里的选项来指定模式。
模式
输入
输出
输出文件扩展名
preserve
.jsx
react
React.createElement(“div”)
.js
react-native
.js
这些模式只在代码生成阶段起作用,类型检查并不受影响。
- 在preserve模式下生成代码中会保留JSX以供后续的转换操作使用(比如:Babel)。 另外,输出文件会带有.jsx扩展名。
- react模式会生成React.createElement,在使用前不需要再进行转换操作了,输出文件的扩展名为.js。
- react-native相当于preserve,它也保留了所有的JSX,但是输出文件的扩展名是.js。
2、只能使用 as 操作符做类型断言
在 TSX 中只能使用 as 操作符来实现 类型断言,不能使用尖括号(<>),这两者是等价的。
const foo = bar as foo;// ✅正确
const foo = <foo>bar;// ❌错误
三、React 中使用 JSX
React 的 JSX 简介
JSX 和 React 是相互独立的,React 开发不一定使用 JSX ,但我们建议使用它。在 React 中使用 JSX,是一种非常棒的体验。
在 React 中使用 JSX 的注意事项:
- React DOM 使用
className
属性替换 HTML 的 class 属性,使用 htmlFor
属性替换 HTML 的 for 属性。
1、React 中 JSX 的渲染
在 React 中 Babel 插件会把 JSX 转译成一个名为 React.createElement()
函数调用。
以下两种示例代码完全等效:
<script type="text/babel">
const element = (
<h1 className="greeting">Hello, world!</h1>
);
</script>
// 等价于
<script>
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
</script>
React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 注意:这是简化过的结构
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
2、React 中 JSX 可以防止 XSS 注入攻击
你可以安全地在 JSX 当中插入用户输入内容:
const title = response.potentiallyMaliciousInput;
// 直接使用是安全的:
const element = <h1>{title}</h1>;
React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。
四、Vue 中使用 JSX
渲染函数 & JSX
为什么我推荐使用JSX开发Vue3
0、Vue 中 SFC 与 JSX 模式的对比
SFC 模式:
<template>
<span>{{text}}span>
template>
<script setup lang="tsx">
import { ref } from 'vue'
const props = {}
const emits = []
const directives = {}
const text = ref('示例')
script>
<style>
.sapn{ color: red }
style>
JSX 模式:
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'SelfComponent',
props: {},
emits: [],
directives: {},
setup() {
const text = ref('示例')
return { text }
},
render() {
return (
<div>{this.text}</div>
)
}
})
其实,jsx 的 render 函数是可以省略的,因为 setup 默认会返回一个 render 方法来渲染 jsx,所以你也可以这样写:
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'SelfComponent',
props: {},
emits: [],
directives: {},
setup(props, ctx) {
const text = ref('示例')
return () => (
<span>{text.value}</span>
)
}
})
【注意】若在 setup 直接渲染 html 标签或组件,在使用 ref 定义的变量时需要带上 .value
关键字。
1、文本插值
Vue 里面文本插值默认是用双大括号:
<h1>{{ msg }}h1>
在JSX中变成了单大括号:
const name = '标题'
const element = <h1>Hello, { name }</h1>
与 template 模板语法中的文本插值一样,大括号内支持任何有效的 JavaScript 表达式。
2、条件渲染
在 JSX 中使用“if/else”、“逻辑运算符”、“三目运算符”来取代 v-if 指令来做条件渲染。因为 jsx 本身就是一个条件表达式,不需要 v-if 了。但是 JSX 支持 v-show 指令的使用。
(1)、JSX 中使用 v-show 指令
SFC写法:
<div v-show="isShow">div>
JSX写法:
<div v-show={isShow}>div>
(2)、使用 if/else
const element = (name) => {
if (name) {
return <h1>Hello, { name }</h1>
} else {
return <h1>Hello, Stranger</h1>
}
}
(3)、使用逻辑运算符
js 的逻辑运算符包括:
||
(或)
&&
(与)
!
(非)
??
(空值合并运算符)
const element = icon && <span class="icon"></span>;
(4)、使用三目运算符
三目运算符:条件 ? A : B
(满足条件值取A,否则值取B)。
const element = icon ? <span class="icon"></span> : null;
3、列表渲染
在 JSX 中使用 JS 数组的 map 方法取代 v-for 指令做列表渲染。
const data = [{
id: 1,
title: 'qqqq'
}, {
id: 2,
title: 'wwww'
}]
const element = data.map(item => {
return <div>{ item.title }</div>
})
4、标签的动态属性绑定
标签的动态属性绑定用“大括号包裹”即可,无需用 v-bind 指令。
const href = 'https://www.baidu.com/'
const element = <a href={href}>baidu</a>
5、class 类名绑定
直接使用 JS 模板字符串即可。
const element = <div className={`self-accordion-item-title ${ disabled ? 'disabled' : '' }`}></div>
也可以使用数组:
const element = <div class={
[
'self-accordion-item-title',
disabled && 'disabled'
]
}
>Item</div>
6、style 样式绑定
样式绑定需要用双大括号。
const width = '100px'
const element = <button style={{ width, fontSize: '16px' }}></button>
7、事件绑定
绑定事件也是用大括号。
事件名前要加 on 前缀,比如:click 事件要写成 onClick。
const confirm = () => {
// 确认提交
}
<button onClick={confirm}>确定</button>
如果要带参数,需要使用箭头函数进行包裹:
const confirm = (name) => {
// 确认提交
}
<button onClick={() => confirm('123')}>确定</button>
(1)、事件修饰符
jsx 中给事件增加修饰符需要借助 withModifiers 方法。
import { withModifiers, defineComponent, ref } from 'vue'
const App = defineComponent({
setup() {
const count = ref(0);
const inc = () => {
count.value++;
};
return () => (
<div onClick={ withModifiers(inc, ['stop']) }>{ count.value }</div>
);
},
})
8、v-model 双向绑定
需要使用大括号。
(1)、使用 v-model 指令绑定 modelValue
SFC写法:
<SelfComponent v-model="menuShow" />
JSX写法:
<SelfComponent v-model={ menuShow.value } />
(2)、绑定自定义名称
比如绑定 visible,JSX 中不能直接用 v-model:visible 的语法,需要传入一个数组 [menuShow.value, ‘visible’],数组的第二个参数就是要绑定的自定义名称。
SFC写法:
<SelfComponent v-model:visible="menuShow" />
JSX写法:
<SelfComponent v-model={ [menuShow.value, 'visible'] } />
9、slot 插槽
jsx 中没有 标签,定义插槽需要使用双大括号。
如果是具名插槽,则将 default 改成具名插槽的名称,比如:mySlot,则使用 ctx.slots.mySlot?.()。
插槽从 setup 的第二个参数 ctx 中获取,不需要在其前面加 $ 符号。
import { defineComponent } from 'vue'
export default defineComponent({
setup(props, { slots }) { // 逻辑
return () => {
return <button>{ slots.default?.() }</button>
}
},
})
还可以使用renderSlot方法:
import { renderSlot } from 'vue'
<button>
{ renderSlot(slots, 'default') }
</button>
(1)、Scoped Slots 作用域插槽
使用作用域插槽可以实现插槽传参,以下是具体的示例。
JSX和SFC中插槽使用的写法对比。
JSX写法:
<self-tree data={data}>
{{
mySlot: (item) => (item.open ? <IconOpen /> : <IconClose />),
}}
self-tree>
还可以通过 v-slots 的方式使用:
(item.open ? <IconOpen /> : <IconClose />)
}}>
self-tree>
SFC写法:
<self-tree :data="data">
<template #mySlot="item">
<IconOpen v-if="item.open" />
<IconClose v-else />
template>
self-tree>
其中的item是插槽的参数,通过:ctx.slots.mySlot(item) 的方式给插槽传入参数。或者使用 renderSlot 方法,第三个参数就是要传给插槽的参数:
import { renderSlot, useSlots } from 'vue'
<button>
{ renderSlot(useSlots(), 'mySlot', item) }
</button>
10、在 JSX 中使用 h() 函数创建 Vnodes
在 JSX 中 h() 函数可以大展身手。
vue 用 h() 函数创建 Vnodes
【参考推荐文章】
TS 的 JSX
React 的 JSX 简介
Vue 渲染函数 & JSX
为什么我推荐使用JSX开发Vue3
Vue3中使用JSX简明语法