vue2 使用@vue composition-api的一些问题
引入组件的方式
传统模式
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
这种方式在vue组件中使用 composition api
是没有问题的,但是无法在js中引入使用:
//xxx.js
import { ref, Ref } from "@vue/composition-api";
const a = ref();
此时就会报一个错误:Uncaught Error: [vue-composition-api] must call Vue.use(VueCompositionAPI) before using any function.
中文意思就是vue-composition-api
插件没有被use注册。
这里我们需要第二种引入方式
增加use的优先级
上述问题的原因是因为import
引入会提升,所以导致use在后面,如果use之前有js文件引入的了api,那么就会报错。
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
import router from './router'
import store from './store'
提升后
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
import router from './router'
import store from './store'
Vue.use(VueCompositionAPI)
解决办法就是将VueCompositionAPI作为一个单独的js文件引入,在js文件中use,这样use就不会放到后面。
创建一个composition-api.js
文件,填入以下内容:
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
再去main文件中引入
import Vue from 'vue'
import './composition-api'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
这样我们就能在js文件中引入也不会报错了。
composition-api中路由和vuex
网上常见的例子
<script>
import { defineComponent } from "@vue/composition-api";
export default defineComponent({
setup(props, ctx) {
const store = ctx.root.$store;
const router = ctx.root.$router;
const route = ctx.root.$route;
},
});
</script>
这种写法会有一个问题,route
并不是响应式的,一切基于route的watch监听,computed都不会触发。
而且ctx.root
指向的是你的根组件,也就是id="app"
的组件。
我的办法就是自己写一个可监听的route对象,但是这个对象目前还不是很完美,能用,并且无法监听里面的子属性。
首先写一个hooks:useRouter.ts
/*
* @Author: mulingyuer
* @Date: 2022-03-31 14:29:29
* @LastEditTime: 2022-03-31 15:11:41
* @LastEditors: mulingyuer
* @Description: useRouter
* @FilePath: \casino-vue2.0\src\hooks\useRouter.ts
* 怎么可能会有bug!!!
*/
import VueRouter, { Route } from "vue-router";
import { shallowRef, Ref } from "@vue/composition-api";
const router: Ref<VueRouter> = shallowRef();
const route: Ref<Route> = shallowRef();
//router
export function setRouter(val: VueRouter) {
router.value = val;
}
export function useRouter() {
return router.value;
}
//route
export function setRoute(val: Route) {
route.value = val;
}
export function useRoute() {
return route;
}
在路由中更新对象。
router.js
import Vue from "vue";
import VueRouter from "vue-router";
import { setRouter, setRoute } from "@/hooks/useRouter";
Vue.use(VueRouter);
const routes = [];
const router = new VueRouter({
mode: "hash",
routes,
scrollBehavior() {
return { x: 0, y: 0 };
},
});
//赋值router
setRouter(router);
router.beforeEach((to, from, next) => {
//首次route
if (!useRoute().value) setRoute(from);
});
//导航确定后触发
router.afterEach((to) => {
setRoute(to);
});
export default router;
路由初始化后实例,我们将实例赋值,每次路由切换,我们在确定导航后的钩子里赋值route,防止route被多次触发。
组件中使用:
<script>
import { defineComponent, watch } from "@vue/composition-api";
import { useRouter, useRoute } from "@/hooks/useRouter";
export default defineComponent({
setup() {
const router = useRouter();
const route = useRoute();
watch(
route,
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{ immediate: true }
);
return {
};
},
});
</script>
watch监听ref对象不用函数抛出,直接监听即可,也支持immediate
首次触发。
这种方式优势就是可以在js文件中使用,因为我是自己创建了一个可被观测的对象。
但是利用这种思路,我们其实可以不用这么写,如果没有在js中监听的需求的话。
<script>
import { defineComponent, watch } from "@vue/composition-api";
export default defineComponent({
setup(props,{ root }) {
watch(
() => root.$route,
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{ immediate: true }
);
return {
};
},
});
</script>
这样也是可以进行监听的
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
全部评论 2
自耦
Google Chrome Windows 10木灵鱼儿
FireFox Windows 10