写点什么

Vue 的动态组件 & 异步组件

作者:编程江湖
  • 2022 年 1 月 10 日
  • 本文字数:4241 字

    阅读完需:约 14 分钟

什么是动态组件?

还是发挥一下语文阅读理解能力,动态组件,应该指的就是动态变化的组件,而不是固定写死的,不知道我的理解准不准确,来先一起看看官方的解释!

通过<component> 标签声明一块区域,并预言这块区域将来会被某个组件通过 v-bind:is='componentId' 来填充。

这段话有点抽象,但是我们可以大胆的猜测一下,应该意思是通过<component :is="componentId"></component> 提前定义一个区块,然后注册组件的时候动态注册绑定,到底是不是这样呢?

我们还是老规矩,翠花上代码!

    <div id="app">        <button @click="onChangeComponentClick(1)">To ComponentA</button>        <button @click="onChangeComponentClick(2)">To ComponentB</button>        <button @click="onChangeComponentClick(3)">To ComponentC</button>        <!-- 声明的区域 -->        <component :is="componentId"></component>    </div>        <!-- 定义组件模板内容 -->    <template id="component-a">      <div>component-a</div>    </template>        <template id="component-b">      <div>component-b</div>    </template>        <template id="component-c">      <div>component-c</div>    </template>        <script type="text/javascript">      // 注册组件A/B/C      var commponentA = {        template: "#component-a"      }            var commponentB = {        template: "#component-b"      }            var commponentC = {        template: "#component-c"      }            var vm = new Vue({        el: "#app",        data:function(){          return {            componentId: commponentA          }        },                methods:{          // 通过一个点击事件传入不同的值,判断动态区块要挂载的组件          onChangeComponentClick: function(type){            switch (type) {              case 1:                this.componentId = commponentA;              break;              case 2:                this.componentId = commponentB;              break;              case 3:                this.componentId = commponentC;              break;                          }          },        }      });          </script>
复制代码

我们看上面的这段代码,首先声明了三个变量 componentAcomponentBcomponentC 并为它们指定了 template,在 new Vue 里面指定了 componentId 初始值为 componentA前端培训然后在 html 里面通过 <component> 声明了一块区域,并通过 :is="componentId"绑定了 componentId,意为当前的 <component>将会被 componentId渲染。此时代码运行之后的结果为:

<div id="app">    <div>component-a</div></div>复制代码
复制代码

componentAtemplate 替换掉了通过 <component> 声明的区域。然后通过 onChangeComponentClick 方法来变更 componentId 的指向,当 componentId的指向发生改变的时候,渲染的内容也随之发生改变。

这样一种通过<component> 来声明区域,通过v-bind:is来绑定组件(componentId),然后通过改变组件(componentId)指向来更改展示内容的方式就可以称为动态组件。

如果亲自运行一下上面的代码,就会发现一个问题,那就是在我们每次去切换 component 的时候,在浏览器的控制台中总会去弹出这么一些内容:



这表示当我们每次去切换 component 的时候,模板(component 中的 template)总会去重新渲染,而我们知道每次的 DOM 渲染其实是很消耗性能的操作,那么如果想要避免这样反复渲染的话可以通过 <keep-alive> 标签来告诉Vue,去缓存已经被渲染过的 component

<keep-alive> 的使用非常简单,只需要使用 <keep-alive>来包裹住 <component :is="componentId"></component> 就可以了。代码如下:

<keep-alive>    <component :is="componentId"></component></keep-alive>复制代码
复制代码

什么是异步组件?

举个生活中常见的现象来看什么是异步:你烧水,不等水烧开就去刷牙了,水烧开了会发出声音告诉你,然后你再处理水烧开之后的事情!看完这个再去理解官方的解释有点豁然开朗了!

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。

所以,由此可以看出,异步加载最重要的一个功能就是可以加快页面访问速度,比如我们可以把一些非首屏的页面做成异步加载

定义异步组件

老规矩翠花,上代码:

  <div id="app">    <async-example></async-example>  </div>    <template id="async-example">    <div>      我是一个异步组件    </div>  </template>     <script type="text/javascript">    // 注册组件    var resCom = {      template: "#async-example"    }        Vue.component('async-example', function(resolve, reject){      setTimeout(function(){        // 向resolve回调传递组件定义        resolve(resCom);      }, 1000);    });        var vm = new Vue({      el: "#app"    })  </script>    复制代码
复制代码

