在 Vue 3 中,有两种声明组件的方式
- 常用的Template方式
- TSX (TypeScript + JSX) ,tsx是一种声明组件的灵活方式,特别适合在动态渲染和复杂逻辑场景中。
一、TSX 的特点
- TSX 是 JSX 的扩展,允许使用 TypeScript 的强类型特性。
- 更适合函数式组件和动态 UI。
- 在 Vue 3 中与 defineComponent 搭配使用。
二、安装配置
- 安装依赖
npm install @vitejs/plugin-vue-jsx -D
- 更新 Vite 配置:
编辑 vite.config.ts
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
export default {
plugins: [vue(), vueJsx()],
};
- 更新 TypeScript 配置: 在 tsconfig.json 中启用 JSX 支持:
{
"compilerOptions": {
"jsx": "preserve",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
}
}
三、使用
在目录新建一个xxxxxx.tsx文件
TIPS:tsx不会自动解包,使用ref加
.value
或者unRef(ref对象)
tsx支持 v-model 的使用
import { ref } from 'vue'
let v = ref<string>('')
const renderDom = () => {
return (
<>
<input v-model={v.value} type="text" />
<div>
{v.value}
</div>
</>
)
}
export default renderDom
v-show
import { ref } from 'vue'
let flag = ref(false)
const renderDom = () => {
return (
<>
<div v-show={flag.value}>景天</div>
<div v-show={!flag.value}>雪见</div>
</>
)
}
export default renderDom
v-if是不支持的
所以需要改变风格
import { ref } from 'vue'
let flag = ref(false)
const renderDom = () => {
return (
<>
{
flag.value ? <div>景天</div> : <div>雪见</div>
}
</>
)
}
export default renderDom
v-for也是不支持的
需要使用Map
import { ref } from 'vue'
let arr = [1,2,3,4,5]
const renderDom = () => {
return (
<>
{
arr.map(v=>{
return <div>${v}</div>
})
}
</>
)
}
export default renderDom
v-bind使用
直接赋值就可以
import { ref } from 'vue'
let arr = [1, 2, 3, 4, 5]
const renderDom = () => {
return (
<>
<div data-arr={arr}>1</div>
</>
)
}
export default renderDom
v-on绑定事件
所有的事件都按照react风格来:
- 所有事件有on开头
- 所有事件名称首字母大写
const renderDom = () => {
return (
<>
<button onClick={clickTap}>点击</button>
</>
)
}
const clickTap = () => {
console.log('click');
}
export default renderDom
Props 接受值
import { ref } from 'vue'
type Props = {
title:string
}
const renderDom = (props:Props) => {
return (
<>
<div>{props.title}</div>
<button onClick={clickTap}>点击</button>
</>
)
}
const clickTap = () => {
console.log('click');
}
export default renderDom
Emit派发
type Props = {
title: string
}
const renderDom = (props: Props,content:any) => {
return (
<>
<div>{props.title}</div>
<button onClick={clickTap.bind(this,content)}>点击</button>
</>
)
}
const clickTap = (ctx:any) => {
ctx.emit('on-click',1)
}
Slot
const A = (props, { slots }) => (
<>
<h1>{ slots.default ? slots.default() : 'foo' }</h1>
<h2>{ slots.bar?.() }</h2>
</>
);
const App = {
setup() {
const slots = {
bar: () => <span>B</span>,
};
return () => (
<A v-slots={slots}>
<div>A</div>
</A>
);
},
};
// or
const App = {
setup() {
const slots = {
default: () => <div>A</div>,
bar: () => <span>B</span>,
};
return () => <A v-slots={slots} />;
},
};
// or you can use object slots when `enableObjectSlots` is not false.
const App = {
setup() {
return () => (
<>
<A>
{{
default: () => <div>A</div>,
bar: () => <span>B</span>,
}}
</A>
<B>{() => "foo"}</B>
</>
);
},
};