vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > VUE前端组件式开发和动态装载

VUE如何实现前端组件式开发和动态装载详解

作者:猩火燎猿

Vue动态加载是指在Vue框架中,根据需要动态加载组件、模板或静态资源的能力,这篇文章主要介绍了VUE如何实现前端组件式开发和动态装载的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、认识vue组件

1. 组件的基本概念

组件是 Vue 应用的基本组成单位,每个组件都可以包含自己的模板、逻辑和样式。组件可以复用、嵌套和组合,从而构建复杂的界面。

2. 创建组件

单文件组件(.vue 文件)

这是 Vue 最推荐的组件开发方式。

示例:MyButton.vue

<template>
  <button @click="handleClick">{{ label }}</button>
</template>

<script>
export default {
  name: 'MyButton',
  props: {
    label: String
  },
  methods: {
    handleClick() {
      this.$emit('click')
    }
  }
}
</script>

<style scoped>
button {
  color: #42b983;
}
</style>

3. 使用组件

在父组件中注册和使用

示例:App.vue

<template>
  <div>
    <MyButton label="点我" @click="onBtnClick" />
  </div>
</template>

<script>
import MyButton from './components/MyButton.vue'

export default {
  components: {
    MyButton
  },
  methods: {
    onBtnClick() {
      alert('按钮被点击了!')
    }
  }
}
</script>

4. 组件通信

5. 组件嵌套与复用

你可以在组件内部继续使用其他组件,实现嵌套和复用。

6. 组件开发规范

7. 组件库

你可以自己开发组件库,也可以使用现成的(如 Element Plus、Ant Design Vue 等)。

总结

Vue 组件式开发流程:

8. 组件生命周期

Vue 组件有完整的生命周期钩子,可以在不同阶段执行逻辑,比如:

<code>export default {
  created() {
    // 组件创建时执行
  },
  mounted() {
    // 组件挂载到 DOM 后执行
  },
  updated() {
    // 组件更新时执行
  },
  destroyed() {
    // 组件销毁时执行
  }
}
</code>

9. 动态组件 & 异步组件

动态组件

可以通过 <component :is="componentName"> 动态切换组件:

<template>
  <component :is="currentComponent"></component>
</template>

<script>
import CompA from './CompA.vue'
import CompB from './CompB.vue'

export default {
  data() {
    return {
      currentComponent: 'CompA'
    }
  },
  components: { CompA, CompB }
}
</script>

异步组件

按需加载组件,优化性能:

<code>const AsyncComp = () => import('./AsyncComp.vue')
export default {
  components: { AsyncComp }
}
</code>

10. 插槽(slot)

插槽让组件更灵活,父组件可以向子组件插入内容。

基本插槽

<!-- MyCard.vue -->
<template>
  <div class="card">
    <slot></slot>
  </div>
</template>

具名插槽

&lt;template&gt;
  &lt;div&gt;
    &lt;slot name="header"&gt;&lt;/slot&gt;
    &lt;slot&gt;&lt;/slot&gt;
    &lt;slot name="footer"&gt;&lt;/slot&gt;
  &lt;/div&gt;
&lt;/template&gt;

父组件使用:

<MyCard>
  <template #header>标题</template>
  内容
  <template #footer>底部</template>
</MyCard>

作用域插槽

用于传递数据给插槽内容:

<!-- List.vue -->
<template>
  <div>
    <slot v-for="item in items" :item="item"></slot>
  </div>
</template>

父组件:

<List :items="listData">
  <template #default="{ item }">
    <div>{{ item.name }}</div>
  </template>
</List>

11. 组件样式隔离

在 <style scoped> 标签下写样式,只作用于当前组件,避免样式污染。

