引入组件的方式

传统模式

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>

这样也是可以进行监听的

分类: vue 项目实战 标签: vue2composition-api

评论

全部评论 2

  1. 自耦
    自耦
    Google Chrome Windows 10
    不能使用setup语法糖吗
    1. 木灵鱼儿
      木灵鱼儿
      FireFox Windows 10
      @自耦这个需要使用另一个插件去实现,挺麻烦的,我个人是挺讨厌这个语法糖的

目录