1. 什么是 JSX
JSX是Facebook工程团队创造的JS的类似 XML 的语法糖,不是由引擎或浏览器实现,而是使用Babel之类的转置器将JSX转换成常规的JS,允许在JS中使用类似Html的语法。
2. JSX 用在Vue中
<template>
<div>
<p>{{ countRef }}</p>
</div>
</template>
<script>
import {ref} from 'vue'
export default {
setup (){ // Vue 3新的API setup 可以定义响应式数据
const countRef = ref(1)
return {
countRef
}
}
}
</script>
- 上例是用vue文件的模版写法,再来看一段另一种用render函数的写法:
// Demo2
<script>
import {ref} from 'vue'
export default {
setup (){ // Vue 3新的API setup 可以定义响应式数据
const countRef = ref(1)
const render = () => {
return <div>Hello {countRef.value} </div>
}
return render
}
}
</script>
<template>
<div id="app">
<Demo2 />
</div>
</template>
<script>
import Demo2 from 'xx/Demo2.vue'
export default {
components:{
Demo2
}
}
</style>
以上的例子还可以用 JSX 文件的写法:
// 子组件
import { defineComponent, ref} from 'vue'
export default defineComponent({
setup (props){
const render = () => {
return <div> Child </div>
}
return render
}
)}
import { defineComponent, ref} from 'vue'
import Child from './Child'
export default defineComponent({
// 一种是 传函数 的写法
const countRef = ref(1)
const render = () => {
return <div>Hello {countRef.value} </div>
}
return render
// 另一种是 传对象 的写法 可以接受更多的参数
props:{
name:{
type:String,
}
},
setup (props){
const countRef = ref(1)
const render = () => {
return (
<div>
Hello {props.name} {countRef.value}
<Child /> // 使用子组件
</div>
)
}
return render
}
})
<template>
<div id="app">
<Demo3 name="JIANLONG"/>
</div>
</template>
<script>
import Demo2 from 'xx/Demo2.vue'
export default {
components:{
Demo2
}
}
</style>
3. 为什么要用 JSX
构建一个<TextField />
组件,可以是普通的单行文本输入或多行输入(文本区域),假如绑定的信息有很多:
- 传统的模板写法:
<div>
<textarea v-if="multiline" v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false">
<input v-else v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false">
</div>
- JSX 写法:
render (createElement) {
const inputAttributes = {
class: 'input-field has-outline', // class definition
onClick: this.handleClick // event handler
backdrop: false // custom prop
}
const inputMarkup = this.multiline
? <textarea {...inputAttributes}></textarea>
: <input {...inputAttributes}/>
return inputMarkup
}
- 配置插件,让vue支持jsx
(@vitejs/plugin-vue-jsx
和[@vue/babel-plugin-jsx]
插件)
pnpm i -D @vitejs/plugin-vue-jsx@1.3.9
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
export default defineConfig({
plugins: [
vue(),
vueJsx({
transformOn:true,
mergeProps:true
})
]
})
4. template
对比 TSX
- template
<script setup lang="ts">
// 加setup后 声明的所有变量或函数可自动在template中使用
import { ref } from "vue";
const count = ref(0);
const onClick = () => {
count.value += 1;
};
</script>
<template>
<div>
{{ count }}
</div>
<div>
<button @click="onClick">+1</button>
</div>
</template>
- TSX
import { defineComponent, ref } from "vue";
export const App = defineComponent({
setup() {
const refCount = ref(0)
const onClick = ()=>{
refCount.value += 1 // react 不能实现
}
return () => <>
<div>
{refCount.value}
</div>
<div>
<button onClick={onClick}>+1</button>
</div>
</>
}
})
- 上例中的
<>
写法,类似于react的Fragment
组件,代替div作为外层不可见的包裹元素 - 命名时注意用onClick 类似于react的方法
- 引用
ref
的变量命名时注意加refCount
- 上面的写法,既可以使用到vue的数据响应式,又可以使用到
react
的丰富JSX
语法