目录
2、defineComponent() render的方式 Options API
3、defineComponent() setup的方式 Composition API
一、使用
1、安装插件
pnpm install @vitejs/plugin-vue-jsx -D
或 yarn add @vitejs/plugin-vue-jsx -D
2、在vite.config.ts中引入
并在vue()后面添加上,所需的配置项 vueJsx,无配置就可以直接写为vueJsx()
vueJsx({
// options are passed on to @vue/babel-plugin-jsx
// 选项配置也是通过babel去设置的
}),
二、声明tsx组件的三种方式
1、函数式组件
// 缺点:一些复杂的配置项无法设置
export default () => <div>TestTsx</div>;
2、defineComponent() render的方式 Options API
export default defineComponent({
// 其他配置,data/props...
// 缺点:还要跟this打交道,访问变量需要用this.xxx
render() {
return <div>TestTsx</div>;
},
});
3、defineComponent() setup的方式 Composition API
// defineComponent() setup Composition API
export default defineComponent({
// 其他配置,data/props...
setup() {
return () => <div>TestTsx1</div>;
},
});
三、使用tsx的语法
语法1(只允许一个根节点)
vue3中允许多个根节点同时存在,tsx不允许,我们可以设置一个<></>空标签来包裹
语法2(v-model、v-show)
v-model,v-show跟以前的用法类似,但注意后面不是双引号“”,而是大括号{}
注意:v-model里面绑定变量需要加上 .value ,这也是与vue3的区别
export default defineComponent({
// 其他配置,data/props...
setup() {
const counter = ref(0);
return () => (
<>
<div>TestTsx1</div>
<input type="text" v-model={counter.value} />
</>
);
},
});
语法3(v-if 无效,找替代)
需要用三目运算或&&来代替
<div>{isflag ? <span>A</span> : <span>B</span>}</div>
isActive && <p>123</p> //isActive === true的情况下,展示 && 后面的标签
isActive && title==='123' && <p>123</p>
//isActive === true && title==='123' 的情况下,展示 && 最后面的标签
语法4:v-for 使用map代替
<div>
{arr.value.map((item, i) => (
<p key={i}>
{item}--{i}
</p>
))}
</div>
运行结果:
语法5:插槽
jsx 中想实现vue中的插槽写法也有很大不同,主要利用 v-slots 的指令来实现:
插槽的三种接收方式:
child.tsx
export default defineComponent({
// 利用setup的第二个参数,可以接收插槽信息
setup(props, { slots }) {
return () => (
<>
默认插槽:{slots.default && slots.default()}
<br />
具名插槽:
{slots.title && slots.title()}
{slots.content && slots.content()}
<br />
作用域插槽:{slots.suffix && slots.suffix({ name: "作用域插槽内容" })}
<br />
</>
);
},
});
parent.tsx
import Child from "./tchild";
export default defineComponent({
setup() {
return () => (
<>
<Child
v-slots={{
title: () => <h2>我是标题</h2>, //具名插槽
content: () => <h3>我是内容</h3>, //具名插槽
suffix: (props: { name: string }) => <span>{props.name}</span>, //作用域插槽
}}
>
我是默认插槽内容
</Child>
</>
);
},
});
效果:
疑问来了,那我不用 v-slots 其实也可以实现,为啥还要用。只是用v-slots显得比较正规好理解~
<Child>
{{
default: "我是默认插槽的内容",
title: () => <h2>我是标题</h2>,
content: () => <h3>我是内容</h3>,
suffix: (props: { name: string }) => <span>{props.name}</span>,
}}
</Child>
语法6:事件绑定 on+事件名
(小驼峰命名法)进行事件绑定
export default defineComponent({
emits: ["submit"],
setup() {
const handleClick = () => {
alert("我被点击了");
};
return (props, { emit }) => (
<>
<buttion onClick={handleClick}>按钮</buttion>
</>
);
},
});
语法7:通过props向子组件传参
parent.tsx
看下面的例子,可以传递标签给子组件
import Child from "./tchild";
export default defineComponent({
setup() {
const msg = "我是来自父组件的消息";
return () => (
<>
<Child msg={msg} childs={[<h3>我是一</h3>, <h3>我是二</h3>]}></Child>
</>
);
},
});
child.tsx
export default defineComponent({
props: {
msg: String,
childs: Array,
},
// 利用setup的第二个参数,可以接收插槽信息
setup(props, { slots }) {
console.log(props);
return () => (
<>
<p>{props.msg}</p>
<p>{props.childs[0]}</p>
</>
);
},
});
语法8:emit 事件派发
vue中子向父传值都是emit的方式,这个在vue3中写法相似,只是多了一个定义emit的步骤,这也是为了后续的类型推导做准备
parent.tsx
注意:父组件接收子组件发射的方法同样需要加上 on
import Child from "./tchild";
export default defineComponent({
setup() {
const msg = "我是来自父组件的消息";
const numClick = (val) => {
alert(val);
};
return () => (
<>
<Child msg={msg} onNumClick={numClick}></Child>
</>
);
},
});
child.tsx
注意:子组件中需要添加 emits: ["numClick"],同vue3类似,vue3中也需要添加defineEmits将事件发射出去
export default defineComponent({
emits: ["numClick"],
props: {
msg: String,
childs: Array,
},
// 利用setup的第二个参数,可以接收插槽信息
setup(props, { emit }) {
const count = ref(1);
const childClick = () => {
emit("numClick", count.value);
};
return () => (
<>
<Button onClick={childClick}>触发父组件事件</Button>
</>
);
},
});
还有一些样式设置及进阶的知识,见下一篇文章哦~