Vue.extend和VueComponent的关系源码解析
目录
0.概念解释
前言
需求分析
Vue.extend
编程式的使用组件
源码分析
0.概念解释
Vue.extend和VueComponent是Vuejs框架中创建组件的两种不同方式。Vue.extend方法能够让你根据Vue对象(继承)来定义一个新的可重用的组件构造器。而VueComponent方法则是将该元件定义下侧的函数以及组件实例化时需要用到的选项(如data、computed、watch、methods、created等)作为对象传入,系统会将这个对象转换成一个Vue的构造器。 两者的关系是, Vue.extend本质上是一个用来创建Vue组件的函数,而VueComponent是定义组件的一种方式。使用Vue.extend可以灵活地定义组件,而使用VueComponent可以使代码更加简洁,可以快速创建出组件。Vue.extend的好处是它可以通过链式调用更方便地定义组件,而在VueComponent中只允许传入对象参数,因此Vue.extend灵活度更高。尽管VueComponent定义组件更简洁,但其性能却不及Vue.extend,而且它也不便于做复杂的组件定义。因此,Vue.extend和VueComponent有其各自的应用场景,可以根据实际需求来选择使用哪一种,而不是简单地把它们二者看成同一种方式。
前言
写Vue.js已经3年了吧,对Vue.extend全局方法的了解也就停留在了解啦,一直抱着不用就不学的思想,造成了一次又一次的错过~~~
直到最近,才通过公司10年秃头少年的代码,才知道错过Vue.extend方法,也就等于错过了对Vue组件的第二春了解的机会!!!
需求分析
在页面中弹出消息提示框,比如在用户点击按钮给予回应
这种业务场景很常见吧,肯定是先创建一个弹框组件,在需要使用弹框的地方注册组件并挂载到页面上去
但是需求还没结束,又提出在所以页面都可以弹出这个消息提示框
首选局部注册肯定是不行了,局部注册只能当前页面使用,所以要选择在App.vue中注册并挂载,因为App.vue是所有组件的根组件,所以组件也都能访问到App.vue中的方法,我们只需要在App.vue暴露一个弹框显示的方法就可以了
产品还不打算放过我,又提出需求是可以同时出现多个消息提示框
这个就不好实现了呀,一个组件挂载只能弹出一个提示框,总不能在App.vue挂载很多个吧,其实这也是解决方案,但是不利于扩展、占用内存!!!
那就没有办法了吗?也不是,那就要请出主角Vue.extend全局方法!!!
Vue.extend
看看官方的八股文:
使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象
我认为这段文字表达十分明了,首先Vue.extend参数是包含组件选项的对象,返回值是Vue的子类
import Vue from 'vue'
let VueComponent = Vue.extend({})
VueComponent.prototype.__proto__ == Vue.prototype // true
我们这里将子类称为VueComponent
你对这个名称很熟悉吧~~~
import Vue from 'vue/dist/vue.esm.js' // 必须引入这个版本的Vue才可以使用template选项
new Vue({el: "#app",template: `<App></App>`,components: { App },mounted() {let app = this.$children[0]; // App组件实例let VueComponent = app.constructor // App构造函数console.log(app);console.log(VueComponent);console.log(VueComponent.prototype.__proto__ == Vue.prototype);}
})
不难发现VueComponent就是组件的构造函数~~~
是不是一下就明白了,Vue.extend的返回值就是组件的构造函数,传入的选项就是组件的初始配置
Vue.extend作用可以理解为:
首选创建一个Vue类的子类(组件的构造函数),将传入的组件选项配置当做实例子类的默认值(组件的初始配置),并返回这个类(组件的构造函数)
Vue.component("Toast", {}) // 全局注册组件
console.log(Vue.component("Toast")); // Toast组件构造函数
在使用Vue.component方法注册全局组件时,其实内部也是先调用Vue.extend生成VueComponent,再声明到全局组件中,局部组件也是一样的~~~
其实这里还能了解一个知识点:所以的组件构造函数的父类都是Vue,所以组件可以使用Vue上所以方法和属性,比如emit、set等
编程式的使用组件
VueComponent可以被称为小Vue,VueComponent的使用也就可以对照Vue
let VueComponent = Vue.extend({})
new VueComponent({el: "#app",template: `<h1>Vue.extend的使用</h1>`
})
是不是和Vue的使用一模一样喃?
区别在于Vue.extend可以通过参数确定组件的初始配置~~~
现在完成一下最开始的需求吧~
编写my-toast.vue
<template><h1 class="title" v-if="show">{{ title }}</h1>
</template>
<script>export default {name: "my-toast",props: {title: {typeof: String,default: ""}},data() {return {show: true};},created() {setTimeout(() => {this.show = false;this.$nextTick(() => {this.$destroy();});}, 2000);}};
</script>
<style>.title {width: 180px;height: 50px;position: fixed;right: 20px;top: 20px;background-color: rgba(0, 0, 0, 0.15);text-align: center;line-height: 50px;border-radius: 8px;font-size: 16px;}
</style>
在vue的原型上绑定显示弹框方法
import Vue from 'vue';
import myToast from './components/my-toast.vue';
Vue.prototype.$toast = function (title) {const ToastComponent = Vue.extend(myToast);const toastComponent = new ToastComponent({propsData: {title}})toastComponent.$mount(document.createElement('div'));document.body.appendChild(toastComponent.$el);
}
在需要弹框的地方调用方法
// ....某vue页面
mounted() {this.$toast("测试");
}
let vm = new VueComponent(options)的注意点:
- 传递的props配置需要配置到propsData属性中
- 使用VueX、
VueRoter等第三方模块,需要把这些模块挂载到options上 - 使用插槽需要通过vm.$scopedSlots传递
源码分析
你可以在源码目录src/core/global-api/extend.js下找到这个函数的定义
Vue.extend = function (extendOptions: any): typeof Component {extendOptions = extendOptions || {}// this指的是Vueconst Super = this// 每个组件构造函数都有唯一的cidconst SuperId = Super.cid// 创建完的VueComponent构造函数,会保存到_Ctor中// 如果下次传入相同的extendOptions和SuperId,就直接取用缓存内的值const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})if (cachedCtors[SuperId]) {return cachedCtors[SuperId]}// 获取组件nameconst name =getComponentName(extendOptions) || getComponentName(Super.options)if (__DEV__ && name) {// 校验组件namevalidateComponentName(name)}// 创建VueComponent构造函数const Sub = function VueComponent(this: any, options: any) {this._init(options)} as unknown as typeof Component// 重点:实现了原型链继承,让VueComponent的原型指向Vue的原型// Vue的原型的所有方法和属性,在VueComponent也存在Sub.prototype = Object.create(Super.prototype)Sub.prototype.constructor = Sub// 生成唯一cidSub.cid = cid++// 传入的extendOptions和Vue.options合并Sub.options = mergeOptions(Super.options, extendOptions)Sub['super'] = Super// 配置props的响应式if (Sub.options.props) {initProps(Sub)}// 配置computed的响应式if (Sub.options.computed) {initComputed(Sub)}// 继承静态方法Sub.extend = Super.extendSub.mixin = Super.mixinSub.use = Super.use// ASSET_TYPES = ['component', 'directive', 'filter']ASSET_TYPES.forEach(function (type) {Sub[type] = Super[type]})if (name) {Sub.options.components[name] = Sub}// 保存基础配置Sub.superOptions = Super.optionsSub.extendOptions = extendOptionsSub.sealedOptions = extend({}, Sub.options)// 设置缓存cachedCtors[SuperId] = Subreturn Sub}
Vue.extend关键在于继承Vue,抛开其他功能代码,主要实现继承的代码:
// 继承原型
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
// 继承静态方属性和方法
// 继承静态方法
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// ASSET_TYPES = ['component', 'directive', 'filter']
ASSET_TYPES.forEach(function (type) {Sub[type] = Super[type]
})
相关文章:
Vue.extend和VueComponent的关系源码解析
目录 0.概念解释 前言 需求分析 Vue.extend 编程式的使用组件 源码分析 0.概念解释 Vue.extend和VueComponent是Vuejs框架中创建组件的两种不同方式。Vue.extend方法能够让你根据Vue对象(继承)来定义一个新的可重用的组件构造器。而VueComponent方…...
【动态规划】01背包问题(滚动数组 + 手画图解)
01背包除了可以用形象的二维动态数组表示外,还可以使用空间复杂度更低的一维滚动数组。 目录 文章目录 前言 一、滚动数组的基本理解 二、确定dp及其下标含义 三、确定递推公式 四、确定初始化 五、确定遍历顺序 1.用物品(正序)遍历背…...
javaEE 初阶 — 超时重传机制
文章目录超时重传机制1. 数据重复传输问题2. 如何解决数据重复传输问题3. 重传次数问题TCP 的工作机制:确认应答机制 超时重传机制 如果传输数据的时候丢包了该怎么办? 利用 超时重传,也就是超过了一定的时间,如果还没响应就重新…...
小米5x wlan无法打开解决
诱因:想要利用空置设备做节点服务器或者边缘计算,因此解锁并刷了magisk,印象中在刷之前wlan已经无法打开无法进行wifi联网 表现: 1 WLAN开关无法打开,或者虚假打开,无法扫描wifi 2 设置->我的设备->全…...
负载均衡之最小活跃数算法
文章目录[toc]一、概念二、场景与设计思路三、实现四、代码下载一、概念 活跃数 集群中各实例未处理的请求数。 最小活跃数 集群中各个实例,哪个实例未处理的请求数据最小,就称之为最小活跃数。 二、场景与设计思路 场景 以获取微服务地址为场景。 设计…...
JavaScript 评测代码运行速度的几种方法
一、使用 performance.now() API 在 JavaScript 中,可以使用 performance.now() API 来评测代码的运行速度。该 API 返回当前页面的高精度时间戳,您可以在代码执行前后调用它来计算代码执行所需的时间。 例如: let t0 performance.now();…...
Linux 编译器 gcc/g++
本文已收录至《Linux知识与编程》专栏! 作者:ARMCSKGT 演示环境:CentOS 7 目录 前言 正文 gcc/g常用命令 自定义可执行程序名命令-o 预处理指令-E 编译指令-S 汇编指令-c 链接指令gcc 命令巧记口诀 链接库 动态库-动态链接 静态库…...
2.Java基础【Java面试第三季】
2.Java基础【Java面试第三季】前言推荐2.Java基础01_字符串常量Java内部加载-上58同城的java字符串常量池面试code讲解intern()方法---源码解释02_字符串常量Java内部加载-下whyOpenJDK8底层源码说明递推步骤总结考查点03_闲聊力扣算法第一题字节跳动两数求和题目说明面试题解法…...
Java高级-多线程
本篇讲解java多线程 基本概念: 程序、进程、线程 **程序(program)**是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。 **进程(process)**是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程…...
mysql高级(事务、存储引擎、索引、锁、sql优化、MVCC)
文章目录1.事务1.1 四大特性ACID1.2 并发事务2.存储引擎2.1 InnoDB2.2 MyISAM2.3 Memory2.4 存储引擎特点2.5 存储引擎的选择3.性能分析3.1 查看执行频次3.2 慢查询日志3.3 profile3.4 explain4.索引4.1 索引结构B-TreeBTreeHash面试题4.2 索引分类思考题4.3 语法4.4 使用规则最…...
Java后端开发功能模块思路
文章目录前言一、查找接口及参数信息1.1 找访问路径1.2 参数及返回结果信息1.3 编写功能模块函数二、代码设计思路三、总结前言 对于正在学习Java后端开发的同学来说,对于Java后端功能模块的开发过程及思路要有一个整体清晰的流程。才能保证在开发过程中更加的顺畅…...
CAPL(vTESTStudio) - DoIP - TCP发送_05
TCP发送 参数定义 版本号:02 FD or 01 FE or 其他任意值数据类型:00 05 or 00 06 or 80 01 or其他任意值数据长度:想要发送的任意长度...
使用IntelliJ IDEA搭建datax-web开发环境
记录:372场景:使用IntelliJ IDEA搭建datax-web开发环境,以及datax-web基本使用。版本:JDK 1.8Python 2.7.5datax-web开源地址:https://github.com/WeiYe-Jing/datax-web1.配置Maven环境1.1安装目录目录:D:\…...
[SSD固态硬盘技术 14] GC垃圾回收太重要了
今天介绍臭名昭著的垃圾收集 过程(或“GC”),maybe 这是对JAVA 工程师而言。当遇到GC导致速度降低时候, 他们真的想跳脚。 我想到我的小孩打疫苗,哭的哇哇叫, 在他的眼里疫苗应该也是讨厌的吧, 但事实真的如此吗? 但首先,让我们考虑一下如果根本没有 GC,闪存系统会发…...
lamada表达式、stream、collect整理
lamada表达式格式 格式:( parameter-list ) -> { expression-or-statements } 实例:简化匿名内部类的写法 原本写法: public class LamadaTest { public static void main(String[] args) { new Thread(new Runnable() { …...
Nacos 入门微服务项目实战
Nacos 核心源码精讲 - IT贱男 - 掘金小册全方位源码精讲,深度剖析 Nacos 注册中心和配置中心的核心思想。「Nacos 核心源码精讲」由IT贱男撰写,375人购买https://s.juejin.cn/ds/BuC3Vs9/ Hi,大家好,欢迎大家来学习《Nacos 核心源…...
【c++】类和对象:让你明白“面向一个对象有多重要”:构造函数,析构函数,拷贝构造函数的深入学习
文章目录 什么是面向对象?一:类是什么? 1.类的访问限定符 2.封装 3.类的实例化 4.this指针二:类的6个默认成员函数 1.构造函数 2.析构函数 3.拷贝构造函数什么是面向对象? c语言是面向…...
职场IT老手教你3步教你玩转可视化大屏设计,让领导眼前一亮!
我是制造企业的IT中心的研发人员,平常工作就是配合业务部门出出报表,选型一些商业软件,并在内部负责实施运维。最近领导出去参观了一些数字化转型比较领先的工厂和制造企业,回来就甩给我几张图,问能不能我们也做几个这…...
【光伏功率预测】基于EMD-PCA-LSTM的光伏功率预测模型(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
大数据Kylin(二):Kylin安装使用
文章目录 Kylin安装使用 一、Kylin安装要求 二、Kylin安装 1、Kylin安装前环境准备...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
