Vue工程化中创建全局组件、extend创建组件、extends配置组件、异步组件

发布于:2022-12-15 ⋅ 阅读:(451) ⋅ 点赞:(0)


1. Vue工程化中创建全局组件

工程化中创建全局组件需要在src/components文件夹下创建,并且全局组件需要写在 js 文件内。

步骤:

  1. 例如,我们现在要创建与加载相关的全局组件,创建目录如下:

在这里插入图片描述

  1. 编写 index.js 文件

    import Vue from 'vue'
    
    // 工程化中,它没有了template配置 只有 el和render,全局组件不能使用el
    
    
    //创建全局组件
    Vue.component('loading', {
      render: h => {
        return h('h3', null, '加载中...')
      }
    })
    
  2. 编写入口文件 main.js 文件

    import Vue from 'vue'
    import App from './App.vue'
    
    // 引入全局组件
    import './components/loading'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App)
    }).$mount('#app')
    
  3. 编写父组件 App.vue 文件

    <template>
      <div>
        <h3 class="title">App组件</h3>
        <hr />
        <!-- 引入全局组件,不需要注册 -->
        <loading />
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
        }
      }
    }
    </script>
    

在这里插入图片描述

在工作中,我们更喜欢下面这种写法:

我们需要在 loading 文件夹下再创建一个 loading.vue文件,然后修改以下index.js文件的写法,入口文件main.js和父组件App.vue的写法不变。

loading.vue文件:

<template>
  <div>
    <h3>我是一个loading</h3>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
h3 {
  color: green;
}
</style>

index.js文件:

import Vue from 'vue'

import loading from './loading.vue'

Vue.component('loading', loading)

在这里插入图片描述

2. 使用 extend 创建组件

我们创建Vue实例时,都会有一个el选项,来指定实例的根节点,如果不写el选项,那组件就处于未挂载状态。Vue.extend 的作用,就是基于 Vue 构造器,创建一个‘ 子类 ',它的参数跟new Vue的基本一样,但data要跟组件一样,是个函数,再配合$mount,就可以渲染组件,并且挂载到任意指定的节点上,比如body(这是单文件组件做不到的)。

通俗一点来讲,工作中我们会有如下应用场景,比如我们需要一个弹框(即组件)显示在页面上,但是又不想让弹框影响整个 html 层级,进而影响页面的CSS样式。所以我们需要弹框不要挂载到 app 节点上,而是挂载在另一个新创建的节点上,这时候就需要用到 extend 创建组件。

我们可以通过 extend 创建一个组件,让这个组件拥有 el 的能力,即能挂载到自定义的 dom 节点上。

步骤:

  1. 在公共index.html文件中,新建一个弹框节点

    在这里插入图片描述

  2. 新建dialog文件夹,并在文件夹下创建index.jsdialog.vue文件

    在这里插入图片描述

  3. 编写index.js文件

    import Vue from 'vue'
    import dialog from './dialog.vue'
    
    // 使用extend继承创建组件
    const Cmp = Vue.extend(dialog)
    
    new Cmp().$mount('#dialog')
    
  4. 编写dialog.vue文件

    <template>
      <div>我是一个弹层</div>
    </template>
    
    <script>
    export default {}
    </script>
    
    <style lang="scss" scoped></style>
    
  5. 编写入口文件main.js文件

    import Vue from 'vue'
    import App from './App.vue'
    
    import './components/dialog'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App)
    }).$mount('#app')
    

在这里插入图片描述

改写一下,我们使用模块化的写法:

修改index.js文件:

import Vue from 'vue'
import dialog from './dialog.vue'

// 使用extend继承创建组件
const Cmp = Vue.extend(dialog)

export default () => new Cmp().$mount('#dialog')
// new Cmp().$mount('#dialog')

修改main.js文件:

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false
Vue.prototype.$dialog = dialog

new Vue({
  render: h => h(App)
}).$mount('#app')

编写App.vue文件,在页面中显示:

<template>
  <div>
    <h3 class="title">App组件</h3>
    <hr />
    <button @click="showDialog">显示</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
    }
  },
  methods: {
    showDialog() {
      return this.$dialog()
    }
  }
}
</script>

在这里插入图片描述

3. 使用 extends 配置组件

