单页应用( SPA )的初始加载速度很慢,有时会有点笨拙。这是因为传统上,服务器将向客户端发送大量的 JavaScript,在屏幕上显示任何内容之前,必须先下载和加载这些代码。正如你所能想象的,随着你的应用规模的增长,这会变得越来越有问题。
幸运的是,当使用 Vue CLI (底层使用了 Webpack )构建 Vue 应用程序时,可以采取许多措施来避免这种情况。在本文中,我将演示如何利用异步组件和 Webpack 的代码拆分功能在应用程序初始化渲染后仅加载页面的一部分内容。这将使初始加载时间保持在最小值,并使你的应用程序运行起来感觉更加快速。
至此之前,你需要对 vue.js 和 node.js 有一个基本的了解。
在开始创建异步组件之前,让我们先看看我们平时如何加载组件。为此,我们将使用一个非常简单的消息组件:
<!-- Message.vue -->
<template>
<h1>New message!</h1>
</template>
现在我们已经创建了组件,让我们将其加载到 app.vue 文件中并显示它。我们只需导入组件并将其添加到组件选项,以便在模板中使用它:
<!-- App.vue -->
<template>
<div>
<message></message>
</div>
</template>
<script>
import Message from "./Message";
export default {
components: {
Message
}
};
</script>
但这样带来了什么?每当加载应用程序时,都会加载消息组件,于是它包含在初始化加载中。
对于一个简单的应用程序来说,这可能不是一个大问题,但是考虑一些更复杂的东西,比如一个网络商店。假设用户将项目添加到一个购物篮中,然后希望签出,因此单击“签出”按钮,该按钮将呈现一个包含所选项目所有详细信息的包。如果使用上面的方法,签出相关组件也将包含在这个包中,尽管我们只需要在用户点击签出按钮时调用签出相关的组件。甚至有可能用户不用点击签出按钮就可以浏览网站,这也就意味着加载这个有可能不会被用到的组件是没有意义的的。
为了提高应用程序的效率,我们可以将延迟加载和代码拆分技术结合起来。
延迟加载就是延迟组件的初始加载。你可以在 medium.com 这样的网站上看到懒加载的操作,在那里图片恰恰在需要之时才被加载。这是很有用的,因为我们不必浪费资源来预先加载所有的内容,因为读者可能会开始看的时候就跳过这篇文章的一半。
Webpack 提供的代码拆分功能允许您将代码拆分为各种捆绑包( bundles ),然后可以按需或在以后的时间点并行加载。它只能用于在需要或使用特定代码时加载它们。
Vue 中提供一个称之为动态导入的功能用来满足这样的场景。此功能引入了一种方法函数的形式,它将返回包含请求的 promise。因为 import 是一个接收类型是字符串的方法,所以我们可以做一些功能强大的事情,比如使用表达式加载模块。从 Chrome 的 61 版本开始,动态导入被支持。更多关于它们的信息可以在谷歌开发者网站上找到。
代码拆分可以由 Webpack、Rollup 或 Parcel 等绑定程序完成,它们支持动态导入语法,并可以为每个动态导入的模块创建单独的文件。稍后我们将在 F12 控制台的“ network ”选项中看到这一点。但首先,让我们看看静态导入和动态导入之间的区别:
// static import
import Message from "./Message";
// dynamic import
import("./Message").then(Message => {
// Message module is available here...
});
现在,让我们将上述功能应用到我们的消息组件中,我们将得到一个 app.vue 组件,如下所示:
<!-- App.vue -->
<template>
<div>
<message></message>
</div>
</template>
<script>
import Message from "./Message";
export default {
components: {
Message: () => import("./Message")
}
};
</script>
如您所见,import ()函数将解决返回组件的 promise,这意味着我们已经成功地异步加载了组件。如果您 F12 查看控制台的网络项,您会注意到一个名为 0.js 的文件,其中包含这个异步组件。
既然我们已经知道了异步组件的处理方法,那么我们只需要在真正需要的时候加载它们,从而发挥他们的功能。在本文的前面章节中,举了一个只有当用户点击签出按钮时才加载的签出框的例子。现在让我们来实现这样一个例子。
如果您没有安装 Vue CLI,参考下面代码进行安装:
npm i -g @vue/cli
接下来,使用 CLI 创建一个新项目,并在出现提示时选择默认设置:
vue create my-store
之后进入项目目录,然后安装 Ant Design Vue 库
cd my-store
npm i ant-design-vue
接下来,在 src/main.js 中引入 Ant Design 相关 CSS:
import 'ant-design-vue/dist/antd.css'
最后,在 src/comonents 中创建两个组件 checkout.vue 和 items.vue:
touch src/components/{Checkout.vue,Items.vue}
打开 src/app.vue 并用以下代码替换其中的代码:
<template>
<div id="app">
<h1>{{ msg }}</h1>
<items></items>
</div>
</template>
<script>
import items from "./components/Items"
export default {
components: {
items
},
name: 'app',
data () {
return {
msg: 'My Fancy T-Shirt Store'
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
我们所要做的就是显示一条消息并呈现一个<items>组件。
接下来,打开 src/components/items.vue 并添加以下代码:
<template>
<div>
<div style="padding: 20px;">
<Row :gutter="16">
<Col :span="24" style="padding:5px">
<Icon type="shopping-cart" style="margin-right:5px"/>{{shoppingList.length}} item(s)
<Button @click="show = true" id="checkout">Checkout</Button>
</Col>
</Row>
</div>
<div v-if="show">
<Row :gutter="16" style="margin:0 400px 50px 400px">
<checkout v-bind:shoppingList="shoppingList"></checkout>
</Row>
</div>
<div style="background-color: #ececec; padding: 20px;">
<Row :gutter="16">
<Col :span="6" v-for="(item, key) in items" v-bind:key="key" style="padding:5px">
<Card v-bind:title="item.msg" v-bind:key="key">
<Button type="primary" @click="addItem(key)">Buy ${{item.price}}</Button>
</Card>
</Col>
</Row>
</div>
</div>
</template>
<script>
import { Card, Col, Row, Button, Icon } from 'ant-design-vue';
export default {
methods: {
addItem (key) {
if(!this.shoppingList.includes(key)) {
this.shoppingList.push(key);
}
}
},
components: {
Card, Col, Row, Button, Icon,
checkout: () => import('./Checkout')
},
data: () => ({
items: [
{ msg: 'First Product', price: 9.99 },
{ msg: 'Second Product', price: 19.99 },
{ msg: 'Third Product', price: 15.00 },
{ msg: 'Fancy Shirt', price: 137.00 },
{ msg: 'More Fancy', price: 109.99 },
{ msg: 'Extreme', price: 3.00 },
{ msg: 'Super Shirt', price: 109.99 },
{ msg: 'Epic Shirt', price: 3.00 },
],
shoppingList: [],
show: false
})
}
</script>
<style>
#checkout {
background-color:#e55242;
color:white;
margin-left: 10px;
}
</style>
我们将显示一个购物车图标,其中包含当前购买的商品数量。商品本身是从数组中提取的。如果单击某个项目的“ Buy ”按钮,将调用 additem 方法,该方法会将商品相关内容推送到 ShoppingList 数组中。继而增加购物车的总数。
我们还向页面添加了一个签出按钮
<Button @click="show = true" id="checkout">Checkout</Button>
接下来事情开始变得有趣起来,当用户单击此按钮时,我们将参数 show 设置为 true。这个布尔值对于有条件地加载异步组件非常重要。
下面几行,您可以找到一个 v-if 语句,当 show 设置为 true 时,它只显示<div>的内容。这个<div>标签包含 checkout 组件,只有在用户点击"Checkout"按钮时才加载它。
checkout 组件在<script>中异步加载。更牛的是,我们甚至可以通过 v-bind 语句将参数传递给组件。综上所述,我们可以很容易的创建一个带有条件的异步组件。
<div v-if="show">
<checkout v-bind:shoppingList="shoppingList"></checkout>
</div>
让我们快速在 src/component s/checkout.vue 中添加签出组件的代码:
<template>
<Card title="Checkout Items" key="checkout">
<p v-for="(k, i) in this.shoppingList" :key="i">
Item: {{items[Number(k)].msg}} for ${{items[Number(k)].price}}
</p>
</Card>
</template>
<script>
import { Card } from 'ant-design-vue';
export default {
props: ['shoppingList'],
components: {
Card
},
data: () => ({
items: [
{ msg: 'First Product', price: 9.99 },
{ msg: 'Second Product', price: 19.99 },
{ msg: 'Third Product', price: 15.00 },
{ msg: 'Fancy Shirt', price: 137.00 },
{ msg: 'More Fancy', price: 109.99 },
{ msg: 'Extreme', price: 3.00 },
{ msg: 'Super Shirt', price: 109.99 },
{ msg: 'Epic Shirt', price: 3.00 },
]
})
}
</script>
这里,我们循环 shoppingList 的内容输出到屏幕上。
F12 打开控制台“ network ”选项的情况下在商店周围单击,以确保仅在单击“ Checkout ”按钮时才加载 Checkout 组件。
我们甚至可以定义一个错误组件,当异步组件需要一些时间来加载或无法加载时进行显示。加载动画是一个非常实用的应用场景,但请记住,这会再次减慢应用程序的速度。异步组件应该小而快速地加载。下面是一个例子:
const Message = () => ({
component: import("./Message"),
loading: LoadingAnimation,
error: ErrorComponent
});
创建和实现异步组件非常简单,这应该是开发流程的一部分。从用户体验的角度来看,尽可能减少初始加载时间以保持用户的吸引力是很重要的。希望本教程能够帮助您实现异步加载自己的组件,并找到他们合适的实际使用场景。
1
powertoolsteam OP 本文由葡萄城进行翻译,原文地址: https://www.sitepoint.com/vue-async-components/ 转载请注明出处:葡萄城官网( https://www.grapecity.com.cn/developer ),葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
|
2
strugglexiang 2019-04-25 08:48:14 +08:00 via Android
已阅
|
3
meepo3927 2019-04-25 11:53:06 +08:00
|