【vue学习】动态组件和异步组件

动态组件

image

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:

image

is

上述内容可以通过 Vue<component> 元素加一个特殊的 is 特性来实现

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

在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字,或
  • 一个组件的选项对象
  • component中绑定参数的方式和普通组件一样
    image
  • 解析 DOM 模板时的注意事项:有些 HTML 元素,诸如 <ul>、<ol>、<table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr><option>,只能出现在其它某些特定的元素内部。这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
<table>
  <blog-post-row></blog-post-row>
</table>
  • 这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:
<table>
  <tr is="blog-post-row"></tr>
</table>

keep-alive

当组件切换时,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题

image

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

重新创建动态组件的行为通常非常有用,但该案例中,我们更希望标签的组件实例能够被缓存下来。我们可以用 <keep-alive> 元素将其动态组件包裹起来。

image

image

注意这个 <keep-alive> 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。

组件中的name选项有什么作用?

根据上面的注意事项,延伸出该问题,下面来看个网上的回答:

vue组件name的作用小结

  1. 当项目使用keep-alive时,可搭配组件name进行缓存过滤
//假设我们有个组件命名为detail,
//其中dom加载完毕后我们在钩子函数mounted中进行数据加载
export default {
  name:'Detail'
},
mounted(){
  this.getInfo();
},
methods:{
  getInfo(){
     axios.get('/xx/detail.json',{
       params:{
        id:this.$route.params.id 
       }
     }).then(this.getInfoSucc)
   }
 }
 /**
 在App.vue中使用了keep-alive导致
 我们第二次进入的时候页面不会重新请求,
 即不会再次触发mounted函数。

 有两个解决方案:
 一个增加activated()函数,每次进入新页面的时候再获取一次数据。
 还有个方案就是在keep-alive中增加一个过滤exclude:
 */
 <div id="app"> 
 <keep-alive exclude="Detail">
  <router-view/>
 </keep-alive>
</div>
  1. DOM做递归组件时
<div>
    <div v-for="(item,index) of list" :key="index">
      <div>
        <span class="item-title-icon"></span>
        {{item.title}}
      </div>
      <div v-if="item.children" >
      <!-- detail-list 就是该组件自身 -->
        <detail-list :list="item.children"></detail-list>
      </div>
    </div>
 </div>
<script>
export default {
  name:'DetailList',//递归组件是指组件自身调用自身
  props:{
    list:Array
    /**
    const list = [{
     "title": "A",
     "children": [
     {"title": "A-A","children": [{"title": "A-A-A"}]},
     {"title": "A-B"}]
    }, {
     "title": "B"
    }, {
     "title": "C"
    }, {
     "title": "D"
    }]
    */
  }
}
</script>

迭代结果如下:


image
  1. 当你用vue-tools时:该调试工具里显示的组见名称是由vue中组件name决定的
    image

异步组件

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。

为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。

Vue 只有在这个组件需要被渲染时才会触发该工厂函数,且会把结果缓存起来供未来重渲染

知识点

image
  • 如你所见,这个工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。

  • 这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpackcode-splitting 功能一起配合使用:

    image

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

    image

组件之间的循环引用

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

    image

  • vue处理边界情况中有一种情况是:组件之间的循环引用,这里就涉及到了异步加载组件问题:

    image

  • 当你仔细观察的时候,你会发现这些组件在渲染树中互为对方的后代和祖先——一个悖论!
    当通过 Vue.component 全局注册组件的时候,这个悖论会被自动解开。
    如果你是这样做的,那么你可以跳过这里。

  • 然而,如果你使用一个模块系统依赖/导入组件,例如通过 webpackBrowserify,你会遇到一个错误:

    image

  • 这里我们可以异步import(具体的我们可以在处理边界情况一节中具体再学习

    image

处理加载状态

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异步组件处理路由组件加载状态的解决方案

  • 在大型单页面应用中,处于对性能的考虑和首屏加载速度的要求,我们一般都会使用webpack的代码分割和vue-router的路由懒加载功能将我们的代码分成一个个模块,并且只在需要的时候才从服务器加载一个模块。
  • 但是这种解决方案也有其问题,当网络环境较差时,我们去首次访问某个路由模块,由于加载该模块的资源需要一定的时间,那么该段时间内,我们的应用就会处于无响应的状态,用户体验极差。
  • 【解决方案】这种情况,我们一方面可以缩小路由模块代码的体积,静态资源使用cdn存储等方式缩短加载时间,另一方面则可以路由组件上使用异步组件,显示loadingerror等状态,使用户能够得到清晰明了的操作反馈。
  • 【具体实现】声明方法,基于Vue动态组件工厂函数来返回一个Promise对象
    image

    调用:
    image
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335