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 相关文章推荐
JS解析XML的实现代码
Nov 12 Javascript
js验证电话号码与手机支持+86的正则表达式
Jan 23 Javascript
createTextRange()的使用示例含文本框选中部分文字内容
Feb 24 Javascript
JS实现图片上传预览功能
Nov 21 Javascript
JS实现的样式切换功能tableCSS实例
Dec 30 Javascript
Vue仿支付宝支付功能
May 25 Javascript
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
Oct 18 Javascript
JS高阶函数原理与用法实例分析
Jan 15 Javascript
微信小程序实现bindtap等事件传参
Apr 08 Javascript
如何检测JavaScript中的死循环示例详解
Aug 30 Javascript
解决iview table组件里的 固定列 表格不自适应的问题
Nov 13 Javascript
使用Cargo工具高效创建Rust项目
Aug 14 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
使用php统计字符串中中英文字符的个数
2013/06/23 PHP
修改ThinkPHP缓存为Memcache的方法
2014/06/25 PHP
PHP微信支付开发实例
2016/06/22 PHP
PHP实现类似于C语言的文件读取及解析功能
2017/09/01 PHP
PHP设计模式之装饰器模式定义与用法详解
2018/04/02 PHP
PHP设计模式之观察者模式定义与用法分析
2019/04/04 PHP
浅析PHP反序列化中过滤函数使用不当导致的对象注入问题
2020/02/15 PHP
javascript 对象比较实现代码
2009/04/27 Javascript
IE6-IE9不支持table.innerHTML的解决方法分享
2012/09/14 Javascript
jQuery插件开发全解析
2012/10/10 Javascript
js的延迟执行问题分析
2014/06/23 Javascript
js在IE与firefox的差异集锦
2014/11/11 Javascript
Javascript验证方法大全
2015/09/21 Javascript
JS基于Ajax实现的网页Loading效果代码
2015/10/27 Javascript
实例详解jQuery Mockjax 插件模拟 Ajax 请求
2016/01/12 Javascript
JavaScript中解决多浏览器兼容性23个问题的快速解决方法
2016/05/19 Javascript
微信小程序使用checkbox显示多项选择框功能【附源码下载】
2017/12/11 Javascript
详解webpack-dev-server的简单使用
2018/04/02 Javascript
Node.js文件编码格式的转换的方法
2018/04/27 Javascript
浅谈ECMAScript 中的Array类型
2019/06/10 Javascript
[02:18]DOTA2英雄基础教程 育母蜘蛛
2014/01/20 DOTA
Python定时任务工具之APScheduler使用方式
2019/07/24 Python
python连接mysql有哪些方法
2020/06/24 Python
scrapy中如何设置应用cookies的方法(3种)
2020/09/22 Python
使用Python下载抖音各大V视频的思路详解
2021/02/06 Python
html5 postMessage解决跨域、跨窗口消息传递方案
2016/12/20 HTML / CSS
给民警的表扬信
2014/01/08 职场文书
结婚邀请函范文
2014/01/14 职场文书
家长给小学生的评语
2014/01/30 职场文书
深入开展党的群众路线教育实践活动心得体会
2014/11/05 职场文书
公司年会开场白
2015/06/01 职场文书
2015年教师个人业务工作总结
2015/10/23 职场文书
2016年感恩节寄语
2015/12/07 职场文书
小组组名及励志口号
2015/12/24 职场文书
vue-treeselect的基本用法以及解决点击无法出现拉下菜单
2022/04/30 Vue.js
mysql查找连续出现n次以上的数字
2022/05/11 MySQL