当前位置: 首页 > news >正文

Vue 动态创建 component

Vue 动态创建 component

angular 中 可以通过 ComponentFactoryResolver 来动态创建 component , 在平时使用 vue 的过程中也没有了解到这方面的信息。于是就花时间研究了一下。

Vue 的组件可以通过两种方式来声明,一种是通过 Vue.component,另外一种则是 Single File Components(SFC)

以下除非特别说明,组件都是全局注册的

Vue.component 方式

首先来看 Vue.component 方式的。

Vue.component('button-counter',{
   data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
});

在上面的代码中我们声明了一个叫做 button-counter 的组件。如果在常规情况下使用的话,只需要在页面上写对应的 <button-counter></button-counter> 标签就够了。

那么通过编程方式怎么处理呢?

在官方文档中我们可以看到,我们可以通过 Vue.component('component-name') 的方式来获取到 组件。而组件实例又有 $mount 这样一个方法,官方对于 $mount 的解释如下:

$mount 方法有两个参数

  • {Element | string} [elementOrSelector]
  • {boolean} [hydrating]

If a Vue instance didn’t receive the el option at instantiation, it will be in “unmounted” state, without an associated DOM element. vm.$mount() can be used to manually start the mounting of an unmounted Vue instance.

If elementOrSelector argument is not provided, the template will be rendered as an off-document element, and you will have to use native DOM API to insert it into the document yourself.

The method returns the instance itself so you can chain other instance methods after it.

那我们是否可以通过这种方式来达到我们的需求呢?

还不够!

为什么?

因为 Vue.component 返回的结果是一个 function!它返回的并不是 组件实例,而是一个构造函数。

那到这里其实我们就清楚了。 对于 Vue.component 声明的组件,我们先通过 Vue.component 获取它的构造函数,再 new 出一个组件实例,最后 通过$mount 挂载到 html 上。

下面是完整的代码:

Vue.component("button-counter", {
  data: function() {
    return {
      count: 0
    };
  },
  template:
    '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
});

Vue.component("app", {
  data: function() {
    return {
      count: 0
    };
  },
  template:
    '<div> <h1>App Component</h1><button @click="insert">click to insert new Component</button> <div id="appId"> </div></div>',
  methods: {
    insert() {
      const component = Vue.component("button-counter");
      const instance = new component();
      instance.$mount("#appId");
    }
  }
});

new Vue({
  el: "#app"
});

https://codepen.io/YoRolling/...

SFC

在实际工作中,大部分都是用官方的脚手架 vue-cli 生成项目,用的也是 SFC 这种方式。

我们的 button-counter 如果用 SFC 方式实现的话应该是这样子的:

<template>
    <button v-on:click="count++">You clicked me {{ count }} times.</button>
</template>

<script>
export default {
  name: "ButtonCounter",
  data() {
    return {
      count: 0
    };
  }
};
</script>

那么是否可以通过 export 出的对象来实现我们的需求呢?

首先我们来看,在 SFC 中, 我们在 script 中 export 了一个对象出去,那么通过这个对象应该是可以达到要求的。

先来看看 import 之后这个对象是什么样子的。

图片描述

可以发现 import 得到的对象要比我们在 组件中声明的多了一些属性和方法。

Vue.component 模式中,我们先获取到组件的构造函数,然后构造实例,通过实例的一些方法来处理数据和挂载节点。

很显然,现有数据不能满足我们。如果我们能将这个对象转化成一个组件的构造函数,那我们就可以利用上面的方案来实现我们的需求了。

那么,究竟需要怎么转换呢?

没错! 就是 Vue.extend 这个大兄 dei!我们看下官方的说明。

Create a “subclass” of the base Vue constructor. The argument should be an object containing component options.

The special case to note here is the data option - it must be a function when used with Vue.extend().

通过传入一个包含 Component options 的对象, Vue.extend 帮助我们创建一个 继承了 Vue constructor 的子类,也就是我们之前需要的构造函数。

好了,得到了构造函数,接下来的工作就简单了 。实例化,然后挂载。

下面就是完整的代码:

<template>
  <div id="app">
    <div>
    <img width="25%" src="./assets/logo.png">
  </div>
    <div>
    <button @click="insert">click me to insert ButtonCounter</button>
  </div>
    <div id="container"></div>
  </div>
</template>

<script>
import ButtonCounter from './components/ButtonCounter';
import Vue from 'vue';
export default {
  name: 'App',
  components: {
    ButtonCounter,
  },
  methods: {
    insert() {
      const bcConstructor = Vue.extend(ButtonCounter);
      const instance = new bcConstructor();
      instance.$mount('#container');
    },
  },
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>    

在线查看 https://codesandbox.io/s/m59r3547zy

https://codesandbox.io/s/m59r...

结束

Happy Ending。

到这里,通过编程的方式动态创建组件挂载到HTML 的两种方式就完成了。

再次感到看文档的重要性。 ?

? 如有错误,欢迎大家斧正!

相关文章:

  • ACM经典问题--布线问题(三)
  • 自然语言处理--Word2vec(一)
  • HDU3068(最长回文串)
  • redis初识
  • 头指针与头结点的异同
  • Npoi将excel数据导入到sqlserver数据库
  • OpenStack导入镜像后Launch不起来的几个问题
  • zookeeper 面试题 有用
  • 如何写PHP规范注释
  • /proc/stat文件详解(翻译)
  • Android性能:通过Choreographer检测UI丢帧和卡顿
  • java提高篇(五)-----使用序列化实现对象的拷贝
  • java小心机(3)| 浅析finalize()
  • Adapter Class Cast Exception Removing Footer View from ListView
  • LeetCode--014--最长公共前缀
  • “大数据应用场景”之隔壁老王(连载四)
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【剑指offer】让抽象问题具体化
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • Java比较器对数组,集合排序
  • LeetCode18.四数之和 JavaScript
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • React-redux的原理以及使用
  • vue-cli在webpack的配置文件探究
  • web标准化(下)
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 精彩代码 vue.js
  • 手机端车牌号码键盘的vue组件
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 我的zsh配置, 2019最新方案
  • 在Unity中实现一个简单的消息管理器
  • ​​​​​​​​​​​​​​Γ函数
  • #NOIP 2014# day.1 T2 联合权值
  • #stm32整理(一)flash读写
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • (C++17) std算法之执行策略 execution
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (汇总)os模块以及shutil模块对文件的操作
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (转)ABI是什么
  • (转载)虚函数剖析
  • .cfg\.dat\.mak(持续补充)
  • .net core使用ef 6
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET连接数据库方式
  • [2024最新教程]地表最强AGI:Claude 3注册账号/登录账号/访问方法,小白教程包教包会
  • [Android]竖直滑动选择器WheelView的实现
  • [AutoSar]BSW_Com07 CAN报文接收流程的函数调用
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [docker] Docker的数据卷、数据卷容器,容器互联
  • [Golang]K-V存储引擎的学习 从零实现 (RoseDB mini版本)
  • [HOW TO]怎么在iPhone程序中实现可多选可搜索按字母排序的联系人选择器
  • [lintcode easy]Maximum Subarray
  • [Luogu 2816]宋荣子搭积木