vue引入组件的方法一般如下
先编写两个被引入的组件

组件1:component1.vue

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

<script>
    export default {
        name: "Component1"
    }
</script>

<style scoped>

</style>

组件2:component2.vue

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

<script>
    export default {
        name: "Component2"
    }
</script>

<style scoped>

</style>

然后组件中引入以上组件

<template>
  <div class="container">
    <component1/>
    <component2/>
  </div>
</template>
<script>
import Component1 from "component1.vue";
import Component2 from "component2.vue";
export default {
  name: "content1",
  components: {Component1,Component2},
}
</script>

以上方式使用静态import的方式引入组件,无法灵活的按需引入组件,最多控制显示哪个。

我总结了几种按需动态加载组件的方法,vue版本2.6.11

方法一

通过动态修改components内组件指向的方式实现异步动态加载组件

<template>
  <div class="wrapper">
    <h3 style="text-align: left">ComponentsMode</h3>
    <button @click="show = false">销毁</button>
    <button @click="switchComponent('component1')">组件1</button>
    <button @click="switchComponent('component2')">组件2</button>
    <div class="a">
      <model-page v-if="show"></model-page>
    </div>
  </div>
</template>

<script>
import Component1 from "component1";

export default {
  name: "AsyncComponent",
  components: {
    /*
    * 这里使用import()实现异步加载组件, 而且component可以改成变量, 但正常注册组件的行为只会执行一次,
    * 即使component的值改变, 或者本组件重新加载, 也无法重新注册组件, 所以这里只能实现延迟加载组件的的功能
    * 可以使用折中方法,给组件套个父级,通过销毁和创建父级的方法重新注册组件,实现动态组件功能,不再赘述
    * */
    ModelPage: () => {
      let component = 'component1';
      /*import()本身支持变量, 但一方面许多浏览器对import()支持不佳, 另一方面, 项目需要使用webpack编译, 使用变量webpack无法判断哪些文件需要编译
      而且微博pack编译打包后, js文件被打包到app.js, 浏览器不可能只加载一个文件的一部分, 这时单独import毫无意义,
      webpack提供了解决方法, import的路径仅文件名使用变量, 目录路径使用常量, webpack编译打包时会把该路径下所有js单独打包, 而不是合并到app.js
      * */
      return import(`./${component}`);
    }
  },
  data() {
    return {
      show: false,
      apps: null,
    }
  },
  methods: {
    /*
    * 通过动态修改$options的components内的组件实现动态异步加载组件的功能
    * */
    switchComponent: function (component) {
      this.$options.components['ModelPage'] = () => import(`./${component}`);

      //由于components改变后视图不会自动刷新, 需要手动刷新, 也可以使用this.$forceUpdate()
      this.show = false;
      let that = this;
      this.$nextTick(() => {
        that.show = true;
      })
    }
  },
}
</script>

<style scoped>
.wrapper {
  padding: 15px;
}

.a {
  text-align: left;
  height: 100px;
  border: 1px solid blue;
  margin-top: 20px;
}
</style>

方法二

使用Vue.extend实现异步加载组件
这种方式生成的vue实例虽然可以通过propsData传参, 但实例没有parent, 没有上下文, 但不能实现双向绑定, 可以通过直接调用实例方法或者实例事件的方式通讯

<template>
  <div class="wrapper">
    <h3 style="text-align:left;">extendMode</h3>
    <button @click="switchComponent('component1')">组件1</button>
    <button @click="switchComponent('component2')">组件2</button>
    <div class="a">
      <div id="mount-point" ref="mount-point"></div>
    </div>
  </div>

</template>

<script>
    import Vue from 'vue';

    export default {
        name: "ExtendMode",
        data(){
            return {
                instance: null
            }
        },
        methods: {
            switchComponent: function (name) {
                if(this.instance){
                    this.instance.$destroy();
                    this.$refs['mount-point'].removeChild(this.instance.$el);
                }
                import(`./${name}`).then(component => {
                    let VueConstructor = Vue.extend(component.default); //使用Vue.extend创建组件构造器
                    this.instance = new VueConstructor();
                    this.instance.$mount();
                    this.$refs['mount-point'].appendChild(this.instance.$el);//挂载到指定dom上
                });
            }
        }
    }
</script>

<style scoped>
  .wrapper {
    padding: 15px;
  }

  .a {
    text-align: left;
    height: 100px;
    border: 1px solid blue;
    margin-top: 20px;
  }
</style>

方法三

通过特殊 attribute is实现动态异步加载组件功能
is的值可以是组件命名, 也可以是组件选项对象, 这里使用的是后者, 使用动态修改is指向的组件选项对象, 实现动态异步加载组件

<template>
  <div class="wrapper">
    <h3 style="text-align: left">IsMode</h3>
    <button @click="show = false">销毁</button>
    <button @click="switchComponent('component1')">组件1</button>
    <button @click="switchComponent('component2')">组件2</button>
    <div class="a">
      <component :is="apps" v-if="show"></component>
    </div>
  </div>
</template>

<script>

    export default {
        name: "IsMode",
        data() {
            return {
                show: false,
                apps: null,
            }
        },
        methods: {
            switchComponent: function (component) {
                this.apps = () => import(`./${component}`);
                this.show = true;
            }
        },
    }
</script>

<style scoped>
  .wrapper {
    padding: 15px;
  }

  .a {
    text-align: left;
    height: 100px;
    border: 1px solid blue;
    margin-top: 20px;
  }
</style>

方法四

和方法三类似, 只不过使用的是全局组件注册方式实现

<template>
  <div class="wrapper">
    <h3 style="text-align:left;">VueComponentMode</h3>
    <button @click="show = false">销毁</button>
    <button @click="switchComponent('component1')">组件1</button>
    <button @click="switchComponent('component2')">组件2</button>
    <div class="a">
      <component :is="apps" v-if="show"></component>
    </div>
  </div>
</template>

<script>
    import Vue from 'vue';

    export default {
        name: "VueComponent",
        data() {
            return {
                show: false,
                apps: 'ModelPage',
            }
        },
        methods: {
            /*
            * 通过动态注册全局组件实现动态异步加载组件的功能
            * */
            switchComponent: function (component) {
                Vue.component('ModelPage', () => import(`./${component}`));

                //由于components改变后视图不会自动刷新, 需要手动刷新, 也可以使用this.$forceUpdate()
                this.show = false;
                let that = this;
                window.setTimeout(function () {
                    that.show = true;
                })
            }
        }
    }
</script>

<style scoped>
  .wrapper {
    padding: 15px;
  }

  .a {
    text-align: left;
    height: 100px;
    border: 1px solid blue;
    margin-top: 20px;
  }
</style>

Logo

前往低代码交流专区

更多推荐