Vue源码系列讲解——全局API篇【一】(Vue.extend)

这篇具有很好参考价值的文章主要介绍了Vue源码系列讲解——全局API篇【一】(Vue.extend)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. Vue.extend

1.1 用法回顾

其用法如下:

Vue.extend( options )
  • 参数

    • {Object} options
  • 作用

    使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

    data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数

    <div id="mount-point"></div>
    
    // 创建构造器
    var Profile = Vue.extend({
      template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
      data: function () {
        return {
          firstName: 'Walter',
          lastName: 'White',
          alias: 'Heisenberg'
        }
      }
    })
    // 创建 Profile 实例,并挂载到一个元素上。
    new Profile().$mount('##mount-point')
    

    结果如下:

    <p>Walter White aka Heisenberg</p>
    

1.2 原理分析

通过用法回顾我们知道,Vue.extend的作用是创建一个继承自Vue类的子类,可接收的参数是一个包含组件选项的对象。

既然是Vue类的子类,那么除了它本身独有的一些属性方法,还有一些是从Vue类中继承而来,所以创建子类的过程其实就是一边给子类上添加上独有的属性,一边将父类的公共属性复制到子类上。接下来,我们就来看看源码是如何实现这个过程的。

该API的定义位于源码的src/core/global-api/extend.js中,如下:

Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
        return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
        validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
        this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
        Super.options,
        extendOptions
    )
    Sub['super'] = Super

    if (Sub.options.props) {
        initProps(Sub)
    }
    if (Sub.options.computed) {
        initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
        Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
        Sub.options.components[name] = Sub
    }

    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
}

可以看到,虽然代码量稍微有点多,但是逻辑并不复杂,下面我们就来逐行分析一下。

首先,该函数内部定义了几个变量,如下:

extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
  • extendOptions:用户传入的一个包含组件选项的对象参数;
  • Super:指向父类,即基础 Vue类;
  • SuperId:父类的cid属性,无论是基础 Vue类还是从基础 Vue类继承而来的类,都有一个cid属性,作为该类的唯一标识;
  • cachedCtors:缓存池,用于缓存创建出来的类;

接着,在缓存池中先尝试获取是否之前已经创建过的该子类,如果之前创建过,则直接返回之前创建的。之所以有这一步,是因为Vue为了性能考虑,反复调用Vue.extend其实应该返回同一个结果,只要返回结果是固定的,就可以将结果缓存,再次调用时,只需从缓存中取出结果即可。在API方法定义的最后,当创建完子类后,会使用父类的cid作为key,创建好的子类作为value,存入缓存池cachedCtors中。如下:

if (cachedCtors[SuperId]) {
    return cachedCtors[SuperId]
}

接着,获取到传入的选项参数中的name字段,并且在开发环境下校验name字段是否合法,如下:

const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
    validateComponentName(name)
}

接着,创建一个类Sub,这个类就是将要继承基础Vue类的子类,如下:

const Sub = function VueComponent (options) {
    this._init(options)
}

到这里,我们已经把类创建好了,接下来的工作就是让该类去继承基础Vue类,让其具备一些基础Vue类的能力。

首先,将父类的原型继承到子类中,并且为子类添加唯一标识cid,如下:

Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++

接着,将父类的options与子类的options进行合并,将合并结果赋给子类的options属性,如下:

Sub.options = mergeOptions(
    Super.options,
    extendOptions
)

接着,将父类保存到子类的super属性中,以确保在子类中能够拿到父类,如下:

Sub['super'] = Super

接着,如果选项中存在props属性,则初始化它,如下:

if (Sub.options.props) {
    initProps(Sub)
}

function initProps (Comp) {
  const props = Comp.options.props
  for (const key in props) {
    proxy(Comp.prototype, `_props`, key)
  }
}

初始化props属性其实就是把参数中传入的props选项代理到原型的_props中。

接着,如果选项中存在computed属性,则初始化它,如下:

if (Sub.options.computed) {
    initComputed(Sub)
}

function initComputed (Comp) {
  const computed = Comp.options.computed
  for (const key in computed) {
    defineComputed(Comp.prototype, key, computed[key])
  }
}

初始化props属性就是遍历参数中传入的computed选项,将每一项都调用defineComputed函数定义到子类原型上。此处的defineComputed函数与我们之前在生命周期初始化阶段initState中所介绍的defineComputed函数是一样的。

接着,将父类中的一些属性复制到子类中,如下:

Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use

export const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]
// create asset registers, so extended classes
// can have their private assets too.
ASSET_TYPES.forEach(function (type) {
    Sub[type] = Super[type]
})
// enable recursive self-lookup
if (name) {
    Sub.options.components[name] = Sub
}

接着,给子类新增三个独有的属性,如下:

Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)

最后,使用父类的cid作为key,创建好的子类Sub作为value,存入缓存池cachedCtors中。如下:

// cache constructor
cachedCtors[SuperId] = Sub

最终将创建好的子类Sub返回。

