Vue中的动态组件和异步组件

1.动态组件

1.1 动态组件的用法

如果在开发过程中想要实现动态组件,比如在不同的条件下显示不同的组件,可以使用<component>标签结合:is属性。

定义组件:
假设你有两个组件:ComponentA.vueComponentB.vue

//ComponentA.vue
<template>
  <div>这是组件A</div>
</template>
 
<script>
export default {
  name: 'ComponentA'
}
</script>

//ComponentB.vue
<template>
  <div>这是组件B</div>
</template>
 
<script>
export default {
  name: 'ComponentB'
}
</script>

使用动态组件:
在父组件中,你可以这样使用<component :is="currentComponent">来动态切换组件。

//ParentComponent.vue
<template>
  <div>
    <button @click="changeComponent('ComponentA')">切换到组件A</button>
    <button @click="changeComponent('ComponentB')">切换到组件B</button>
    <component :is="currentComponent"></component>
  </div>
</template>
 
<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
 
export default {
  data() {
    return {
      currentComponent: 'ComponentA' // 默认显示ComponentA
    }
  },
  methods: {
    changeComponent(componentName) {
      this.currentComponent = componentName; // 切换组件名称
    }
  },
  components: {
    ComponentA,
    ComponentB
  }
}
</script>

1.2 is属性的其他作用

有些 HTML 元素,诸如<ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

<table>
  <blog-post-row></blog-post-row>
</table>

这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is attribute 给了我们一个变通的办法:

<table>
  <tr is="blog-post-row"></tr>
</table>

2.异步组件

2.1 什么是异步组件

当我们的项目达到一定的规模时,对于某些组件来说,我们并不希望一开始全部加载,而是需要的时候进行加载。这样做可以很好的提高用户体验,加快页面的载入速度,为此Vue 提供了异步组件的性能优化方案。

Vue 异步组件:是指通过异步方式加载的组件。

2.2 组件的加载 VS 组件渲染

  • 组件加载:是组件的引入和注册,不走组件的生命周期函数
  • 组件渲染:是生成组件实例的过程,走生命周期函数

2.3 异步组件的注册

(1)基础使用

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。

(2)require引入组件

异步组件和webpackcode-splitting功能一起配合使用:

Vue.component('async-webpack-example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack
  // 自动将你的构建代码切割成多个包,这些包
  // 会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})

(3)import引入组件

你也可以在工厂函数中返回一个 Promiseimport()会返回一个 Promise

Vue.component(
  'async-webpack-example',
  // 这个动态导入会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

(4)局部注册

//vue文件中

components: {
  // 方式一: import
  AsyncComponent: () => import("./components/asyncComponent.vue"),

  // 方式二: require
  AsyncComponent: (resolve) => require(["./components/asyncComponent.vue"], resolve),
},

2.4 处理加载状态

const AsyncComponent = () => ({
  // 需要加载的组件 (应该是一个 `Promise` 对象)
  component: import('./MyComponent.vue'),
  // 异步组件加载时使用的组件
  loading: LoadingComponent,
  // 加载失败时使用的组件
  error: ErrorComponent,
  // 展示加载时组件的延时时间。默认值是 200 (毫秒)
  delay: 200,
  // 如果提供了超时时间且组件加载也超时了,
  // 则使用加载失败时使用的组件。默认值是:`Infinity`
  timeout: 3000
})

全局注册:

Vue.component('async-webpack-example', AsyncComponent)

局部注册:

components: {
  AsyncComponent: AsyncComponent),
},

下面再来列举一个处理加载状态的详细例子来进行说明:

<template>
  <div class="index-area">
    <button @click="show=!show">点击</button>
    <div v-if="show">
      <asyncCompsList></asyncCompsList>
    </div>
  </div>
</template>

<script>
import loadingComp from "@/components/asyncComps/loading.vue";
import errorComp from "@/components/asyncComps/error.vue";
const asyncCompsList = () => ({
  component: import(/* webpackChunkName: 'asyncCompsList' */"@/components/asyncComps/list.vue"),
  loading:loadingComp,
  error:errorComp,
  delay:200,
  timeout:3000,
})
export default {
  name: "index",
  components: {
    //这里注释掉,用下面那种方法可以处理加载状态
    // list:()=>import(/* webpackChunkName: 'asyncCompsList' */"@/components/asyncComps/list.vue")
    asyncCompsList
  },
  data() {
    return {
      show: false,
    }
  }
}
</script>
<style scoped>
</style>

2.5 异步组件 VS 普通组件

  • 异步组件: 只有在template模板使用的时候,才会加载和渲染组件
  • 同步组件: 在引入和注册的时候已经加载完成组件,在template模板使用的时候,开始渲染组件

下面来看一个例子:
如下,在App.vue主页面中、分别用同步和异步的方式引入组件syncComponentasyncComponent,点击按钮可以控制两个组件的渲染:

//App.vue
<template>
  <div id="app">
    <button @click="shwoAsync = true">展示异步组件</button>
    <button @click="shwoSync = true">展示同步组件</button>
    <!-- 异步组件 -->
    <AsyncComponent v-if="shwoAsync" />
    <!-- 同步组件 -->
    <SyncComponent v-if="shwoSync" />
  </div>
</template>

<script>
import SyncComponent from "./components/syncComponent.vue";
export default {
  name: "App",
  components: {
    AsyncComponent: () => import("./components/asyncComponent.vue"),
    SyncComponent,
  },
  data() {
    return {
      // 是否展示异步组件
      shwoAsync: false,
      // 是否展示同步组件
      shwoSync: false,
    };
  },
};
</script>

asyncComponent异步组件内容如下:

<script>
/*
 * 异步组件:当第一次切换到当前组件时候,才会去后台请求异步组件渲染函数,请求完了之后,
 * 下面这句代码才会执行,然后根据这个渲染函数创建组件实例
 */
console.log("异步组件加载----");
export default {
  name: "AsyncComponent",
};
</script>

syncComponent同步组件内容如下:

<script>
/* 这个在没有渲染到该组件时, 就已经被引入执行了,只会执行一次 */
console.log("同步组件加载----");
export default {
  name: "syncComponent",
};
</script>

运行项目,打开控制台,在进入App.vue的时候、同步组件syncComponent的js代码已经开始执行。
在这里插入图片描述
但是,只有点击展示异步组件按钮的时候,异步组件的js代码才开始执行。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值