使用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


写在最后


  • 公众号无法外链,如果文中有链接,可点击下方阅读原文查看😊
相关文章
|
30天前
|
资源调度 JavaScript 前端开发
创建vue3项目步骤以及安装第三方插件步骤【保姆级教程】
这是一篇关于创建Vue项目的详细指南,涵盖从环境搭建到项目部署的全过程。
163 1
|
30天前
|
缓存 NoSQL JavaScript
Vue.js应用结合Redis数据库:实践与优化
将Vue.js应用与Redis结合,可以实现高效的数据管理和快速响应的用户体验。通过合理的实践步骤和优化策略,可以充分发挥两者的优势,提高应用的性能和可靠性。希望本文能为您在实际开发中提供有价值的参考。
56 11
|
2月前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
146 3
|
3月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
64 1
|
3月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
149 58
|
3月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
74 8
|
3月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
181 64
|
8天前
|
JavaScript 前端开发 开发者
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
|
8天前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
8天前
|
JavaScript 前端开发 数据安全/隐私保护
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。

热门文章

最新文章