以上,就是Vue.extend的所有逻辑。其实总体来讲,整个过程就是先创建一个类Sub,接着通过原型继承的方式将该类继承基础Vue类,然后给Sub类添加一些属性以及将父类的某些属性复制到Sub类上,最后将Sub类返回。文章来源地址https://www.toymoban.com/news/detail-839571.html

到了这里,关于Vue源码系列讲解——全局API篇【一】(Vue.extend)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端Vue Node.js + Express + MongoDB 构建的后端服务API接口

    构建一个使用 Vue.js 作为前端, Node.js + Express + MongoDB 作为后端服务的全栈应用涉及到多个步骤。这里简要概述整个过程,并提供一些基本的代码示例来帮助你开始。 安装 MongoDB: 根据你的操作系统从 MongoDB 官网 下载并安装 MongoDB。 启动 MongoDB 服务: 安装完成后,根据 MongoDB 的

    2024年04月14日
    浏览(34)
  • 前端系列12集-全局API,组合式API,选项式API的使用

    The  setup()  hook serves as the entry point for Composition API usage in components in the following cases: 在以下情况下,  setup()  钩子用作组件中 Composition API 使用的入口点: Using Composition API without a build step; 在没有构建步骤的情况下使用 Composition API; Integrating with Composition-API-based code in an Op

    2024年02月03日
    浏览(30)
  • IIS部署vue前端过程(含IIS及相关配置和安装),部署遇到的问题及报错(承接vueconfig.js全局配置环境变量,跨域问题)

    目录 一.IIS使用安装。 二.部署准备工作 三.部署前端(以vue为主) 四.问题与报错 1.HTTP 错误 404.0 - Not Found(需重写路由入口) 2.请求调用不了(需要重写请求地址) 3.地址显示undefined 第一步,打开“ 控制面板 ”,点击“ 网络和Internet ”。 第二步,点击左侧“ 程序 ”,然后点击

    2024年02月08日
    浏览(49)
  • 【vue】Vue 全局API 详细介绍(nextTick、set、delete、......)

    一、Vue.extend(options) 当然,我们也可以把使用extend创建出来的实例挂载到自定义标签上(这里不再展开)。 Vue.extend只是创建一个构造器,这个构造器预设一些参数,这个构造器创建可复用的组件。 其主要用来服务于Vue.component,用来生成组件。 二、 Vue.component Vue.component()会注

    2023年04月23日
    浏览(67)
  • 前端vue2 全局水印效果

    最近写项目遇到一个需求,全局显示水印,不管在哪个路由都要显示。 想要实现的效果: 新建shuiyin.js文件 main.js中全局注册

    2024年02月15日
    浏览(32)
  • 若依vue前端有全局用户信息变量吗

    \\\"若依\\\"是一个基于SpringBoot和Vue的前后端分离的开源项目。在前端Vue部分,全局用户信息通常保存在Vuex中,Vuex是Vue.js的状态管理模式。它提供了一个集中式存储来管理所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 在若依系统中,全局用户信息通常

    2024年02月14日
    浏览(26)
  • uniapp引入全局js,vue2/vue3不同方式引入

    Hi I’m Shendi uniapp引入全局js,vue2/vue3不同方式引入 最近写小程序,个人开发,选用了 uni-app 进行开发 选用的 vue3 版本 因为我用的 vue3 版本,在这里踩了没学过vue3的坑,用vue2引入全局js的方式使用,导致undefined… Vue2 版引入全局js的方法如下 将js放到项目内,一般放到自建的

    2024年02月03日
    浏览(30)
  • 记录--封装一个通过js调用的全局vue组件

    在使用vue项目编写的时候,不可避免的会碰到需要时js api来调用组件进行显示的情况 例如饿了么element ui 的 Notification 通知、Message 消息提示等组件 虽然已经提供了,但是由于api的限制,我们只能通过特定的参数来有限的改变组件的样式 之前的文章说过可以使用 new Vue() 、

    2024年02月09日
    浏览(43)
  • 【Vue.js】Vue3全局配置Axios并解决跨域请求问题

    对于前后端分离项目,前端和后端端口不能重复,否则会导致前端或者后端服务起不来。例如前端访问地址为: http://localhost:8080/ ,后端访问地址为 http://localhost:8081/ 。后端写好Controller,当用Axios访问该接口时,将会报错: Access to XMLHttpRequest at \\\' http://localhost:8081/login \\\' from

    2024年02月05日
    浏览(52)
  • Web前端 ---- 【vue】vue 组件传值(props、全局事件总线、消息的订阅与发布)

    目录 前言 父子组件 父传子 子传父 全局事件总线 什么叫全局事件总线 如何创建全局事件总线 如何在组件上获取到这个全局vc对象 最常用的创建全局事件总线 兄弟组件 消息订阅与发布 安装 使用 爷孙组件 在上篇文章我们介绍了父子组件之间的传值通信,本文将介绍不仅限

    2024年02月05日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包