<style scoped>
.card { border: 1px solid #ccc; }
</style>

12. 组件自动导入(vite/vue-cli)

使用 Vite 或 Vue CLI 可以配置自动导入,无需手动 import

<code>// vite.config.js
import Components from 'unplugin-vue-components/vite'
export default {
  plugins: [
    Components({ /* options */ })
  ]
}
</code>

13. 组件测试

可以使用 Vue Test Utils 或 Vitest 进行单元测试,保证组件质量。

14. 组件文档与封装

16. 组件拆分与复用实践

页面拆分思路

示例:

src/
  components/
    BaseButton.vue
    BaseDialog.vue
    UserList.vue
    UserForm.vue
  views/
    UserPage.vue

17. 组件间通信进阶

1. 父子通信(props/$emit)

2. 兄弟通信

mitt 示例:

<code>// eventBus.js
import mitt from 'mitt'
export default mitt()</code>
<code>// 组件A
import bus from './eventBus'
bus.emit('custom-event', data)

// 组件B
import bus from './eventBus'
bus.on('custom-event', (data) => { ... })
</code>

18. 组合式 API 与组件复用

Vue3 推荐使用组合式 API(setuprefreactivecomputedwatch等),逻辑可以抽成 composable 复用。

示例:

<code>// useCounter.js
import { ref } from 'vue'
export function useCounter() {
  const count = ref(0)
  const inc = () => count.value++
  return { count, inc }
}
</code>
<script setup>
import { useCounter } from './useCounter'
const { count, inc } = useCounter()
</script>

19. 动态组件和递归组件

动态组件

<component :is="current"></component>

递归组件

用于树形结构等场景,自己调用自己。

<TreeNode :node="node">
  <TreeNode v-for="child in node.children" :node="child" />
</TreeNode>

20. 插槽的进阶用法

21. 组件懒加载和按需加载

提升性能,减少首屏包体积。

<code>const MyComp = defineAsyncComponent(() => import('./MyComp.vue'))
</code>

22. 组件的自定义指令

有时你需要在组件中用自定义指令封装 DOM 操作逻辑。

<code>app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})
</code>

23. 组件的类型声明(TypeScript)

用 TypeScript 能让组件开发更规范、更易维护。

<code><script lang="ts" setup>
defineProps<{ label: string }>()
</script>
</code>

24. 组件的单元测试

用 Vitest + Vue Test Utils:

<code>import { mount } from '@vue/test-utils'
import MyButton from './MyButton.vue'

test('emit click event', () => {
  const wrapper = mount(MyButton, { props: { label: '点我' } })
  wrapper.trigger('click')
  expect(wrapper.emitted()).toHaveProperty('click')
})
</code>

25. 组件开发注意事项

二、动态加载组件实现

1. 基础动态组件用法(<component :is="...">

你可以通过 <component :is="组件名或组件对象"> 动态切换渲染不同的组件。

示例

假设有两个组件:CompA.vue 和 CompB.vue

CompA.vue

<template>
  <div>A 组件内容</div>
</template>

CompB.vue

<template>
  <div>B 组件内容</div>
</template>

App.vue

<template>
  <div>
    <button @click="current = 'CompA'">显示A</button>
    <button @click="current = 'CompB'">显示B</button>
    <component :is="current" />
  </div>
</template>

<script setup>
import CompA from './CompA.vue'
import CompB from './CompB.vue'

import { ref } from 'vue'
const current = ref('CompA')

const components = { CompA, CompB }
</script>

<script>
export default {
  components: { CompA, CompB }
}
</script>

注意:如果用 <script setup>,无需 components 选项,直接在模板里用变量名即可。

2. 异步组件(懒加载组件)

在大型项目中,为了优化性能,可以按需懒加载组件。

Vue 3 推荐写法

语法一:defineAsyncComponent

<template>
  <component :is="AsyncComp" />
</template>

<script setup>
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() => import('./CompA.vue'))
</script>

动态切换多种异步组件

<template>
  <button @click="current = 'A'">A</button>
  <button @click="current = 'B'">B</button>
  <component :is="asyncComponents[current]" />
</template>

<script setup>
import { defineAsyncComponent, ref } from 'vue'

const asyncComponents = {
  A: defineAsyncComponent(() => import('./CompA.vue')),
  B: defineAsyncComponent(() => import('./CompB.vue'))
}
const current = ref('A')
</script>

3. 动态组件的缓存(keep-alive)

如果你希望切换组件时缓存组件状态,可以用 <keep-alive> 包裹:

<keep-alive>
  <component :is="current" />
</keep-alive>

4. 动态组件常见应用场景

5. 总结

6. 动态加载组件并传递参数(props)

你可以通过 v-bind 给动态组件传递不同的 props。

示例:

<template>
  <component
    :is="currentComp"
    v-bind="currentProps"
  />
</template>

<script setup>
import { ref } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'

const currentComp = ref(CompA)
const currentProps = ref({ msg: 'Hello A' })

