使用Vue3的CompositionAPI来优化代码量(下)

简介: 使用Vue3的CompositionAPI来优化代码量(下)

在组件中使用


定义完相应死变量后,我们就可以在组件中导入使用了,部分代码如下所示,完整代码请移步:message-display.vue


import initData from "@/module/message-display/main-entrance/InitData";
export default defineComponent({
   setup(props, context) {
    // 初始化组件需要的data数据
    const {
      createDisSrc,
      resourceObj,
      messageContent,
      emoticonShowStatus,
      emojiList,
      toolbarList,
      senderMessageList,
      isBottomOut,
      audioCtx,
      arrFrequency,
      pageStart,
      pageEnd,
      pageNo,
      pageSize,
      sessionMessageData,
      msgListPanelHeight,
      isLoading,
      isLastPage,
      msgTotals,
      isFirstLoading,
      messagesContainer,
      msgInputContainer,
      selectImg
    } = initData();
    // 返回组件需要用到的方法
    return {
      createDisSrc,
      resourceObj,
      messageContent,
      emoticonShowStatus,
      emojiList,
      toolbarList,
      senderMessageList,
      isBottomOut,
      audioCtx,
      arrFrequency,
      pageStart,
      pageEnd,
      pageNo,
      pageSize,
      sessionMessageData,
      msgListPanelHeight,
      isLoading,
      isLastPage,
      msgTotals,
      isFirstLoading,
      messagesContainer,
      msgInputContainer,
      selectImg
    };
   }
})


我们定义后响应式变量后,就可以在拆分出来的文件中导入initData函数,访问里面存储的变量了。


在文件中访问initData


我将页面内所有的事件监听也拆分成了文件,放在了EventMonitoring.ts中,在事件监听的处理函数是需要访问initData里存储的变量的,接下来我们就来看下如何访问,部分代码如下所示,完整代码请移步EventMonitoring.ts)


import {
  computed,
  Ref,
  ComputedRef,
  watch,
  getCurrentInstance,
  toRefs
} from "vue";
import { useStore } from "vuex";
import initData from "@/module/message-display/main-entrance/InitData";
import { SetupContext } from "@vue/runtime-core";
import _ from "lodash";
export default function eventMonitoring(
  props: messageDisplayPropsType,
  context: SetupContext<any>
): {
  userID: ComputedRef<string>;
  onlineUsers: ComputedRef<number>;
} | void {
  const $store = useStore();
  const currentInstance = getCurrentInstance();
  // 获取传递的参数
  const data = initData();
  // 将props改为响应式
  const prop = toRefs(props);
  // 获取data中的数据
  const senderMessageList = data.senderMessageList;
  const sessionMessageData = data.sessionMessageData;
  const pageStart = data.pageStart;
  const pageEnd = data.pageEnd;
  const pageNo = data.pageNo;
  const isLastPage = data.isLastPage;
  const msgTotals = data.msgTotals;
  const msgListPanelHeight = data.msgListPanelHeight;
  const isLoading = data.isLoading;
  const isFirstLoading = data.isFirstLoading;
  const listId = data.listId;
  const messageStatus = data.messageStatus;
  const buddyId = data.buddyId;
  const buddyName = data.buddyName;
  const serverTime = data.serverTime;
  const messagesContainer = data.messagesContainer as Ref<HTMLDivElement>;
  // 监听listID改变
  watch(prop.listId, (newMsgId: string) => {
    listId.value = newMsgId;
    messageStatus.value = prop.messageStatus.value;
    buddyId.value = prop.buddyId.value;
    buddyName.value = prop.buddyName.value;
    serverTime.value = prop.serverTime.value;
    // 消息id发生改变,清空消息列表数据
    senderMessageList.length = 0;
    // 初始化分页数据
    sessionMessageData.length = 0;
    pageStart.value = 0;
    pageEnd.value = 0;
    pageNo.value = 1;
    isLastPage.value = false;
    msgTotals.value = 0;
    msgListPanelHeight.value = 0;
    isLoading.value = false;
    isFirstLoading.value = true;
  });
}


正如代码中那样,在文件中使用时,拿出initData中对应的变量,需要修改其值时,只需要修改他的value即可。


至此,有关compositionAPI的基本使用就跟大家讲解完了,下面将跟大家分享下我在实现过程中所踩的坑,以及我的解决方案。


踩坑分享


