各位 Vuer,Vue3 现在已经成为默认版本,今天我们来熟悉一下在 Vue3 中如何使用 JSX 的基本语法

文本插值

Vue 中的文本插值默认是使用双大括号:

1
<h1>{{msg}}</h1>

在 JSX 中变成了单大括号:

1
2
const name = 'World'
const element = <h1>Hello, { name }</h1>

和在 Vue 模板语法中的文本插值一样,大括号内支持任何有效的 JavaScript表达式,比如:2 + 2,user.firstName,formatName(user)等。

条件渲染

  1. 使用 if/else

    1
    2
    3
    4
    5
    6
    7
    const element = (name) => {
    if (name) {
    return <h1>Hello, { name }</h1>
    } else {
    return <h1>Hello, Stranger</h1>
    }
    }

    以上代码等效于:

    1
    const element = (name) => <h1>Hello, { name || 'Stranger' }</h1>
  2. 使用三目运算符

    1
    const element = icon ? <span class="icon"></span> : null;

    以上代码等效于:

    1
    const element = icon && <span class="icon"></span>;

列表渲染

列表渲染直接使用 JS 数组的 map 方法即可,不需要使用 v-for指令。

1
2
3
4
5
6
7
8
9
10
11
const data = [{
id: 1,
title: '通用'
}, {
id: 2,
title: '导航'
}]

const element = data.map(item => {
return <div>{ item.title }</div>
})

标签属性绑定

属性绑定也是使用大括号包裹,不需要使用 v-bind 指令。

1
2
3
const href = 'https://xmwpro.com/'

const element = <a href={href}>白雾茫茫丶</a>

class 类名绑定

直接使用 JS 模板字符串即可。

1
const element = <div className={`devui-accordion-item-title ${ disabled ? 'disabled' : '' }`}></div>

也可以使用数组:

1
2
3
4
5
6
7
const element = <div class={
[
'devui-accordion-item-title',
disabled && 'disabled'
]
}
>Item</div>

style 样式绑定

样式绑定需要使用双大括号。

1
2
3
const width = '100px'

const element = <button style={{ width, fontSize: '16px' }}></button>

事件绑定

绑定事件也是用大括号,注意事件名前面要加上 on 前缀,比如 click 事件要写成 onClick,mouseenter 事件要写成 onMouseenter

1
2
3
4
5
const confirm = () => {
// 确认提交
}

<button onClick={confirm}>确定</button>

如果要带参数,需要使用箭头函数进行包裹:

1
2
3
4
5
const confirm = (name) => {
// 确认提交
}

<button onClick={() => confirm('devui')}>确定</button>
  1. 事件修饰符
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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 }。

v-model 双向绑定

  1. 绑定 modelValue
    这种情况比较简单。
    JSX 写法:

    1
    <d-flexible-overlay v-model={ menuShow.value }></d-flexible-overlay>

    SFC 写法:

    1
    <d-flexible-overlay v-model="menuShow"></d-flexible-overlay>
  2. 绑定自定义名称
    比如绑定 visible,JSX 中不能直接用 v-model:visible 的语法,需要传入一个数组 [menuShow.value, ‘visible’],数组的第二个参数就是要绑定的自定义名称。
    JSX 写法:

    1
    <d-flexible-overlay v-model={[menuShow.value, 'visible']}></d-flexible-overlay>

    SFC 写法:

    1
    <d-flexible-overlay v-model:visible="menuShow"></d-flexible-overlay>

slot 插槽

jsx 中没有标签,定义插槽需要使用双大括号。

如果是具名插槽,则将 default 改成具名插槽的名称,比如 mySlot,则使用 ctx.slots.mySlot?.()。

插槽从 setup 的第二个参数 ctx 中获取,不需要加 $ 前缀。

1
2
3
4
5
6
7
8
9
import { defineComponent } from 'vue'

export default defineComponent({
setup(props, { slots }) { // 逻辑
return () => {
return <button>{ slots.default?.() }</button>
}
},
})

还可以使用 renderSlot 方法:

1
2
3
4
5
import { renderSlot } from 'vue'

<button>
{ renderSlot(slots, 'default') }
</button>
  1. Scoped Slots 作用域插槽
    使用作用域插槽可以实现插槽传参,以下是具体的示例。

JSX 和 SFC 中插槽使用的写法对比。

JSX 写法:

1
2
3
4
5
<d-tree data={data}>
{{
mySlot: (item) => (item.open ? <IconOpen /> : <IconClose />),
}}
</d-tree>

还可以通过 v-slots 的方式使用:

1
2
3
4
<d-tree data={data} v-slots={{
mySlot: (item) => (item.open ? <IconOpen /> : <IconClose />)
}}>
</d-tree>

SFC 写法:

1
2
3
4
5
6
<d-tree :data="data">
<template #mySlot="item">
<IconOpen v-if="item.open" />
<IconClose v-else />
</template>
</d-tree>

其中的 item 是插槽的参数,通过

1
ctx.slots.mySlot(item)

的方式给插槽传入参数。
或者使用 renderSlot 方法,第三个参数就是要传给插槽的参数:

1
2
3
4
5
import { renderSlot, useSlots } from 'vue'

<button>
{ renderSlot(useSlots(), 'mySlot', item) }
</button>