Vue动态组件与异步组件实例详解


Posted in Javascript onFebruary 23, 2019

本文实例讲述了Vue动态组件与异步组件。分享给大家供大家参考,具体如下:

1 在动态组件上使用 keep-alive

我们之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件:

<component v-bind:is="currentTabComponent"></component>

当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。例如我们来展开说一说这个多标签界面:

Vue动态组件与异步组件实例详解

你会注意到,如果你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent 实例。

重新创建动态组件的行为通常是非常有用的,但是在这个案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive> 元素将其动态组件包裹起来。

<!-- 失活的组件将会被缓存!-->
<keep-alive>
 <component v-bind:is="currentTabComponent"></component>
</keep-alive>

现在这个 Posts 标签保持了它的状态 (被选中的文章) 甚至当它未被渲染时也是如此。

html:

<div id="dynamic-component-demo">
  <button
      v-for="tab in tabs"
      v-bind:key="tab"
      v-bind:class="['tab-button',{active:currentTab === tab}]"
      v-on:click="currentTab = tab"
      >{{ tab }}
  </button>
  <keep-alive>
    <component
        v-bind:is="currentTabComponent"
        class="tab"></component>
  </keep-alive>
</div>

js:

Vue.component('tab-posts', {
  data: function () {
    return {
      posts: [
        {
          id: 1,
          title: '赶在618前夕,微信更新了两个支付与电商功能',
          content: '本周末,中国消费者即将迎来上半年最大的消费网购峰值,6月17日父亲节,6月18日端午节,也是京东、天猫等电商的618购物节。略微出人意料但又在情理之中的是,中国最大的社交平台微信,近日密集上线了两个与支付和电商相关的功能。'
        },
        {
          id: 2,
          title: '腾讯要花32亿收购《绝地求生》开发商10%股份',
          content: '目前腾讯和蓝洞已经接近达成协议,如果交易成功,腾讯将成为蓝洞的第二大股东。'
        },
        {
          id: 3,
          title: '这两个地球之眼是真的吗?形成原因至今仍是谜团',
          content: '一名俄罗斯男子乘坐直升机游览时,经过俄罗斯萨哈林岛(库页岛)时,看到一个巨大的坑洞。地球上坑坑洞洞很多,本该不用大惊小怪。但当飞机离得更近,换了个角度看这个坑时,他震惊了,这分明就是“地球的眼睛”。'
        }
      ],
      selectedPost: null
    }
  },
  template: `
    <div class="posts-tab">
      <ul class="posts-sidebar">
        <li
          v-for="post in posts"
          v-bind:key="post.id"
          v-bind:class="{selected:post === selectedPost}"
          v-on:click="selectedPost = post">
          {{ post.title }}
        </li>
      </ul>
      <div class="selected-post-container">
        <div
          v-if="selectedPost"
          class="selected-post">
          <h3>{{ selectedPost.title }}</h3>
          <div v-html="selectedPost.content"></div>
        </div>
        <strong v-else>
          请点击某个标签页
        </strong>
      </div>
    </div>
  `
});
Vue.component('tab-archive', {
  template: '<div>archive 页面</div>'
});
new Vue({
  el: '#dynamic-component-demo',
  data: {
    currentTab: 'Posts',
    tabs: ['Posts', 'Archive']
  },
  computed: {
    currentTabComponent: function () {
      return 'tab-' + this.currentTab.toLowerCase();
    }
  }
});

css:

.tab-button {
  padding: 6px 10px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  border: 1px solid #ccc;
  cursor: pointer;
  background: #f0f0f0;
  margin-bottom: -1px;
  margin-right: -1px;
}
.tab-button:hover {
  background: #e0e0e0;
}
.tab-button.active {
  background: #e0e0e0;
}
.tab {
  border: 1px solid #ccc;
  padding: 10px;
}
.posts-tab {
  display: flex;
}
.posts-sidebar {
  max-width: 40vw;
  margin: 0;
  padding: 0 10px 0 0;
  list-style-type: none;
  border-right: 1px solid #ccc;
}
.posts-sidebar li {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  cursor: pointer;
}
.posts-sidebar li:hover {
  background: #eee;
}
.posts-sidebar li.selected {
  background: lightblue;
}
.selected-post-container {
  padding-left: 10px;
}
.selected-post > :first-child {
  margin-top: 0;
  padding-top: 0;
}

效果:

Vue动态组件与异步组件实例详解

2 异步组件

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

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    //在此定义组件
    resolve({
      template: `
        <div>
          我是异步加载的哦
        </div>
      `
    })
  }, 1000);
});

如你所见,这个工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能 一起配合使用:

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

你也可以在工厂函数中返回一个 Promise,所以把 webpack 2 和 ES2015 语法加在一起,我们可以写成这样:

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

当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:

new Vue({
 // ...
 components: {
  'my-component': () => import('./my-async-component')
 }
})