今天是周四,我周一开始决定使用CompositionAPI来重构我这个组件的,一直搞到昨天晚上才重构完成,前前后后踩了很多坑,正所谓踩坑越多你越强,这句话还是很有道理的😎。


接下来就跟大家分享下我踩到的一些坑以及我的解决方案。


dom操作


我的组件需要对dom进行操作,在optionsAPI中可以使用this.$refs.xxx来访问组件dom,在setup中是没有this的,翻了下官方文档后,发现需要通过ref来定义,如下所示:


<template>
<div ref="msgInputContainer"></div>
<ul v-for="(item, i) in list" :ref="el => { ulContainer[i] = el }"></ul>
</template>
<script lang="ts">
  import { ref, reactive, onBeforeUpdate } from "vue";
  setup(){
    export default defineComponent({
    // DOM操作,必须return否则不会生效
    // 获取单一dom
    const messagesContainer = ref<HTMLDivElement | null>(null);
    // 获取列表dom
    const ulContainer = ref<HTMLUListElement>([]);
    const list = reactive([1, 2, 3]);
    // 列表dom在组件更新前必须初始化
    onBeforeUpdate(() => {
       ulContainer.value = [];
    });
    return {
      messagesContainer,
      list,
      ulContainer
    }
  })
  }
</script>


访问vuex


在setup中访问vuex需要通过useStore()来访问,代码如下所示:


import { useStore } from "vuex";
const $store = useStore();
console.log($store.state.token);


访问当前实例


在组件中需要访问挂载在globalProperties上的东西,在setup中就需要通过getCurrentInstance()来访问了,代码如下所示:


import { getCurrentInstance } from "vue";
const currentInstance = getCurrentInstance();
currentInstance?.appContext.config.globalProperties.$socket.sendObj({
  code: 200,
  token: $store.state.token,
  userID: $store.state.userID,
  msg: $store.state.userID + "上线"
});


无法访问$options


我重构的websocket插件是将监听消息接收方法放在options上的,需要通过this.$options.xxx来访问,文档翻了一圈没找到有关在setup中使用的内容,那看来是不能访问了,那么我只能选择妥协,把插件挂载在options上的方法放到globalProperties上,这样问题就解决了。


内置方法只能在setup中访问


如上所述,我们使用到了getCurrentInstanceuseStore,这两个内置方法还有initData中定义的那些响应式数据,只有在setup中使用时才能拿到数据,否则就是null。


我的文件是拆分出去的,有些函数是运行在某个拆分出来的文件中的,不可能都在setup中执行一遍的,响应式变量也不可能全当作参数进行传递的,为了解决这个问题,我有试过使用provide注入然后通过inject访问,结果运行后发现不好使,控制台报黄色警告说provide和inject只能运行在setup中,我直接裂开,当时发了一条沸点求助了下,到了晚上也没得到解决方案😪。


经过一番求助后,我的好友@前端印象给我提供了一个思路,成功的解决了这个问题,也就是我上面initData的做法,将响应式变量定义在导出函数的外面,这样我们在拆分出来的文件中导入initData方法时,里面的变量都是指向同一个地址,可以直接访问存储在里面的变量且不会将其进行初始化。


至于getCurrentInstanceuseStore访问出现null的情景,还有props、emit的使用问题,我们可以在initData的导出函数内部定义set方法,在setup里的方法中获取到实例后,通过set方法将其设置进我们定义的变量中。


至此,问题就完美解决了,最后跟大家看下优化后的组件代码,393行😁

640.png

                          image-20210114201837539    


项目地址


项目地址:chat-system-github


在线体验地址:chat-system


写在最后


  • 公众号无法外链,如果文中有链接,可点击下方阅读原文查看😊
相关文章
|
16天前
|
存储 JavaScript 前端开发
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
【10月更文挑战第21天】 vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
|
13天前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
30 7
|
14天前
|
前端开发 数据库
芋道框架审批流如何实现(Cloud+Vue3)
芋道框架审批流如何实现(Cloud+Vue3)
36 3
|
13天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
33 1
|
13天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
34 1
|
15天前
|
前端开发 JavaScript
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
|
16天前
Vue3 项目的 setup 函数
【10月更文挑战第23天】setup` 函数是 Vue3 中非常重要的一个概念,掌握它的使用方法对于开发高效、灵活的 Vue3 组件至关重要。通过不断的实践和探索,你将能够更好地利用 `setup` 函数来构建优秀的 Vue3 项目。
|
3天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
3天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
3天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。