vue使用tsx
Cannot find module ‘./index.module.scss‘ or its corresponding type declarations.ts
项目创建 typed-css.d.ts 文件
ts
declare module '*.module.css' {
const classes: { readonly [key: string]: string }
export default classes
}
declare module '*.module.sass' {
const classes: { readonly [key: string]: string }
export default classes
}
declare module '*.module.scss' {
const classes: { readonly [key: string]: string }
export default classes
}
将其配置到tsconfig.json
json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Node",
"target": "ESNext",
"jsx": "preserve", //就是这个参数
"experimentalDecorators": true,
"strictNullChecks": true,
"strictFunctionTypes": true
},
"exclude": ["node_modules", "**/node_modules/*"],
"include": ["src", "docs", "typed-css.d.ts"]
}
关闭报错的文件,重新打开或重启 vscode
踩坑 VSCode 报错 ReferenceError: React is not defined
安装并配置 @vitejs/plugin-vue-jsx 插件
ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx' // 添加这一句
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(), // 添加这一句
],
})
配置 tsconfig.json "jsx": "preserve"
json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Node",
"target": "ESNext",
"jsx": "preserve", //就是这个参数
"experimentalDecorators": true,
"strictNullChecks": true,
"strictFunctionTypes": true
},
"exclude": ["node_modules", "**/node_modules/*"]
}
关闭报错的文件,重新打开或重启 vscode
vue tsx 中使用 ref/reactive 变量/事件和样式
说明
注意ref变量,在html中需要`.value`才能显示
INFO
使用 css 模块化功能: 将 css/less/scss/sass 等文件命名为 xxx.module.scss/xxx.module.less/xxx.module.css 然后再在 tsx/jsx 文件中引入使用即可,参考上面的例子
props 与 v-model 使用
生命周期钩子
Sub01.tsx
tsx
import { defineComponent, onBeforeUnmount, onMounted, onUpdated, ref, toRefs } from 'vue'
export default defineComponent({
props: {
count: {
type: Number,
required: true,
},
},
setup(props) {
const { count } = toRefs(props)
const mountedStatus = ref<string>('onMounted未执行')
onMounted(() => {
setTimeout(() => {
mountedStatus.value = '子组件onMounted'
}, 5000)
})
onBeforeUnmount(() => {
alert('子组件卸载')
})
return () => (
<>
<p>子组件count:{count.value}</p>
<div>{mountedStatus.value}</div>
</>
)
},
})
slot 使用
对 slot 做了如下处理
- 给 slot dom 多包了一层
- 给 slot dom 添加了一个额外的 click 事件
tsx
import { defineComponent, onMounted } from 'vue'
export default defineComponent({
setup(props, ctx) {
// console.log(ctx)
// console.log(ctx.slots.default && ctx.slots.default())
//@ts-ignore
const vNode = ctx.slots.default()[0] as VNode
// 此时的vNode还只是vNode,并没有在浏览器中渲染完毕,所以vNode.el为null
// console.log(vNode.el)
// 给slot节点多包一层
const wrapperSlot = <h3>{vNode}</h3>
onMounted(() => {
// 此时的vNode已经在浏览器中渲染完毕,所以vNode.el为实际的dom对象了
const dom = vNode.el as HTMLElement
dom.addEventListener('click', () => {
alert('tsx click')
})
})
// function tsxOnClick($event) {
// console.log('tsxOnClick', $event)
// }
// let oldClickCall = vNode.props.onClick
// /*
// 这种方式可以直接在vNode还没渲染成真实的dom节点的时候,就将事件添加上去,
// 但如果vNode代指的dom本来就通过vue绑定了对应的事件的话,就有可能被覆盖。
// 比如下面的例子:如果事先已经绑定了一个click事件,这里再直接绑定一个click,那就会将原来的clikc事件覆盖
// 所以最好的方式,还是通过dom.addEventListener方式绑定
// */
// vNode.props.onClick = $event => {
// if (oldClickCall) {
// oldClickCall()
// }
// tsxOnClick($event)
// }
return () => (
<>
<div>这是子组件</div>
{wrapperSlot}
</>
)
},
})
WARNING
注意这里获取 slot 的 dom 对象的方式有缺陷,必须是 slot 原本的 dom 有 ref 属性这种方式才能获取到。
比如:上面例子的 slot 的原始 dom 是下面这个,因为有设置ref="spanDomRef"这个,所以 tsx 子组件中,才能在 mounted 回调中获取到对应 dom 对象,如果没有设置 ref,那么得到的结果依然为 null
html
<span ref="spanDomRef" @click="onClick" @mouseenter="onMouseEnter1(), onMouseEnter2(11)">
我是通过默认插槽填充的内容
</span>
最稳妥的获取插槽 dom 方式详见:vue 中如何获取插槽的 dom 对象#jsx-tsx-语法中