function switchToB() {
  currentComp.value = CompB
  currentProps.value = { msg: 'Hello B' }
}
</script>

7. 动态组件的事件监听

可以通过 v-on 监听动态组件发出的事件:

<template>
  <component
    :is="currentComp"
    v-bind="currentProps"
    v-on="currentEvents"
  />
</template>

<script setup>
import { ref } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'

const currentComp = ref(CompA)
const currentProps = ref({ msg: 'Hello A' })
const currentEvents = ref({
  someEvent: (val) => { console.log('事件触发', val) }
})
</script>

8. 动态组件与插槽结合

动态组件也可以使用插槽,父组件可根据需要传递内容:

<template>
  <component :is="currentComp">
    <template #default>
      <div>插槽内容</div>
    </template>
  </component>
</template>

9. 动态组件的异步加载进阶(带加载/错误/超时处理)

defineAsyncComponent 支持配置 loading、error、timeout 等状态:

<code>import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./CompA.vue'),
  loadingComponent: LoadingComp,
  errorComponent: ErrorComp,
  delay: 200,
  timeout: 3000,
})
</code>

10. 动态组件的注册方式

如果组件很多,可以用对象管理:

<code>const components = {
  CompA: () => import('./CompA.vue'),
  CompB: () => import('./CompB.vue'),
  // ...
}
</code>

然后在 <component :is="components[activeName]" /> 动态加载。

11. 动态组件的递归加载(树形结构)

适合渲染树状数据:

<TreeNode :node="rootNode" />

TreeNode 组件内部递归调用自己。

12. 动态加载远程组件(高级)

有些场景需要从后台拉取组件代码并动态渲染,可以结合 eval 或 new Function(安全性需考虑),或用微前端方案。

13. 动态表单、动态弹窗、动态页面等场景

实际业务中,常见动态加载组件的场景有:

14. 动态组件的性能优化

15. 小结

动态加载组件在 Vue 项目中非常常用,关键点包括:

三、动态import组件

1. 动态 import 组件的原理

import() 是 JavaScript 的原生动态导入语法,会返回一个 Promise,可以实现按需加载(懒加载):

<code>const CompA = () => import('./CompA.vue')
</code>

配合 Vue 的 <component :is="...">,就可以动态加载并显示组件。

2. Vue 3 推荐用法:defineAsyncComponent

Vue 3 提供了 defineAsyncComponent 用于异步加载组件,支持 loading、error 等状态。

<code>import { defineAsyncComponent } from 'vue'

const AsyncCompA = defineAsyncComponent(() => import('./CompA.vue'))
</code>

3. 实战:动态 import 并显示组件

1)准备两个组件

CompA.vue

<template>
  <div>我是A组件</div>
</template>

CompB.vue

<template>
  <div>我是B组件</div>
</template>

2)父组件动态加载并显示

App.vue

<template>
  <button @click="show('A')">显示A</button>
  <button @click="show('B')">显示B</button>
  <component :is="currentComp" />
</template>

<script setup>
import { ref } from 'vue'
import { defineAsyncComponent } from 'vue'

const currentComp = ref(null)

function show(type) {
  if (type === 'A') {
    currentComp.value = defineAsyncComponent(() => import('./CompA.vue'))
  } else if (type === 'B') {
    currentComp.value = defineAsyncComponent(() => import('./CompB.vue'))
  }
}
</script>

3)带 loading、error 组件的动态 import

<script setup>
import { defineAsyncComponent, ref } from 'vue'
import Loading from './Loading.vue'
import ErrorComp from './Error.vue'

const currentComp = ref(null)

function show(type) {
  if (type === 'A') {
    currentComp.value = defineAsyncComponent({
      loader: () => import('./CompA.vue'),
      loadingComponent: Loading,
      errorComponent: ErrorComp,
      delay: 200,
      timeout: 3000
    })
  } else if (type === 'B') {
    currentComp.value = defineAsyncComponent({
      loader: () => import('./CompB.vue'),
      loadingComponent: Loading,
      errorComponent: ErrorComp,
      delay: 200,
      timeout: 3000
    })
  }
}
</script>

4. 总结

5. 进阶:动态组件注册表

如果组件很多,可以用对象来管理:

<script setup>
import { defineAsyncComponent, ref } from 'vue'

