写在最前:本文转自掘金
首先得安装 vite 插件 @vitejs/plugin-vue-jsx 以支持 jsx 文件开发
$ pnpm i @vitejs/plugin-vue-jsx
文件类型声明
// vite-env.d.ts
declare module '*.tsx'
1. 文本插值
vue 里文本插值默认使用双大括号:
<h1>{{ msg }}</h1>
在 JSX 变成了单大括号
const name = "Vue"
const element = <h1>hello, { msg }</h1>
且打括号内支持有效的 JavaScript表达式,例如:2+2
,user.firstName
,formateName(user)
等。
2. 条件渲染
使用 if/else
let hasDetail = true;
const element = (hasDetail:boolean)=> {
if(hasDetail){
return (
<div class={'wrap'}>
<p>标题</p>
<p>内容</p>
</div>
)
}else{
return <p>内容丢失</p>
}
}
return () => (
<div class={'content'}>
<p>使用 if/else</p>
{element(hasDetail)}
</div>
)
这种方式类似v-if
,但是和v-if
还是有点区别,v-if
可以作用在更小的范围,而这种方式只适合整个组件的条件渲染,形似下例子:
return () => {
if (name) {
return <h1>Hello, { name }</h1>
} else {
return <h1>Hello, Stranger</h1>
}
}
若想渲染更小的范围可以采用第一种方式,提取节点赋值于函数变量。
使用三目运算
return () => (
{ hasDetail ? <span>1</span> : <span>2</span> }
)
3. 列表渲染
列表渲染直接使用js数组的map方法即可
const data = [{
id: 1,
title: '通用'
}, {
id: 2,
title: '导航'
}]
return () => (
<div class={styles.content}>
<p class={[styles.title,styles.active]}>渲染列表</p>
{
data.map((item,idx)=> <div key={item.id}>{item.title}</div>)
}
</div>
)
4. 标签属性绑定
属性绑定也是使用大括号包裹
let url = "http://www.xiaojiayun.top"
return () => (
<div class={styles.content}>
<p class={[styles.title,styles.active]}>标签数据绑定</p>
<a href={url} target="_blank">JiaYUN</a>
</div>
)
如果是需要绑定多个属性,可以使用 ...
操作符
const properties = {a: 1, b: 2}
<div {...properties}></div>
5. class类名绑定
直接使用JS模板字符串即可。
return () => (
<div class={`devui-accordion-item-title ${ disabled ? 'disabled' : '' }`}>Item</div>
)
复制代码
也可以使用数组:
return () => (
<div class={['accordion', disabled && 'disabled']}>Item</div>
)
这里需要注意是 ,在jsx中直接赋值类名并不会解决类名冲突问题,有两种办法可以解决,一种就是在命名class时保证其唯一性,第二种是通过 css module,具体来讲就是把css 作为模块引入js中,然后会生成唯一的名称,只需在 vit.config.ts 中配置一下即可。
css: {
modules:{
localsConvention:'camelCase'
}
}
这里规定css类名的命名规则为小驼峰,即child-item类在js中会变成childItem变量。但是要实现css module的功能,对css文件命名由要求,必须在后缀名前面是module,例如xxx.module.css、xxx.module.less、xxx.module.scss。
在tsx文件中引用
import styles from "./objectManage.module.scss"
let element = <p class={[styles.title,styles.active]}>标签数据绑定</p>
6. style 样式绑定
样式绑定需要使用双大括号。
const width = '100px'
const element = <button style={{ width, fontSize: '16px' }}></button>
7. 事件绑定
绑定事件也是用大括号,注意事件名前面要加上on
前缀,比如click
事件要写成onClick
,mouseenter
事件要写成onMouseenter
。
const confirm = () => {
// 确认提交
}
<button onClick={confirm}>确定</button>
复制代码
如果要带参数,需要使用箭头函数进行包裹:
const confirm = (name) => {
// 确认提交
}
<button onClick={() => confirm('test')}>确定</button>
8. 事件修饰符
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, ['self']) }>{ count.value }</div>
);
},
})
注意:Vue模板中ref变量是可以直接解构的,但是在jsx中不行,需要记得添加.value
,比如上面的{ count.value }
。
9. v-model 双向绑定
绑定 modelValue
<el-input v-model={ name.value }></el-inpu>
绑定自定义名称
比如绑定visible
,JSX中不能直接用v-model:visible
的语法,需要传入一个数组[menuShow.value, 'visible']
,数组的第二个参数就是要绑定的自定义名称。
<d-flexible-overlay v-model={[menuShow.value, 'visible']}></d-flexible-overlay>
10. slot 插槽
jsx中没有<slot>
标签,定义插槽需要使用双大括号。
如果是具名插槽,则将 default
改成具名插槽的名称。
作用域插槽则在函数里传入要传给插槽的参数。
// child.tsx
import { defineComponent } from 'vue'
export default defineComponent({
setup(props, { slots }) { // 逻辑
return () => (
<div>
<p>这里是插槽</p>
<p>这个是默认插槽内容:{slots.default?.()}</p>
<p>这个是具名插槽内容:{slots.mySlot?.()}</p>
<p>这个是作用域插槽:{slots.main?.({row:'我才是最主要的'})}</p>
</div>
)
},
})
在父组件中使用
使用 v-slots
指令使用插槽传参
import Child from './child.tsx'
export default defineComponent({
components:{ Child },
setup() {
return () => {
<Child v-slots={{
default:()=>'默认插槽内容',
mySlot:()=>'有名插槽',
main:(props:Record<'row',string>)=>props.row
}}></Child >
}
}
})