5

1、动态组件

Vue.js 提供了一个特殊的元素 <component> 用来动态地挂载不同的组件。如果我们打算在一个地方根据不同的状态引用不同的组件的话,比如tab页,就可以用到这一标签。

<template>
  <div id="app">
    <el-button-group>
      <el-button type="primary" size="small" v-for="item in btnGroup" :key="item.id" @click="handleBtn(item.name)">{{item.name}}</el-button>
    </el-button-group>
    <div>
      <keep-alive>
        <component :is="curComponent"></component>
      </keep-alive>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      curComponent: 'comA',
      btnGroup: [
        {
          id: 1,
          name: '组件一'
        },
        {
          id: 2,
          name: '组件二'
        }
      ]
    }
  },
  components: {
    comA: {
      template: `<input placeholder="请输入名字" type="text"/>`
    },
    comB: {
      template: `<p>2222222222</p>`
    }
  },
  methods: {
    handleBtn (name) {
      if (name === '组件一') {
        this.curComponent = 'comA'
      }
      if (name === '组件二') {
        this.curComponent = 'comB'
      }
    }
  }
}
</script>

id1.gif
当我们点击不同的按钮时,下面会切换不同的组件。实现动态组件的加载。is的值可以是一个已经注册的组件的名字或者一个组件的选项对象。

如果我们需要频繁的切换页面,每次都是在组件的创建和销毁的状态间切换,这无疑增大了性能的开销。那么我们要怎么优化呢?

Vue提供了动态组件的 缓存。keep-alive 会在切换组件的时候缓存当前组件的状态,等到再次进入这个组件,不需要重新创建组件,只需要从前面的缓存中读取并渲染。

2、异步组件

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

异步组件存在的意义在于加载一个体量很大的页面时,如果我们不设置加载的优先级的话,那么可能页面在加载视频等信息的时候会非常占用时间,然后主要信息就会阻塞在后面在加载。这对用户来说无疑不是一个很差的体验。但是如果我们设置加载的顺序,那么我们可以优先那些最重要的信息优先显示,优化了整个项目。

异步组件大致有以下几种定义方式:

Vue.componenet('async-component', function (resolve) {
    resolve({
        template: `<p>{{msg}}</p>`,
        data () {
            return {
                msg: '11111'
            }
        }
    })   
})

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

一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用

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

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

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

注意:import函数import语句作用是不一样的
当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:

<script>
    export default {
        data () {
            return {}
        },
        components: {
            'async-component': () => import('./async-component')
            //或者
            'async-component': (resolve) => require.ensure([], () => resolve(require('./async-component')), 'component')
        }
    }
</script>

require.ensure方法由webpack提供,详细解释参考:
https://www.cnblogs.com/weiyuanquyu/p/8432044.html

2.1 异步组件配合webpack进行代码分割
为什么有时候要使用异步导入组件配合webpack进行代码分割呢?因为如果我们有一个组件非常庞大,把所有得组件都打包到app.vue入口文件中,当页面加载时将会非常慢,其中有一些组件在当前路由中并没有使用到,但也会被加载,这时导致页面加载非常慢的重要原因。如果这些组件只有在使用时才被加载,这样肯定会加快整个页面的加载速度,而webpack正好能够帮我们将异步组件单独打包成文件。

例子(vue-cli搭建项目):
image.png
组件A:

<template>
  <div>
    <p>11111111111</p>
    <com-b></com-b>
  </div>
</template>

<script>
// import comB from '../asyncComponentB/index'
export default {
  name: 'comA',
  components: {
    'comB': () => import('../asyncComponentB/index')
    // comB
  },
  data () {
    return {
    }
  }
}
</script>

组件B:

<template>
  <p>222222222</p>
</template>
<script>
export default {
  name: 'comB',
  components: {
    'comC': (resolve) => require.ensure([], () => resolve(require('../asyncComponentC/index')), 'comC')
  },
  data () {
    return {}
  }
}
</script>

组件C:

<template>
  <p>33333333333333333334444444444433</p>
</template>

<script>
export default {
  name: 'comC',
  data () {
    return {}
  }
}
</script>

app.vue:

<template>
  <div id="app">
    <com-a></com-a>
  </div>
</template>

<script>
// import comA from './components/asyncComponentA'
export default {
  name: 'App',
  data () {
    return {
    }
  },
  components: {
    comA: () => import('./components/asyncComponentA')
    // comA
  }
}
</script>

运行npm run build --report
image.png
image.png
可以看到A、B、C三个组件被打包成独立文件

参考:
https://cn.vuejs.org/v2/guide/components-dynamic-async.html

https://segmentfault.com/a/1190000018018502?utm_source=tag-newest

https://www.jianshu.com/p/40a364b5e964


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。