如果你是一个 Browserify 用户同时喜欢使用异步组件,很不幸这个工具的作者明确表示异步加载“并不会被 Browserify 支持”,至少官方不会。Browserify 社区已经找到了一些变通方案,这些方案可能会对已存在的复杂应用有帮助。对于其它的场景,我们推荐直接使用 webpack,以拥有内建的被作为第一公民的异步支持。

处理加载状态

2.3.0+ 新增

这里的异步组件工厂函数也可以返回一个如下格式的对象:

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

注意如果你希望在 Vue Router 的路由组件中使用上述语法的话,你必须使用 Vue Router 2.4.0+ 版本。

希望本文所述对大家vue.js程序设计有所帮助。

Javascript 相关文章推荐
谷歌浏览器 insertCell与appendChild的区别
Feb 12 Javascript
javascript中的new使用
Mar 20 Javascript
javascript正则表达式中参数g(全局)的作用
Nov 11 Javascript
jquery实现带复选框的表格行选中删除时高亮显示
Aug 01 Javascript
异步动态加载js与css文件的js代码
Sep 15 Javascript
JavaScript动态创建link标签到head里的方法
Dec 22 Javascript
JS Array创建及concat()split()slice()的使用方法
Jun 03 Javascript
浅谈react+es6+webpack的基础配置
Aug 09 Javascript
jQuery选择器之子元素选择器详解
Sep 18 jQuery
解析vue data不可以使用箭头函数问题
Jul 03 Javascript
详解.vue文件中style标签的几个标识符
Jul 17 Javascript
Nest.js参数校验和自定义返回数据格式详解
Mar 29 Javascript
详解单页面路由工程使用微信分享及二次分享解决方案
Feb 22 #Javascript
详解关于Vuex的action传入多个参数的问题
Feb 22 #Javascript
Vue.js实现开发购物车功能的方法详解
Feb 22 #Javascript
vue组件之间通信方式实例总结【8种方式】
Feb 22 #Javascript
vue2.0中set添加属性后视图不能更新的解决办法
Feb 22 #Javascript
浅谈Node框架接入ELK实践总结
Feb 22 #Javascript
vue工程全局设置ajax的等待动效的方法
Feb 22 #Javascript
You might like
POSIX 风格和兼容 Perl 风格两种正则表达式主要函数的类比(preg_match, preg_replace, ereg, ereg_replace)
2010/10/12 PHP
请离开include_once和require_once
2013/07/18 PHP
PHP5.6新增加的可变函数参数用法分析
2017/08/25 PHP
PHP实现文件上传后台处理脚本
2020/03/04 PHP
jQuery+CSS实现菜单滑动伸展收缩(仿淘宝)
2013/03/22 Javascript
JS返回上一页实例代码通过图片和按钮分别实现
2013/08/16 Javascript
利用javascript打开模态对话框(示例代码)
2014/01/11 Javascript
javascript基本类型详解
2014/11/28 Javascript
jQuery on方法传递参数示例
2014/12/09 Javascript
node.js中的fs.futimes方法使用说明
2014/12/17 Javascript
基于javascript实现样式清新图片轮播特效
2016/03/30 Javascript
js es6系列教程 - 新的类语法实战选项卡(详解)
2017/09/02 Javascript
canvas轨迹回放功能实现
2017/12/20 Javascript
Angular5中提取公共组件之radio list的实例代码
2018/07/10 Javascript
vue-router动态设置页面title的实例讲解
2018/08/30 Javascript
Vue指令指令大全
2019/02/09 Javascript
利用JavaScript将Excel转换为JSON示例代码
2019/06/14 Javascript
typescript nodejs 依赖注入实现方法代码详解
2019/07/21 NodeJs
layui checkbox默认选中,获取选中值,清空所有选中项的例子
2019/09/02 Javascript
详解基于Vue的支持数据双向绑定的select组件
2019/09/02 Javascript
d3.js实现图形拖拽
2019/12/19 Javascript
VUE中使用HTTP库Axios方法详解
2020/02/05 Javascript
[05:37]DOTA2-DPC中国联赛 正赛 Elephant vs iG 选手采访
2021/03/11 DOTA
基于Python和Scikit-Learn的机器学习探索
2017/10/16 Python
Python获取数据库数据并保存在excel表格中的方法
2019/06/12 Python
python使用requests.session模拟登录
2019/08/09 Python
Python unittest框架操作实例解析
2020/04/13 Python
tensorflow模型文件(ckpt)转pb文件的方法(不知道输出节点名)
2020/04/22 Python
Python爬虫入门有哪些基础知识点
2020/06/02 Python
用C或者C++语言实现SOCKET通信
2015/02/24 面试题
运动会入场词200字
2014/02/15 职场文书
企业精细化管理实施方案
2014/03/23 职场文书
老公保证书怎么写
2015/02/26 职场文书
党组织结对共建协议书
2016/03/23 职场文书
导游词之宁夏贺兰山岩画
2019/11/08 职场文书
Python 内置函数速查表一览
2021/06/02 Python