const compMap = {
  A: defineAsyncComponent(() => import('./CompA.vue')),
  B: defineAsyncComponent(() => import('./CompB.vue')),
  // 还可以继续添加更多
}
const current = ref('A')
</script>

<template>
  <button @click="current = 'A'">A</button>
  <button @click="current = 'B'">B</button>
  <component :is="compMap[current]" />
</template>

6. 动态 import 组件并传递 props

你可以通过 v-bind 给动态加载的组件传递参数:

<template>
  <button @click="show('A')">显示A</button>
  <button @click="show('B')">显示B</button>
  <component :is="currentComp" v-bind="compProps" />
</template>

<script setup>
import { ref } from 'vue'
import { defineAsyncComponent } from 'vue'

const currentComp = ref(null)
const compProps = ref({ msg: '默认消息' })

function show(type) {
  if (type === 'A') {
    currentComp.value = defineAsyncComponent(() => import('./CompA.vue'))
    compProps.value = { msg: '这是A组件的消息' }
  } else if (type === 'B') {
    currentComp.value = defineAsyncComponent(() => import('./CompB.vue'))
    compProps.value = { msg: '这是B组件的消息' }
  }
}
</script>

CompA.vue/CompB.vue

<template>
  <div>{{ msg }}</div>
</template>
<script setup>
defineProps(['msg'])
</script>

7. 动态 import 组件并绑定事件

可以通过 v-on 绑定事件到动态组件:

<template>
  <component
    :is="currentComp"
    v-bind="compProps"
    v-on="compEvents"
  />
</template>

<script setup>
import { ref } from 'vue'
import { defineAsyncComponent } from 'vue'

const currentComp = ref(null)
const compProps = ref({})
const compEvents = ref({
  click: (val) => console.log('子组件点击', val)
})

function showA() {
  currentComp.value = defineAsyncComponent(() => import('./CompA.vue'))
  compProps.value = { msg: 'A消息' }
}
</script>

8. 动态 import 组件 + 缓存(keep-alive)

有些场景需要缓存已加载的组件状态:

<template>
  <keep-alive>
    <component :is="currentComp" v-bind="compProps" />
  </keep-alive>
</template>

9. 批量管理动态组件(组件注册表)

当有很多可动态加载的组件时,可以用对象批量管理:

<script setup>
import { defineAsyncComponent, ref } from 'vue'

const compMap = {
  A: defineAsyncComponent(() => import('./CompA.vue')),
  B: defineAsyncComponent(() => import('./CompB.vue')),
  C: defineAsyncComponent(() => import('./CompC.vue'))
}
const current = ref('A')
</script>

<template>
  <button @click="current = 'A'">A</button>
  <button @click="current = 'B'">B</button>
  <button @click="current = 'C'">C</button>
  <component :is="compMap[current]" />
</template>

10. 动态 import 组件的 loading/error/超时处理

可以配置 loading/error 组件、延迟和超时:

<code>import { defineAsyncComponent } from 'vue'
import LoadingComp from './LoadingComp.vue'
import ErrorComp from './ErrorComp.vue'

const AsyncA = defineAsyncComponent({
  loader: () => import('./CompA.vue'),
  loadingComponent: LoadingComp,
  errorComponent: ErrorComp,
  delay: 200,
  timeout: 3000
})
</code>

11. 动态 import 组件的实际业务场景

12. 动态 import 组件的性能优化建议

13. 动态 import 组件的完整案例(汇总)

<template>
  <div>
    <button @click="show('A')">A</button>
    <button @click="show('B')">B</button>
    <keep-alive>
      <component
        :is="currentComp"
        v-bind="compProps"
        v-on="compEvents"
      />
    </keep-alive>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { defineAsyncComponent } from 'vue'

const currentComp = ref(null)
const compProps = ref({})
const compEvents = ref({
  click: (val) => console.log('事件', val)
})

function show(type) {
  if (type === 'A') {
    currentComp.value = defineAsyncComponent(() => import('./CompA.vue'))
    compProps.value = { msg: 'A消息' }
  } else if (type === 'B') {
    currentComp.value = defineAsyncComponent(() => import('./CompB.vue'))
    compProps.value = { msg: 'B消息' }
  }
}
</script>

总结 

到此这篇关于VUE如何实现前端组件式开发和动态装载的文章就介绍到这了,更多相关VUE前端组件式开发和动态装载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文