在上面的这段代码中,首先声明了一个变量 resCom,并给它指定了一个 template指向 async-example,这和声明局部组件时所进行的操作是一致的。

然后通过 Vue.component('async-example', function (resolve, reject){}来创建了一个工厂函数,这个函数包含resolvereject 两个参数。前端培训这两个参数表示两个回调方法,我们可以通过 resolve(resCom) 使程序去异步加载定义的 resCom 组件,也可以使用 reject('加载失败描述内容'); 来表示加载失败。这里的 setTimeout 仅作为模拟异步操作使用的。当然上面的代码也可以通过局部组件的方式使用:

var vm = new Vue({    el: '#app',    components: {        'async-example': function (resolve, reject) {            setTimeout(function () {                resolve(resCom);                // reject('加载失败描述内容');            }, 1000);        }    }});复制代码
复制代码

如果大家对 Promise 比较熟悉的话,可以发现这种写法 function (resolve, reject){...}像极了一个 Promise的定义。在 Vue 中一样也可以通过 Promise 的方式来定义异步组件,这也是定义异步组件的第二种方式 Promise。

把上面的代码略作修改来看:

// 注册组件    var resCom = {      template: "#async-example"    };        var promise = new Promise(function(resolve, reject){      setTimeout(function(){        resolve(resCom)      }, 1000);    });        // Vue.component('async-example', function(resolve, reject){    //   setTimeout(function(){    //     // 向resolve回调传递组件定义    //     resolve(resCom);    //   }, 1000);    // });        var vm = new Vue({      el: "#app",      components:{        'async-example':function(){          return promise        }      }    })复制代码
复制代码

在上面的代码中我们声明了一个 Promise,具体的写法与标准方式相同,然后在注册这个异步组件时,直接 return 回这个 Promise 即可。

我们在前面说过Webpack + Vue-CLI是 Vue 所推崇的一种构建方式,同时 Webpack 也直接内建支持这种 Promise 的异步组件注册方式。当使用 Webpack 来构建正式项目时,我们也可以直接通过 import('./my-async-component')来注册一个异步组件,import('./my-async-component') 会直接返回一个 Promise。

// 全局注册Vue.component(  'async-webpack-example',  // 这个 `import` 函数会返回一个 `Promise` 对象。  () => import('./my-async-component'))
// 局部注册new Vue({ // ... components: { 'my-component': () => import('./my-async-component') }}) 复制代码
复制代码

最后一种异步注册的方式,我们称它为高级异步组件,这种方式是在 Vue2.3.0 新增的一种异步组件注册方式。看一下高级异步组件应该如何定义:

  <script type="text/javascript">    // 注册组件    var resCom = {      template: "#async-example"    };        var promise = new Promise(function(resolve, reject){      setTimeout(function(){        resolve(resCom)      }, 2000);    });        var LoadingComponent = {      template: '<div>加载中显示的组件</div>'    };    var ErrorComponent = {      template: '<div>异步组件加载失败</div>'    };    // Vue.component('async-example', function(resolve, reject){    //   setTimeout(function(){    //     // 向resolve回调传递组件定义    //     resolve(resCom);    //   }, 1000);    // });        const AsyncComponent = function(){      return {        // 需要加载的组件 (应该是一个 `Promise` 对象)        component: promise,        // 异步组件加载时使用的组件        loading: LoadingComponent,        // 加载失败时使用的组件        error: ErrorComponent,        // 展示加载时组件的延时时间。默认值是 200 (毫秒)        delay: 200,        // 如果提供了超时时间且组件加载也超时了,        // 则使用加载失败时使用的组件。默认值是:`Infinity`        // PS: 组件加载超时时间,超时表示加载失败,会展示ErrorComponent。        // 比如在这里当我们把 Promise 中的 setTimeout 改为 4000的时候,则会展示 ErrorComponent        timeout: 3000      }    }        var vm = new Vue({      el: "#app",      // 注意这里与之前的写法不同之处,是因为我们把这个方法提出去赋值给了AsyncComponent的变量      components:{        'async-example': AsyncComponent      }    })  </script> 复制代码
复制代码

可以看到高级异步组件的配置更加全面,在逻辑上反而会比前两种异步组件的配置方式更加简单,所以在实际的项目使用中,我们也更加推崇使用高级异步组件的方式来定义异步组件。

用户头像

编程江湖

关注

IT技术分享 2021.11.23 加入

还未添加个人简介

评论

发布
暂无评论
Vue的动态组件 & 异步组件