extends和mixins类似,通过暴露一个extends对象到组件中使用。通俗来讲,extends 配置是一种继承机制,并且只能继承 js,不能继承 html 模板,和混入非常相似。我们一般用 extends 配置来对已有的组件进行功能拓展或者微调,即将已有的组件继承过来,进行重写。

父组件:

<template>
  <div>
    <h3 class="title">App组件</h3>
    <hr />
    <extendscmp />
  </div>
</template>

<script>
import extendscmp from './components/extends'
export default {
  components: {
    extendscmp
  },
  data() {
    return {
    }
  },
  methods: {
  }
}
</script>

<style lang="scss" scoped></style>

子组件(继承于 msg 组件):

<template>
  <div>
    <h3>extends --- {{ title }}</h3>
    <msg></msg>
  </div>
</template>

<script>
import msg from './msg'
export default {
  components: { msg },
  // 继承,它只能继承方法和属性不能继承模板
  extends: msg,
  created() {
    console.log(this.run())
  }
}
</script>

<style lang="scss" scoped></style>

msg 组件:

<template>
  <div>
    <h3>{{ title }}</h3>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: '我是一个msg'
    }
  },
  methods: {
    run() {
      return 'msg'
    }
  }
}
</script>

<style lang="scss" scoped></style>

在这里插入图片描述

4. 异步组件

使用同步方式导入组件,在进行网络请求时,js 文件会一次性打包到 app 节点中,在服务器端渲染时,网络请求得到结果不会这么快,所以同步方式在某些场景下可能会得不到数据,这时我们需要异步导入组件。

先来看一下同步导入的网络请求状况:

父组件:

<template>
  <div>
    <h3 class="title">App组件</h3>
    <hr />
    <child />
  </div>
</template>

<script>
// 同步导入
import child from './components/child.vue'
    
export default {
  components: {
    child
  },
  data() {
    return {}
  },
  methods: {}
}
</script>

<style lang="scss" scoped></style>

子组件:

<template>
  <div>
    <h3>child组件</h3>
  </div>
</template>

<script>
export default {};
</script>

<style lang="scss" scoped>
</style>

在这里插入图片描述

异步导入组件的好处:

  1. 异步组件具有滞后性,当组件在某一个环节卡住时,不会影响到其他程序。
  2. 异步组件使用 import 导入,可以提供代码分割,可以使得入口文件体积变小,网页加载速度变快。

异步导入组件的写法,以及网络请求状况:

父组件写法:

<template>
  <div>
    <h3 class="title">App组件</h3>
    <hr />
    <child />
  </div>
</template>

<script>

export default {
  components: {
    // 异步组件
    // key标签名:函数,此函数必须要返回一个promise
    // import当函数用,返回的是Promise
    // 使用此方式最多的
    // 这种方式会将js文件拆开发送
    child: () => import('./components/child.vue')
    // 自定义分包的文件名称
    // child: () => import(/*webpackChunkName:'child'*/ './components/child.vue')
  },
  data() {
    return {}
  },
  methods: {}
}
</script>

<style lang="scss" scoped></style>

在这里插入图片描述

由结果可以看出使用异步组件分割代码,可以使得出入口文件(app.js)的体积变小。

异步组件工厂:

父组件:

<template>
  <div>
    <h3 class="title">App组件</h3>
    <hr />
    <child />
  </div>
</template>

<script>
import loading from './components/loading/loading.vue'

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

export default {
  components: {
    child: AsyncComponent
  },
  data() {
    return {}
  },
  methods: {}
}
</script>

<style lang="scss" scoped></style>

在这里插入图片描述

上面是正常用法的运行结果,但是由于网络延迟较小,结果演示并不明显,所以为了让异步加载更好的展示出来,我们自定义一个滞后执行的局部组件来运行,修改代码如下:

父组件:

<template>
  <div>
    <h3 class="title">App组件</h3>
    <hr />
    <child />
  </div>
</template>

<script>
import loading from './components/loading/loading.vue'

const cmp = new Promise(resolve => {
  setTimeout(() => {
    resolve(import('./components/child.vue'))
  }, 3000)
})

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

export default {
  components: {
    // 异步组件工厂
    child: AsyncComponent
  },
  data() {
    return {}
  },
  methods: {}
}
</script>

<style lang="scss" scoped></style>

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到