一般情况下,我们在template标签里去写静态页面模板。现在可以扩展另一种书写风格 tsx,类似react的jsx语法。vue2 的时候就已经支持jsx写法,只不过不是很友好,随着vue3对typescript的支持度增高,tsx写法越来越被接受。
使用参阅:@vitejs/plugin-vue-jsx
1、安装
npm i @vitejs/plugin-vue-jsx -D
可能会出现插件与vite版本不兼容的问题:
解决办法:添加 --force 参数,强制安装即可。
2、配置vite.config.ts
import vueJsx from '@vitejs/plugin-vue-jsx';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vueJsx()]
})
3、 配置tsconfig.json
添加以下信息在compilerOptions配置项中:
"jsx": "preserve",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment",
这样就可以编写tsx文件了。
4、新建xxx.tsx测试
第一种编写方式,内容如下;
export default function() {
return (<div>hello world!</div>)
}
像引入组件一样,在App.vue中 import,使用:
import AppTsx from './App' // 后缀可省略
...
<AppTsx></AppTsx>
显示结果:
5、使用defineComponent编写tsx
第二种编写方式,该语法类似react的class component书写方式,属于Optional API。
import { defineComponent } from 'vue'
export default defineComponent({
data () {
return {
name: "Tom",
age: 23
}
},
render () {
return (<div>{ this.name } is { this.age } years old. </div>)
}
})
注意:在render函数中使用data函数定义的变量时,用的是单花括号‘{ xxx }’进行渲染。
页面效果:
6、setup函数模式编写tsx
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return () => (<div>Setup!</div>)
}
})
7、指令使用变化
支持使用v-show的指令:
setup () {
const flag = false
return () => (<div v-show={flag}>Setup!</div>)
}
Setup!字样是正常隐藏了的。但如果给变量flag使用ref包装一下,v-show就失效了?如下:
这是因为在ts里{xx},对于响应式数据的解析不能自动.value拆包,需要手动写上.value。
不支持v-if指令:
解决:采取另一种编程思想(如js的三元表达式):
个人感觉这种结构读性较差。
不支持v-for指令:
采用数组遍历方式渲染,map()代替v-for:
v-bind 可以用 '{}' 替代:
8、Props接收值
// App.tsc 定义接口类型
type Props = {
title?:string
}
export default defineComponent({
props: {
title:String
},
// setup接收props参数
setup(props:Props) {
return () => (
<>
<div> Props: { props?.title }</div>
<hr />
</>
);
}
});
......
// App.vue 传值
<AppTsx title="我是标题"></AppTsx>
结果:
9、emit派发事件
...
const fun = () => {
console.log('click!');
}
return () => (
<>
{/* <div onClick={fun()}> Props: { props?.title }</div> */}
<div onClick={() => fun()}> Props: { props?.title }</div>
<hr />
</>
);
...
不是以@开头的事件书写,注意{xx}不能直接调用函数,它会自动执行,需要改写为回调函数形式:onClick={() => xxx()}。
传参:
const fun = (num:number) => {
console.log('click!', '参数: ', num);
}
...
<div onClick={() => fun(666)}> Props: { props?.title }</div>
...
触发父组件事件:
setup(props:Props, { emit }) {
...
}
...
const fun = (num:number) => {
console.log('click!', '参数: ', num);
emit('on-click', num)
}
// App.vue
const getNum = (num:number) => {
console.log('父组件接收emit: ', num);
}
...
<AppTsx @on-click="getNum" title="我是标题"></AppTsx>
...
10、插槽slots
// 定义一个子组件
const A = (_, { slots }) => (
<>
<h1>{ slots.default ? slots.default() : '默认插槽' }</h1>
<h2>{ slots.foo?.() }</h2>
</>
);
...
setup(props:Props, { emit }) {
const slot = {
default: () => (<div>hello - default slots</div>),
foo: () => (<div>world - foo slots</div>),
}
return () => (
<>
<A v-slots={slot}></A>
<hr />
</>
);
}
});
...
11、表单双向数据绑定
支持v-model指令:
const v = ref<string>('')
...
return () => (
<>
<input v-model={v.value} type="text" />
<div>{ v.value }</div>
</>
);
...
参考: https://xiaoman.blog.csdn.net/article/details/123172735