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


写在最后


  • 公众号无法外链,如果文中有链接,可点击下方阅读原文查看😊
相关文章
|
23天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
23天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
103 60
|
23天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
29 8
|
22天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
22 1
|
22天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
33 1
|
23天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
27天前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
39 0
|
27天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
28天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
2天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
下一篇
DataWorks