资讯专栏INFORMATION COLUMN

Vue.js 子组件的异步加载及其生命周期控制

lidashuang / 2389人阅读

摘要:本文主要对组件化开发中子组件的异步加载和其生命周期进行一些探讨。异步组件讨论异步加载,需要先了解下异步组件。生命周期控制在使用子组件或者叫局部注册时,我们可能需要在子组件实例化或者叫创建完毕后做某些事情。

前端开发社区的繁荣,造就了很多优秀的基于 MVVM 设计模式的框架,而组件化开发思想也越来越深入人心。这其中不得不提到 Vue.js 这个专注于 VM 层的框架。

本文主要对 Vue.js 组件化开发中子组件的异步加载和其生命周期进行一些探讨。阅读本文需要对 Vue.js 有一定的了解。

注意:本文中的一些例子代码,是以 vue-cli 采用 webpack 模板初始化的项目为基础。
异步组件

讨论异步加载,需要先了解下异步组件。Vue.js 的异步组件是把组件定义为一个工厂函数,在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。例如注册一个全局异步组件:

Vue.component("async-demo", function(resolve, reject) {
  setTimeout(function() {
    // 将组件定义传入 resolve 回调函数
    resolve({
      template: "
I am async!
"      // 组件的其他选项 }) }, 1000) })

异步子组件和全局注册很类似:

Vue.component("parent-demo", {
  // 父组件的其他选项
  components: {
    "async-demo": function(resolve, reject) {
      setTimeout(function() {
        // 将组件定义传入 resolve 回调函数
        resolve({
          template: "
I am async!
"          // 子组件的其他选项 }) }, 1000) } } })

工厂函数的第一个参数 resolve成功后的回调,第二个参数 reject失败后的回调,可以在这里提示用户加载失败等。

这里使用 setTimeout 只是为了模拟异步,在实际项目中,应该配合 webpack 的代码分离功能来实现异步加载。

异步加载

在实际的项目中,如果不使用异步加载,则 Vue.js 组件的 JS、CSS 和模板都会打包到一个 .js 文件中,这个文件可能达到几 MB 甚至更多,严重影响首屏加载时间。所以在项目中我们需要启用组件的异步加载。

webpack 代码分离

webpack 的代码分离有两种,第一种,也是优先选择的方式是,使用符合 ECMAScript 提案的 import() 语法。第二种,则是使用 webpack 特定的 require.ensure。让我们先看看第一种:

import() 调用会在内部用到 promises。如果在旧有版本浏览器中使用 import(),记得使用一个 polyfill 库(例如 es6-promise 或 promise-polyfill),来 shim Promise。
Vue.component(
  "async-demo",
  // 该 import 函数返回一个 Promise 对象。
  () => import("./async-demo")
)

上面的例子中,前文提到的工厂函数支持返回一个 Promise 对象,所以可以使用 import() 这种代码分离方式。

局部注册也是类似的:

Vue.component("parent-demo", {
  // 父组件的其他选项
  components: {
    "async-demo": () => import("./async-demo")
  }
})

本质上,import() 函数返回一个 Promise 实例,你可以自定义这个过程,下文会有说明。

第二种 webpack 代码分离是这样的:

Vue.component("async-demo", function(resolve) {
  require.ensure([], function(require) {
    resolve(require("./async-demo"))
  }, function(error) {
    // 加载出错执行这里
  })
})

看起来比较繁琐,如果你使用 webpack 2 及以上版本,则不建议使用第二种方式。

生命周期控制

在使用子组件(或者叫局部注册)时,我们可能需要在子组件实例化(或者叫创建完毕)后做某些事情。在非异步的子组件中,我们很容易做这件事:



上例中使用了 Vue.js 的子组件引用,所以可以在生命周期函数 mounted 中很方便的获取到子组件的实例,这样就可以在这个函数中处理一些子组件实例化后要做的事情。

但是在异步子组件中,mounted 函数中是无法获取到子组件的实例的,所以我们需要一些技巧来实现这个功能。



上例中,可以看到我们对组件异步加载做了一些特殊的控制,其中 import().then() 则是在加载完子组件的 .js 文件后,实例化子组件之前的回调,如果需要处理出错的情况,则 import().then().catch() 即可。

以上代码只是注入了一个 created 函数,如果要注入其他生命周期函数,例如 mounted,也是类似的:



通过上面的讨论,我们可以做到完全控制 Vue.js 组件的异步加载的全过程,这对于需要精确控制子组件加载的组件,会有很大的帮助。

演示项目

根据上面的思路,写了一个基于 Bootstrap 的异步弹窗演示项目:

https://github.com/hex-ci/vue...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92126.html

相关文章

  • vue面试

    摘要:虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器,当需要在数据变化时执行异步或开销较大的操作时,通过侦听器最有用。路由的钩子函数首页可以控制导航跳转,,等,一般用于页面的修改。 谈谈你对MVVM开发模式的理解 MVVM分为Model、View、ViewModel三者。Model 代表数据模型,数据和业务逻辑都在Model层中定义;View 代表UI视图,负责数据的展示;...

    vspiders 评论0 收藏0
  • Vue面试中,经常会被问到面试题/Vue知识点整理

    摘要:可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。我工作中只用到,对和不怎么熟与的区别相同点都支持指令内置指令和自定义指令都支持过滤器内置过滤器和自定义过滤器都支持双向数据绑定都不支持低端浏览器。 看看面试题,只是为了查漏补缺,看看自己那些方面还不懂。切记不要以为背了面试题,就万事大吉了,最好是理解背后的原理,这样面试的时候才能侃侃而谈。不然,稍微有水平的面试官一看就能看出,是...

    mengbo 评论0 收藏0
  • Vue面试中,经常会被问到面试题/知识点(2019改进版)

    摘要:在第一版的基础上进行了优化,新增一些面试题知识点,对一些知识点进行更加深入的描述。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。改变中的状态的唯一途径就是显式地提交。这两个可以在不进行刷新的情况下,操作浏览器的历史纪录。 在第一版的基础上进行了优化,新增一些面试题/知识点,对一些知识点进行更加深入的描述。 一、对于MVVM的理解? MVVM 是 Model-View-Vie...

    singerye 评论0 收藏0
  • VUE知识点集锦

    摘要:载入前后在阶段,实例的和都初始化了,但还是挂载之前为虚拟的节点,还未替换。类似于,不同在于提交的是,而不是直接变更状态可以包含任意异步操作。 vue基础 1、 router 路由与 a 标签的区别:https://www.jianshu.com/p/34b...2、 VUE双向绑定的原理: 答:VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个...

    Tecode 评论0 收藏0
  • VUE知识点集锦

    摘要:载入前后在阶段,实例的和都初始化了,但还是挂载之前为虚拟的节点,还未替换。类似于,不同在于提交的是,而不是直接变更状态可以包含任意异步操作。 vue基础 1、 router 路由与 a 标签的区别:https://www.jianshu.com/p/34b...2、 VUE双向绑定的原理: 答:VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个...

    APICloud 评论0 收藏0

发表评论

0条评论

lidashuang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<