Vue.extend

配置项data必须为function,否则配置无效。data的合并规则(可以看《Vue官方文档梳理-全局配置》)源码如下:

传入非function类型的data(上图中data配置为{a:1}),在合并options时,如果data不是function类型,开发版会发出警告,然后直接返回了parentVal,这意味着extend传入的data选项被无视了。

我们知道实例化Vue的时候,data可以是对象,这里的合并规则不是通用的吗?注意上面有个if(!vm)的判断,实例化的时候vm是有值的,因此不同于Vue.extend,其实下面的注释也做了说明(in a Vue.extend merge, both should be function),这也是官方文档为何说data是个特例。

另外官方文档所说的“子类”,是因为Vue.extend返回的是一个“继承”Vue的函数,源码结构如下:

Vue.extend = function (extendOptions) {

//***

var Super = this;

var SuperId = Super.cid;

//***

var Sub = function VueComponent(options) {

this._init(options);

};

Sub.prototype = Object.create(Super.prototype);

Sub.prototype.constructor = Sub;

//***

return Sub

};

Vue.nextTick

既然使用vue,当然要沿着数据驱动的方式思考,所谓数据驱动,就是不要直接去操作dom,dom的所有操作完全可以利用vue的各种指令来完成,指令将数据和dom进行了“绑定”,操作数据不仅能实现dom的更新,而且更方便。

如果浏览器支持Promise,或者用了Promise库(但是对外暴露的必须叫Promise,因为源码中的判断为typeof Promise !== 'undefined'),nextTick返回的就是Promise对象。

Vue.nextTick().then(() => {

// do sth

})

Vue执行nextTick的回调采用call的方式cb.call(ctx);ctx就是当前Vue实例,因此在回调中可以直接使用this调用实例的配置。

nextTick可以简单理解为将回调放到末尾执行,源码中如果当前不支持Promise和MutationObserver,那么会采用setTimeout的方式来执行回调,这不就是我们常用的延后执行代码的方式。

if (typeof Promise !== 'undefined' && isNative(Promise)) {

} else if (typeof MutationObserver !== 'undefined' && (

isNative(MutationObserver) ||

// PhantomJS and iOS 7.x

MutationObserver.toString() === '[object MutationObserverConstructor]'

)) {

} else {

// fallback to setTimeout

/* istanbul ignore next */

timerFunc = function () {

setTimeout(nextTickHandler, 0);

};

}

举个例子来实际看下:

{{a}}

new Vue({

el: '#app',

data: {

a: 1

},

mounted: function name(params) {

console.log('start');

this.$nextTick(function () {

console.log('beforeChange', this.$refs.dom.textContent)

})

this.a = 2;

console.log('change');

this.$nextTick(function () {

console.log('afterChange', this.$refs.dom.textContent)

})

console.log('end');

}

})

// 控制台依次打印

// start

// change

// end

// beforeChange 1

// afterChange 2

你估计会有些纳闷,既然都是最后才执行,那为什么beforeChange输出的是1而不是2,这是因为this.a=2背后触发dom更新也是采用nextTick的方式,上面的代码实际执行的顺序是:beforeChange>更新dom>afterChange。

Vue.set

Vue.set( target, key, value ),target不能是 Vue 实例,或者 Vue 实例的根数据对象,因为源码中做了如下判断:

var ob = (target).__ob__;

if (target._isVue || (ob && ob.vmCount)) {

"development" !== 'production' && warn(

'Avoid adding reactive properties to a Vue instance or its root $data ' +

'at runtime - declare it upfront in the data option.'

);

return val

}

target._isVue阻止了给Vue实例添加属性,ob && ob.vmCount阻止了给Vue实例的根数据对象添加属性。

Vue.delete

如果Vue能检测到delete操作,那么就不会出现这个api。如果一定要用delete来删除$data的属性,那就用Vue.delete,否则不会触发dom的更新。

同Vue.set,Vue.delete( target, key )的target不能是一个 Vue 示例或 Vue 示例的根数据对象。源码中的阻止方式和Vue.set相同。

在2.2.0+ 版本中target若为数组,key则是数组下标。因为Vue.delete删除数组实际是用splice来删除,delete虽然能用于删除数组,但位置还在,不能算真正的删除。

var a = [1, 2, 3];

delete a[0];

console.log(a); // [undefined, 2, 3]

Vue.use

Vue.use 源码比较简单,可以全部贴出来。

Vue.use = function (plugin) {

var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));

if (installedPlugins.indexOf(plugin) > -1) {

return this

}

// additional parameters

var args = toArray(arguments, 1);

args.unshift(this);

