1. 当Uniapp遇上Vue3+Ts:globalData共享的困境
最近在帮团队升级Uniapp项目到Vue3+TypeScript时,遇到了一个典型问题:App.vue中原本通过export default导出的globalData全局变量,在改用<script setup>语法糖后突然失效了。其他页面通过getApp()获取全局变量时,控制台不断报出"undefined"错误,这直接影响了项目中十几个页面的正常运行。
问题的本质在于<script setup>的设计理念。这个语法糖确实让代码更简洁了,但它彻底改变了组件的导出方式——在setup语法糖中,所有顶层绑定都会自动暴露给模板,因此不再需要(也不允许)使用export default。这就导致我们既想保留Vue3的新特性,又需要兼容老项目中的全局变量体系时,陷入了两难境地。
更棘手的是生命周期函数的执行问题。在原来的Vue2模式中,onLaunch等应用生命周期函数都是直接写在export default对象里的。现在如果全部迁移到setup语法糖中,虽然可以用onLaunch(()=>{})的写法,但实际测试发现某些情况下执行顺序会出现混乱,特别是当页面快速跳转时,可能导致全局变量还未初始化就被调用的情况。
2. 双script标签的魔法:兼容新旧两种模式
经过多次尝试,我发现最优雅的解决方案是同时使用两种script标签。具体做法是在App.vue中保留传统的<script lang="ts">块用于导出globalData,同时新增<script setup lang="ts">块来编写组合式API代码。这种混合写法完美解决了我们的核心需求:
<!-- 处理组合式API和生命周期 --> <script setup lang="ts"> import { onLaunch } from '@dcloudio/uni-app' onLaunch(() => { console.log('组合式API的onLaunch') // 初始化操作... }) </script> <!-- 处理全局变量和传统选项 --> <script lang="ts"> export default { globalData: { userToken: '', systemInfo: {} as UniApp.GetSystemInfoResult }, onLaunch() { console.log('选项式的onLaunch') // 获取系统信息 this.globalData.systemInfo = uni.getSystemInfoSync() } } </script>这里有个关键细节:两个script标签都必须声明相同的语言类型。如果一个是lang="ts"而另一个没有声明,Vite会直接报错"[plugin:vite:vue]