vue3 通过import()动态加载组件,优雅地将页面渲染与数据解耦

文章目录

    • 概要
    • 整体架构流程
      • 1.第一版代码——解耦
      • 2.第二版代码——动态组件
    • 技术细节
    • 小结

概要

目前网上查询动态组件渲染的问题,大部分都是借助h(createVNode)函数、createApp、createRender函数之类的来渲染vnode,然后把vnode加载到某个dom节点中,总感觉这样做不太合适,很可能会挖坑。

所以我想要一种更优雅的方式,对项目原有架构、编码习惯破坏最小,不会增加后面维护代码小伙伴的心智负担。

项目背景:现在项目里有个需求,我想要把页面渲染和页面数据解耦,页面如下:

vue3 通过import()动态加载组件,优雅地将页面渲染与数据解耦_第1张图片

后端大概有七八个组件需要维护配置项,当然最简单的方式肯定是直接在页面里硬编码,以后多一个组件,我就多写一个tab,多写一部分静态html代码来渲染组件,当然还需要多写一部分scripts来引入组件和定义组件。

我简简单单的一个增加组件的需求,需要大致做三项工作:

  1. 静态html标签中增加渲染代码
  2. script中增加引入组件代码
  3. script中增加定义组件代码

上面三项工作都很简单,毕竟这就是大部分前端开发者的工作模式,但是它至少有以下几个缺点:

  1. 增加删除一个组件,需要修改三处代码,出错率、后期维护负担都会增加。
  2. 项目规模变大后,代码修改上下穿插无序,会很难做版本管理,不利于走向产品化
  3. 可读性差,初代开发者觉得最简单的写法最易读,那是因为他目前还比较了解代码,等过三个月,他自己都不知道自己写的代码增加一个小功能,需要修改几处。

所以依据优化组件配置页面这个需求,我需要有个统一入口,来渲染所有页面元素,以后增加、删除、修改组件只需要修改这一个变量即可。

最好的方式就是定义一个tabList数组,页面渲染逻辑定义好后,所有数据的修改都通过修改tabList来实现。

整体架构流程

1.第一版代码——解耦

template部分

<template>
  <Tabs value="name1">
    <TabPane :label="tabItem.label" :name="tabItem.name" v-for="tabItem in tabList">
      {{tabItem.content}}
    </TabPane>

  </Tabs>
</template>

script部分

import {ref} from 'vue'

const tabList = [{
  name: 'midstation',
  label: '监听组件',
  content:''
},
  {
    name: 'restart',
    label: '重启组件',
    content:''
  },

]

这是最基础的结构,以后可以把tabList数据部分通过import方式引入进来,这样渲染有变动时,并不会影响tabList,tabList有变动时,不会影响渲染部分,才能真正将渲染与数据解耦,当同一套基础代码分出许多分支时,才能更自如地拉取与合并代码。

因为针对大部分场景,数据经常变动,渲染逻辑基本不变,渲染变化后也应该能够拉取到各个分支而不影响其他分支。(如果理解不了,不用强求,说明目前接触的项目并不需要考虑这些)

2.第二版代码——动态组件

上面的代码有个问题,就是每个标签页的内容通过content字段渲染,这个字段是个字符串,实际情况中,标签页中可能是表单、可能是各种工具集合,它可能是很复杂的页面,所以一定得有组件引入的方式。

这就是动态组件引用了。

为什么不能直接通过import引入静态组件,然后把静态组件定义在这个content字段,原因上面概述说过了,我们只是想增加删除一个组件,这个功能很单一,应该只有一个入口——tabList,如果import静态引入组件,我们就需要先引入,再修改tabList,对于这种批量、机械化定义的组件而言,引入的这一步,就是个累赘。

所以我们要用动态引入组件的方式,把变量控制在tabList这一个区域。

概述中的挖坑思路就不多讲了,我最初的想法是通过import函数动态引入后再定义组件的方式,content部分核心代码如下:

const tabList = [{
  name: 'midstation',
  label: '监听组件',
  content:()=>{
    import('@/module-install/confSetting/midstation.vue').then(res=>{
		com.value=res.default
	})
  }
}]

这代码参考即可,部分代码未显示,因为这种代码方式被放弃了。它虽然比各种dom操作优雅点,但仍然繁琐,如果要让这种思路可用,需要再封装一个更复杂的函数,专门来处理这种情况。

动态组件(异步组件)并不是一个小众场景,很多ui框架也都实现了,我觉得vue3一定也会考虑这种场景,所以就又翻了翻官网api,果然发现了vue3提供的defineAsyncComponent

这个api可以处理动态组件,而不需要开发者自己去处理promise对象,它的功能,不就是我们上面想要封装的那个函数吗?这次不用自己做了,改良后代码如下:

const tabList = [{
  name: 'midstation',
  label: '监听组件',
  content: defineAsyncComponent(() =>{
        return import('@/module-install/confSetting/midstation.vue')
      }
  )
},
  {
    name: 'restart',
    label: '重启组件',
    content: defineAsyncComponent(() =>{
          return import('@/module-install/confSetting/restart.vue')
        }
    )
  },
]

到这,content字段就已经赋值我们动态组件返回的结果了。下面我们把它渲染出来:

<template>
  <Tabs value="name1">
    <TabPane :label="tabItem.label" :name="tabItem.name" v-for="tabItem in tabList">
      <component :is="tabItem.content"></component>
    </TabPane>

  </Tabs>
</template>

最终结果如图:

vue3 通过import()动态加载组件,优雅地将页面渲染与数据解耦_第2张图片

vue3 通过import()动态加载组件,优雅地将页面渲染与数据解耦_第3张图片
完美加载两个组件,并且以后这个tab页面再有修改,只需要修改tabList一个变量即可。

技术细节

  • import()动态加载组件
  • 渲染模型与数据模型解耦
  • vue3提供的api使用:defineAsyncComponent

小结

如果文章对同学有帮助,请点赞收藏关注博主,感谢支持。

在人类社会资源池中能抢占多少,看的不只是某一因素,而是你在人堆里的整体排名,排名影响因素包括但不止于家庭、学历、性格、颜值、编程能力……看到这篇文章的同学,大概率前面四个因素已经无法重塑,你能提升人堆里排名的机遇在哪,摆在眼前了!

——鲁迅说:中二少年说的

你可能感兴趣的:(vue3实战专栏,vue.js,vue)