if (typeof plugin.install === 'function') {

plugin.install.apply(plugin, args);

} else if (typeof plugin === 'function') {

plugin.apply(null, args);

}

installedPlugins.push(plugin);

return this

};

安装的插件放到了 installedPlugins ,安装插件前通过installedPlugins.indexOf(plugin)来判断插件是否被安装过,进而阻止注册相同插件多次。

插件类型为 object,必须指定 install 属性来安装插件(typeof plugin.install === 'function'),另外插件执行采用plugin.install.apply(plugin, args);,因此 this 访问 object 的其他属性。此处的 args 是由 Vue(args.unshift(this);) 和 Vue.use 传入的除了 plugin 的其他参数(toArray(arguments, 1),1 表示从 arguments[1] 开始截取)。

Vue.use({

a: 1,

install: function (Vue) {

console.log(this.a) // 1

console.log(arguments) // [function Vue(options),"a", "b", "c"]

}

}, 'a', 'b', 'c')

插件类型为 function,安装调用plugin.apply(null, args);,因此在严格模式下插件运行时上下文 this 为 null,非严格模式为 Window。

'use strict'

Vue.use(function plugin() {

console.log(this) // null

console.log(arguments) // [function Vue(options),"a", "b", "c"]

}, 'a', 'b', 'c')

Vue.compile

和众多 JS 模板引擎的原理一样,预先会把模板转化成一个 render 函数,Vue.compile 就是来完成这个工作的,目标是将模板(template 或 el)转化成 render 函数。

Vue.compile 返回了{render:Function,staticRenderFns:Array},render 可直接应用于 Vue 的配置项 render,而 staticRenderFns 是怎么来的,而且按照官网的例子,Vue 还有个隐藏的配置项 staticRenderFns,先来个例子看看。

var compiled = Vue.compile(

'

' +

'

no data binding

' +

'{{prop}}' +

'

'

)

console.log(compiled.render.toString())

console.log(compiled.staticRenderFns.toString())

// render

function anonymous() {

with(this) {

return _c('div', [_m(0), _c('section', [_v(_s(prop))])])

}

}

// staticRenderFns

function anonymous() {

with(this) {

return _c('header', [_c('h1', [_v("no data binding")])])

}

}

原来没有和数据绑定的 dom 会放到 staticRenderFns 中,然后在 render 中以_m(0)来调用。但是并不尽然,比如上述模板去掉

,staticRenderFns 长度为 0,header 直接放到了 render 函数中。

function anonymous() {

with(this) {

return _c('div', [_c('header', [_v("no data binding")]), _c('section', [_v(_s(prop))])])

}

}

Vue.compile 对应的源码比较复杂,上述渲染 没有放到 staticRenderFns 对应源码的核心判断如下:

// For a node to qualify as a static root, it should have children that

// are not just static text. Otherwise the cost of hoisting out will

// outweigh the benefits and it's better off to just always render it fresh.

if (node.static && node.children.length && !(

node.children.length === 1 &&

node.children[0].type === 3

)) {

node.staticRoot = true;

return

} else {

node.staticRoot = false;

}

不符判断条件 !(node.children.length === 1 && node.children[0].type === 3), 有一个子节点 TextNode(nodeType=3)。 注释也说明了一个 node 符合静态根节点的条件。

另外官网说明了此方法只在独立构建时有效,什么是独立构建?这个官网做了详细的介绍,不再赘述。对应官网地址:对不同构建版本的解释。

仔细观察编译后的 render 方法,和我们自己写的 render 方法有很大区别。但是仍然可以直接配置到 render 配置选项上。那么里面的那些 _c()、_m() 、_v()、_s() 能调用?随便看一个 Vue 的实例的 __proto__ 就会发现:

// internal render helpers.

// these are exposed on the instance prototype to reduce generated render

// code size.

Vue.prototype._o = markOnce;

Vue.prototype._n = toNumber;

Vue.prototype._s = toString;

Vue.prototype._l = renderList;

Vue.prototype._t = renderSlot;

Vue.prototype._q = looseEqual;

Vue.prototype._i = looseIndexOf;

Vue.prototype._m = renderStatic;

Vue.prototype._f = resolveFilter;

Vue.prototype._k = checkKeyCodes;

Vue.prototype._b = bindObjectProps;

Vue.prototype._v = createTextVNode;

Vue.prototype._e = createEmptyVNode;

Vue.prototype._u = resolveScopedSlots;

Vue.prototype._g = bindObjectListeners;

正如注释所说,这些方法是为了减少生成的 render 函数的体积。

