Vue 源码(六):Vue

有朋友说前面看不太懂,没关系,Vue 源码在初始化的时候确实有点绕,其实前面几篇博客主要讲解的就是一个东西,Vue 初始化的一些操作。

那么看完这篇博客的内容,前面的也就都明白了。

然后让我们回到源码,接下来,我们给 data 做一个自定义策略,它会接收3个参数,这里做一个详细的解释:

parentVal 是 Vue.options。

childVal 就是我们传的 options 配置。

vm 则指的是 Vue 的实例。

那么我们可以先来打印下 parentVal。

可以看到 parentVal 的值是 undefined。

为什么呢?很明显,因为我们在 Vue.options 里面压根就没有给它配置一个 data。

然后我们在打印 childVal。

可以看到就是我们在 new Vue() 中传入的 data。

那么我们的重点是要针对 vm 来做一些处理。

如果说当前的 vm 是没有传的,并且当前的 childVal 不等于 undefined,那么,我们就需要显示一个报错信息。

为什么?因为当我们在调用 strats.data 的时候,我们实际上是给 data 这个选项做了一些自定义策略,来处理一些数据。

但是我们除了用 new Vue() 来给它传之外,我们的一些子组件在创建的时候也是会调用它这个方法的。

那么在我们的子组件中就应该会有一个限制,在子组件中,我们 data 的配置它就必须是个函数。

然后接下来,我们会来实现 Vue.extend 这个方法,它的作用就是用来创建一个 Vue 的子类。

既然说到类,那么什么是类,什么是子类,什么是父类呢?

其实我们所谓的类,在ES6之前是没有这个东西的。比如我们定义一个构造函数,其实它就是一个类,类实际上就是我们封装了一系列相同的属性和方法。

其实子类和父类的概念就一句话:子类就是在父类的基础之上又拓展了一些新的东西。

光看概念可能不太懂,没关系,我们可以拿电话来举个例子:

我们把以前的电话,比如老人机,封装成一个 Class, 他的功能只有:打电话,发短信。

如果说我们现在又要定义一个 Class,比如现在的很火的华为手机,它的功能除了打电话,发短信之外,还可以玩游戏,拍照等等。

那么在整个设计的过程中,我们就会想到一个问题,如果说我们要来定义两个类,并且这2个类又及其的相似。

比如上面的电话例子,都是有一些共性的:打电话,发短信。

那我们能不能在这些共性里面来找到一些规律呢?那么这个就是子类和父类的概念。

我们就可以把老人机设置成一个父类,把华为手机设置成一个子类。

简单来说,父类它的实例对象能够做的事情,子类它的实例对象也能够做。

但是子类在父类的基础上又拓展了一些新的东西,这些新的东西是父类所不具备的。

那么了解了类,就回到代码上面,我们首先定义一个 initExtend 函数,然后在最开始的时候,我们调用一下它就可以了。

然后我在调用你的时候,直接的把 Vue 这个构造函数给传进去。你接收之后,再给 Vue 本身扩展一个方法 extend,它就是这么来的。

首先,我们知道,extend 这个函数的作用就是去创建一个 Vue 的子类。所以我们在这里需要关注的就2个东西。

一个是参数对象,你是如何去处理这些参数对象的。

第二个就是你的返回值,既然是创建一个 Vue 的子类,那么它的返回值肯定是一个构造函数。

那么首先我们用 extendOptions 来接收你传进来的参数对象。

然后我们接下来返回的是一个 Vue 的子类,那我们就会找到 this。

那么 this 是指谁呢?这里的 this 指的就是 Vue 本身。

因为我们是通过 Vue.extend 来调用的,extend 是 Vue 的一个静态方法。那么调用它的时候,它里面的 this 自然就是 Vue 本身了。

然后我们把 this 赋值给一个变量 Super。

然后我们定义一个 Sub 的方法。大家看到 Sub 这个名字的瞬间,是不是就明白了。

首字母大写,那么它这里肯定是作为一个构造函数存在的。

那么,你在调用 Vue.extend 这个方法的时候,我们最终就会把 Sub 给 return 出去。

那么我们返回的子类也就是 Sub 这个构造函数了。

那么接下来,这里的关键就是怎么处理参数和构造函数的了。

首先,我们会做一个这样的事情,给 Sub 这个构造函数取一个名字 VueComponent。当然,这个名字只是在函数体里面有用的。

那么我们给 Sub 这个构造函数封装哪些属性和方法呢?我们可以创建一个对象,然后指定它的原型是 Super.prototype。

那么在这个时候,是不是也就意味着,我们在这里创建出来的构造函数 Sub,它就会作为 Vue 的一个子类存在。

因为 Sub 的实例对象也都是可以去访问 Vue 原型上面的属性和方法的。

那么这个时候,我如果在 Sub 里面调用 this._init(),它最终调用的是谁呢?

这里的 this 指的是 Sub 的实例,但是我们并没有往 Sub 的原型对象上扩展一个 _init 的方法。

那么我们实际上找到的就是 Vue 原型对象上面的 _init 方法。

那么让我们往回看下,_init 它做了些什么事。

首先我们在调用 _init 的时候,传入了一个 options。

然后我们通过调用 mergeOptions 来进行这些选项的合并。

然后在选项合并的过程中,我们又会去检测你选项的规范,并且会看你有没有一些自定义的策略等等。。

那么接下来,我们在 Sub 里面也会来调用 mergeOptions 这个方法来进行一些选项的合并。

那么我传谁进去呢?

第一个,我们需要把 Super.options 给它传过去,那么 Super.options 指的是谁?Super 就是 Vue,那么 Super.options 指的就是 Vue 的全局API。

第二个,我们会把 extendOptions 给传过去。

最终,我们把这两个对象合并成一个对象之后,在给到 Sub.options。

我们只要调用了 extend 方法,就会返回一个 Vue 的子类出来,这个子类我们是作为组件的语法器存在。

那么,我们在组件的语法器里面,我们就会有一些限制存在,比如说 el 这个选项,我们就不能够去配置,不然就会报错。

因为 el 这个选项,我们只能够在 Vue 的实例里面来进行配置。其他所有的组件,子组件或者子类里面都不能有这个配置。

那它是根据谁来判断的呢?

其实就是根据选项合并的方法 mergeOptions 来进行判断的。

因为我们在选项合并的时候,是没有传 vm 的。因为我们只传了2个参数。

但是实际上,我们在第一次使用的时候,你会发现在 initMixin 这个方法里面,我们是有传 vm 的。

这个 vm 指的就是 Vue 的实例对象。

然后我们接着往下走,就会触发默认策略和自定义策略。

如果说我们在子类里面也配置了 el 这个选项。那么我们就会触发 el 这个自定义策略。

然后我们就会把 el 自定义策略的引用给到 result。

然后我们会给 result 传入 parent[key], child[key], vm, key,那么问题来了, vm 我们有传吗?

我们会发现,在 Sub 函数里面值只是传了2个参数,所以这里的 vm 接收的就是 undefined。

那如果是 vm 是 undefined,那么 strats.el 里面就会进行判断,也就会报错,告诉你,选项 el 只能够在 vue 的实例中使用。

因为在 Vue 的实例中,你在调用 mergeOptions 的时候,是一定会把 vm 给我传过来的。

但是在我们的一些子类,一些子组件里面,我们来进行选项合并的时候,我们是不会把 vm 给它传过去的。

所以这就是为什么在子类或者子组件里面,不能配置 el 的原因。

发布了61 篇原创文章 · 获赞 3 · 访问量 4385

猜你喜欢

转载自blog.csdn.net/weixin_43921436/article/details/101170560
vue