vue3无法使用jsx问题
报错一:无法使用 JSX,除非提供了 "--jsx" 标志
在Vite+Vue3.0中使用jsx语法开发,需要安装jsx插件
npm i @vitejs/plugin-vue-jsx -s
在vite.config.js加入jsx配置
// vite.config.js import { defineConfig } from 'vite' import vueJsx from '@vitejs/plugin-vue-jsx' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue(), vueJsx()], })
至此,我们新建的这个vite项目已经全面支持jsx语法了,此时还需要在tsconfig.ts中配置"jsx": "preserve"属性,就可以愉快的使用jsx形式来写vue了。
报错二:ElementPlusIconsVue挂载问题
import ElementPlusIconsVue
类型“typeof import("D:/\u9879\u76EE/00/model-dev-platform-doc/node_modules/@element-plus/icons-vue/dist/types/index")”的参数不能赋给类型“Plugin_2”的参数。
解决办法:
经过善良的QQ群友点拨之后才明白....
需要遍历挂载
报错二:vue3.0+ts 找不到模块“./XXX.vue”或其相应的类型声明。
鹅鹅鹅鹅鹅鹅.....还没找到原因
卸载掉volar插件,全部报错都消失
关于vue3的jsx写法问题
安装 @vitejs/plugin-vue-jsx vite 插件
yarn add @vitejs/plugin-vue-jsx -D npm install @vitejs/plugin-vue-jsx -D
安装完成之后,在 vite.config.js 中进行配置:
import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import vueJsx from "@vitejs/plugin-vue-jsx"; export default defineConfig({ plugins: [ vue(), vueJsx(), ] })
然后,即可编写 jsx 形式的 vue 单文件组件。
编写示例
基础实例
vue3 新增了 setup 这个组合式 api,这样就使得利用 jsx 编写 vue 组件时的风格非常类似于 react。在 setup 可以创建 state,接受 props,还可以直接返回 jsx。
import { defineComponent} from 'vue'; export default defineComponent({ setup() { return <div>123456789</div> } });
props 和 state
在 vue3 中,存在 ref 和 reactive 这两个创建响应式状态的 api。由于内置的观察者模式,导致 vue 并不需要像 react 那样,提供 useMemo,useCallback 等根据条件判断是否更新的钩子。
ref 在 render 函数中,会自动解构,不需要再使用 ref.value 来获取里面的值。
推荐使用 ref,而不是 reactive。
props 则需要在 defineComponent 中使用 props 属性,指定 props,该组件才会接受对应的 props。
子组件不能在 setup 中返回 jsx,否则弹出警告,不渲染该子组件。
父组件接受子组件后,不可在 setup 中直接返回 ctx,或者 ctx.slots?.default?.() 计算后的值,第一种情况弹出警告,不渲染该子组件;第二种情况,该子组件不会响应式。正确的做法,应该是返回一个渲染函数。
子组件:
import { defineComponent, ref, reactive } from 'vue; export default defineComponent({ name: 'TestB', // 必须传递props,提醒 vue,该组件可以接受名称为 str 的值 // 如果不填,则 props 接受不到该值。 // 如果该组件为子组件,不可在 setup 中返回元素,必须在 render 中返回元素 props: ['str'], setup(this, props, ctx) { const count = ref(0); const { str } = props; const reactiveCount = reactive({value: 0}); return { str, count, reactiveCount, } }, render() { const { count, reactiveCount, str } = this; return <div>{count} - {reactiveCount.value} - {str}</div> } });
父组件:
import { defineComponent } from "vue"; export default defineComponent({ props: ['testStr'], name: 'TestA', setup(props, ctx) { const { testStr } = props; // 注意,不要直接返回一个 ctx.slots?.default?.() 计算后的值,这样不能响应式 // 同时,也要注意,不能直接返回 ctx,会有警告,同时不会显示子元素 const renderFn = () => { return <div>{ ctx.slots?.default?.() ?? "" }</div> } return { testStr, renderFn, } }, render() { const { testStr, renderFn } = this; return <div>你输入的字符串: {testStr} <div>子组件</div> <div>{ renderFn() }</div> </div> } })
事件监听
@vitejs/plugin-vue-jsx 该插件默认将 @input 等相关模板语法,替换成了 onInput 等 jsx 形式。这里以点击事件举例。
import { defineComponent, ref, reactive } from "vue"; interface ITestAProps { str: string; } export default defineComponent({ name: "TestA", props: ["str"], setup(this, props, ctx) { const count = ref(0); const { str } = props; const reactiveCount = reactive({ value: 0 }); const onClick = () => { count.value++; }; const reactiveClick = () => { reactiveCount.value++; }; return { str, count, reactiveCount, onClick, reactiveClick, }; }, render() { const { count, reactiveCount, str, onClick, reactiveClick } = this; return ( <div> <div onClick={onClick}>{count}</div> <div onClick={reactiveClick}>{reactiveCount.value}</div> <div>{str}</div> </div> ); }, });
插槽
vue3 中,可以使用快捷语法(以 element-plus 举例)
<el-popconfirm title="确认删除最后一个配置内容?" confirm-button-text="确认" cancel-button-text="取消" @confirm=" addNewValue.newConfigList.length > 1 ? addNewValue.newConfigList.pop() : ElMessage({ message: '不能删除所有配置内容', type: 'error', }) " > <template #reference> <el-button type="danger"> 删除最后一个表单配置内容 </el-button> </template> </el-popconfirm>
jsx 形式中的 vue3 中,可以使用
import { defineComponent } from 'vue'; import { ElPopconfirm, ElButton } from 'element-plus'; export default defineComponent({ render() { return <ElPopconfirm title="确认删除最后一个配置内容?" confirmButtonText="确认" cancelButtonText="取消" onConfirm={() => { addNewValue.newConfigList.length > 1 ? addNewValue.newConfigList.pop() : ElMessage({ message: '不能删除所有配置内容', type: 'error', }) }} v-slot={{ reference: () => <ElButton type="danger">删除最后一个表单配置内容</ElButton> }} > </ElPopconfirm> } });
其余相关的属性
其余相关的属性,比如 v-model 啥的,还是按照原来的写法去写。
这里需要注意一点 v-model 如果使用 jsx 写法,不会自动双向绑定,需要自己去写对应的函数。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。