全局 API 还剩 directive、filter、component、mixin,这几个比较类似,而且都对应着配置项,会在「选项」中再详细介绍。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

vue怎么把api 挂载到全局_深入理解Vue官方文档梳理之全局API相关推荐

  1. Vue官方文档梳理-全局API

    Vue.extend 配置项data必须为function,否则配置无效.data的合并规则(可以看<Vue官方文档梳理-全局配置>)源码如下: 传入非function类型的data(上图 ...

  2. 基于vue的微信小程序开发5分钟上手教程(官方文档转)

    使用手册 mpvue 继承自 Vue.js,其技术规范和语法特点与 Vue.js 保持一致. 注:其实就是官方文档,只是习惯看博文学习才直接copy过来的,详见官方文档 本文档适用于有一定 Vue.j ...

  3. pythondocumentation是什么_怎样阅读Python官方文档

    如何阅读官方Python文档的初学者,因为他们没有相关的经验,学习语言通常是费时且劳动密集型和效果不是很好.下面简要介绍如何阅读官方文件.一旦你学会快速查询官方文件,学习效率会提高很多文档门户.如何阅 ...

  4. vue进入页面执行的钩子函数_深入理解Vue 的钩子函数

    前言 说到Vue的钩子函数,可能很多人只停留在一些很简单常用的钩子( created , mounted ),而且对于里面的区别,什么时候该用什么钩子,并没有仔细的去研究过,且Vue的生命周期在面试中 ...

  5. pyrealsense 官方文档 官方doc 官方API(API Architecture 架构)

    链接:pyrealsense2 API Architecture https://github.com/IntelRealSense/librealsense/blob/master/doc/api_ ...

  6. django文档_如何在django官方文档中快速找到需要的内容

    许多新手程序员发现Django文档内容非常庞大. 假设想学习如何为用户执行登录.看着很简单:登录是Django的核心功能.如果搜索" django登录"或搜索文档,则会看到一些选项 ...

  7. vue快速修改数组的某个值_详解vue组件三大核心概念

    前言 本文主要介绍属性.事件和插槽这三个vue基础概念.使用方法及其容易被忽略的一些重要细节.如果你阅读别人写的组件,也可以从这三个部分展开,它们可以帮助你快速了解一个组件的所有功能. 本文的代码请猛 ...

  8. 都在夸官方文档 Vue.js 2021 年度报告出炉!

    整理 | 苏宓 出品 | CSDN(ID:CSDNnews) 作为前端开发框架三剑客之一,Vue 自 2014 年发布以来,成为很多开发者必备的工具. 近日,国外软件开发机构 Monterail 在对 ...

  9. 《SpringBoot官方文档》_笔记

    文章目录 Part III. Using Spring Boot Part IV Spring Boot Features 23 SpringApplication 23.1 Startup Fail ...

最新文章

  1. iOS 快速定位约束冲突
  2. pic单片机延时程序C语言,PIC单片机C语言延时程序和循环子程序实现方法
  3. 《教你10分钟制作3D网游》视频吐槽
  4. 碎片化学前端,促进技术提升,我推荐这些
  5. C语言,利用求余运算拆分三位数的个,十,百位数字,并求和
  6. CALL 和 ret 指令
  7. 13章 购买服务器和域名绑定
  8. 2021年最新UI/UE设计学习路线图
  9. 刚毕业想学习web前端,该怎么学才能最快入门?
  10. nyoj 456 邮票分你一半【01背包】
  11. 转《JAVA和C#得相同点和不同点》
  12. Go语言实现线程安全访问队列
  13. C++ set 排序 修改元素之后不会改变原来的排序
  14. win10下什么拼音输入法好用
  15. android studio插件 统计代码行数
  16. 伺服驱动器开发案例,迈信EP100
  17. UEFI模式下安装ubuntu以及重装ubuntu教程
  18. matlab ri值,基于Matlab的中国地面气候资料日值数据集(V3.0)快速处理
  19. LeetCode 871. 最低加油次数
  20. 利用PYTHON连接阿里云物联网平台

热门文章

  1. 2019-06-17问答系统项目落地调研
  2. 苹果Ad_Hoc添加新设备UUID详解
  3. Boosting(Adboost、GBDT、Xgboost)
  4. Linux:安装npm
  5. 正点原子探索者STM32F407ZGT6开发板资料:
  6. 分析网站数据的好处有哪些?
  7. 永久解决IDEA中MAVEN项目总是将LANGUAGE LEVEL重置到5的问题
  8. 20180629小测
  9. Python:斐波那契数列前n项,前n项和
  10. 网络检测,排错的顺序与方法