||

Vue单页面项目中的组件和路由懒加载

一个略有规模的前端项目,或者页面内容比较多,但不需要组件同时显示的这类应用,都可以使用 懒加载 的方式将不用立刻显示的路由或者组件异步加载,这样做的目的是提高用户首次加载页面的速度,增强用户体验。

路由懒加载

由于 Vue 中的 Router 也是通过组件来控制的,所以路由懒加载本身还是异步组件问题,所以全部按照异步组件处理即可。

在 Vue 中,官方提供的异步组件需要返回 Promise ,按照这个要求我们在使用时可以手动返回 Promise 对象,或者通过 Webpack 支持的 ES6 中 import() 来返回 Promise 。

异步组件

Vue 中对异步组件的介绍:

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

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

可以看到异步组件是用过组件工厂函数来异步处理的,使用场景有两种,如果是基于 Webpack 构建的 Vue 项目,那么异步组件可以被分割成代码块分别输出,然后在需要的时候再通过异步加载的方式载入。

例如:

export default {
  components: {
    HelloWorld: resolve => (require(["@/components/HelloWorld.vue"], resolve))
  }
}

或者写一个定时器来模拟,HelloWorld 组件将在 3 秒加载。

export default {
  name: 'Home',
  components: {
    HelloWorld: resolve => (
      setTimeout(() => {
        require(["@/components/HelloWorld.vue"], resolve)
      }, 3000)
    )
  }
}

以这种方式打包后,页面初次启动时将不会显示 HelloWorld 组件,大约 3 秒后,浏览器想服务器发起一个请求,获取 HelloWorld 组件的定义,之后在页面中渲染并显示出来。

使用 import()

使用 import() 将使得上述方法变得简单,Webpack 完全可以处理 import() ,并将其打包为不同的 chunk ,使用如下:

export default {
  name: 'Home',
  components: {
    HelloWorld: () => import( "@/components/HelloWorld.vue")
  }
}

在 Router 中可以直接 import 需要异步加载的组件:

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]

由于异步组件和懒加载的路由都需要返回一个 Promise ,所以使用 require 返回 Promise 也是可以的:

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: resolve => (require(["../views/About.vue"], resolve))
  }
]

引申:异步组件的切换

某些情况下,我们需要在页面中按需切换一个组件,不过这个组件可能是异步组件,应该怎么实现?

以用户的单击事件为例,借助 is 属性绑定组件名称的特征,可以这样做:

export default {
  components: {
    Hardware: () => import( "@/components/Hardware.vue"),
    Software: () => import( "@/components/Software.vue")
  },
  methods: {
    onClick(name, propData) {
      this.propData = propData;
      this.componentName = name;
    }
  }
}

组件模板:

<template slot-scope="scope">
    <component 
      :is="componentName" 
      :prop-data="propData" 
    ></component>
    <button @click="onClick('Hardware', 'somedata')"> Hardware </button>
    <button @click="onClick('Software', 'somedata')"> Software </button>
</template>

以上,通过点击 button 就可以切换组件,而组件会异步加载。

引申:异步组件通讯

上面异步组件切换其实也包含了部分组件通讯,异步组件可以像普通组件那样通 props 属性像其传值,也可以通过监听子组件的事件来实现子组件像父组件传值。

<template slot-scope="scope">
    <component 
      :is="componentName" 
      :prop-data="propData" 
      @onEvent="onComponentEvent"
    ></component>
    <button @click="onClick('Hardware', 'somedata')"> Hardware </button>
    <button @click="onClick('Software', 'somedata')"> Software </button>
</template>

添加事件监听:

export default {
  ...
  methods: {
    onComponentEvent(...params) {
      // 处理异步组件传递过来的数据
    }
  }
}

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注