在vue2中使用setup和compositionAPI

2,497 阅读2分钟

最近写项目用到了vue2,以为要开始痛苦的optionAPI编程,没想到vue2竟然支持compositionAPI了,甚至能在setup里写代码!

下面是vue2的setup写法,用起来和vue3差不多了,还支持pinia!

vue2可以使用refreactive,没有使用proxy实现,还是用了defineProperty的getter,setter,可以放心使用!

刚上手我还不敢相信这是用的vue2,赶紧翻看package.json,哦,vue2.7

使用一天下来(没写多少逻辑,光糊页面了),发现唯一不同的就是:获取当前页面路由信息

vue3里可以用

// vue-router ^4.0
import { useRoute } from 'vue-router';
const route = useRoute();
route.path // /home
route.query // { foo: 'bar' }

但是vue-router版本必须是4以上,我这里的版本号是3,所以没有useRoute这个函数。

那vue2中的获取当前route怎么写?

export default {
    // ...
    mounted(){
        const route = this.$route;
        route.path // /home
    }
}

要从this中获取,那我setup里this是null了,走进死胡同了。

最终找到一个vue2-router的包:ambit-tsai/vue2-helpers: 🔧 A util package to use Vue 2 with Composition API easily (github.com)

用法大概是:

import { useRoute } from 'vue2-helpers/vue-router';
​
const route = useRoute();

这么厉害?看一下源码,关键源码:

// https://github.com/ambit-tsai/vue2-helpers/blob/for-vue-2.7/src/vue-router.ts#L52
export function useRouter(): Router {
    // 获取当前实例
    const inst = getCurrentInstance();
    if (inst) {
        // 从当前实例里拿$router
        return inst.proxy.$root.$router as Router;
    }
    warn(OUT_OF_SCOPE);
    return undefined as any;
}
​
let currentRoute: Route;
​
export function useRoute(): RouteLocationNormalizedLoaded {
    const router = useRouter();
    if (!router) {
        return undefined as any;
    }
    if (!currentRoute) {
        const scope = effectScope(true);
        scope.run(() => {
            // router.currentRoute是当前route
            currentRoute = reactive(assign({}, router.currentRoute)) as any;
            router.afterEach((to) => {
                assign(currentRoute, to);
            });
        });
    }
    return currentRoute;
}

从上面代码可以看出,关键在于getCurrentInstance(),其实从这里就可以拿到this上的东西了,可以直接拿$route

// 获取当前实例
const inst = getCurrentInstance();
if (inst) {
    // inst.proxy.$root === this
    return inst.proxy.$root.$route;
}

最终我没有引入这个包,直接这么写的

10月14号补充:

试着在reactive中写数组,发现是不支持的

const list = reactive([]);

报错描述的很清晰,说是defineProperty的局限性:不能监测数组内部变化。

Composition API 使用 Vue 2 的基于 getter/setter 的响应式系统进行反向移植,以确保浏览器兼容性。 这意味着与 Vue 3 的基于 proxy 的系统存在一些重要的行为差异:

——摘自掘金

算是与vue3不同的地方,解决办法,我换ref用起来是可以的

const list = ref([])

其他细节请看:Vue 2.7 正式发布,代号为 Naruto - 掘金 (juejin.cn)

vue-router3已经支持use-router了!

vue-router/composables.js at dev · vuejs/vue-router (github.com)

只需:

import { useRoute } from 'vue-router/composables'
const route = useRoute();

关于vue2.7中vue-router的讨论:[功能请求]添加对 Vue 2.7 的支持 ·问题 #3760 ·vuejs/vue-router (github.com)

11月3号补充: vue2里貌似写不了自定义组件v-model,因为optionsAPI有专门的地方写,vue3里又是约定式的update:xxx事件,在2.7里不生效。 最终用传prop带.sync的写法做的。