在 Vue 项目中,你可以通过以下步骤在 .js 文件中使用 JSX:
1. 配置 Babel 支持 JSX
首先需要确保你的项目配置支持 JSX 转换:
安装必要依赖
npm install @vue/babel-plugin-jsx -D
yarn add @vue/babel-plugin-jsx -D
配置 babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
'@vue/babel-plugin-jsx'
]
}
2. 在 JS 文件中使用 JSX 的基本语法
// HelloWorld.js
import { defineComponent } from 'vue'
export default defineComponent({
name: 'HelloWorld',
props: {
msg: String
},
setup(props) {
return () => (
<div class="hello">
<h1>{props.msg}</h1>
<button onClick={() => console.log('clicked')}>Click me</button>
</div>
)
}
})
3. JSX 与模板语法的对比
模板语法 JSX 语法
<template> 标签 直接在 JS 中写 JSX
v-if {condition && <div/>}
v-for {items.map(item => <div key={item.id}>{item.name}</div>)}
v-bind 或 : 直接使用属性 name={value}
v-on 或 @ onClick={handler}
v-model value={state} onChange={handler}
- 实际使用示例
带状态的组件
// Counter.js
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
const increment = () => {
count.value++
}
return () => (
<div>
<p>Count: {count.value}</p>
<button onClick={increment}>Increment</button>
</div>
)
}
})
带子组件的示例
// ParentComponent.js
import { defineComponent } from 'vue'
import ChildComponent from './ChildComponent'
export default defineComponent({
setup() {
const items = ['Apple', 'Banana', 'Orange']
return () => (
<div>
<h1>Fruit List</h1>
<ul>
{items.map(item => (
<ChildComponent item={item} key={item} />
))}
</ul>
</div>
)
}
})
- 注意事项
文件扩展名:虽然可以在 .js 文件中使用 JSX,但推荐使用 .jsx 扩展名以便区分
Vue 指令:在 JSX 中不能直接使用 Vue 指令,需要转换为 JSX 等价形式
样式处理:
// 使用对象语法
<div style={{ color: 'red', fontSize: '14px' }}></div>
// 使用 class
<div class={['foo', { active: isActive }]}></div>
插槽:
// 默认插槽
<Child>{() => '默认插槽内容'}</Child>
// 具名插槽
<Child>
{{
default: () => '默认内容',
header: () => <h1>标题</h1>
}}
</Child>
- 与 TypeScript 结合
如果你使用 TypeScript,可以创建 .tsx 文件:
// Hello.tsx
import { defineComponent, PropType } from 'vue'
interface User {
name: string
age: number
}
export default defineComponent({
props: {
user: {
type: Object as PropType<User>,
required: true
}
},
setup(props) {
return () => (
<div>
<p>Name: {props.user.name}</p>
<p>Age: {props.user.age}</p>
</div>
)
}
})
通过以上配置和示例,你就可以在 Vue 项目的 JavaScript 文件中自由使用 JSX 语法了。
或者不使用sertup
在 Vue 组件中直接使用 render 函数(不使用 setup)
在 Vue 中,你可以直接在组件选项中定义 render 函数,而不需要使用 setup 函数。这种方式在 Vue 2 和 Vue 3 中都适用,是更传统的写法。
基本语法
import { h } from 'vue'
export default {
props: ['message'],
render() {
return h('div', this.message)
}
}
完整示例
- 简单组件
// SimpleComponent.js
import { h } from 'vue'
export default {
name: 'SimpleComponent',
props: {
title: String,
count: Number
},
render() {
return h('div', [
h('h1', this.title),
h('p', `Count: ${this.count}`),
h('button', {
onClick: () => this.$emit('increment')
}, 'Add')
])
}
}
- 带状态的组件
// Counter.js
import { h } from 'vue'
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
render() {
return h('div', [
h('p', `Current count: ${this.count}`),
h('button', {
onClick: this.increment
}, 'Increment')
])
}
}
JSX 版本
如果你配置了 JSX 支持(如前所述),可以这样写:
// JsxComponent.js
export default {
props: ['items'],
render() {
return (
<ul>
{this.items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)
}
}
与传统模板的比较
模板语法 Render 函数等效
v-if="condition" condition ? h('div') : null
v-for="item in items" items.map(item => h('div', item))
v-bind:id="id" { id: this.id }
@click="handleClick" { onClick: this.handleClick }
v-model="value" 需要手动实现(见下方示例)
实现 v-model
// InputComponent.js
import { h } from 'vue'
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
render() {
return h('input', {
value: this.modelValue,
onInput: (e) => {
this.$emit('update:modelValue', e.target.value)
}
})
}
}
插槽处理
// LayoutComponent.js
import { h } from 'vue'
export default {
render() {
return h('div', [
h('header', this.$slots.header()),
h('main', this.$slots.default()),
h('footer', this.$slots.footer())
])
}
}
作用域插槽
// ScopedSlotComponent.js
import { h } from 'vue'
export default {
data() {
return {
user: {
name: 'John',
age: 30
}
}
},
render() {
return h('div', [
this.$slots.default({
user: this.user
})
])
}
}