VueJs 源码解析 (四) initRender.Js
vueJs 源码解析 (四) initRender.Js
在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm、compiler、watcher 这三要素,那么今天我们就从这三要素逐步了解清楚。这部分主要是来解读 render.js。
一、initRender 初始化 render 函数
核心代码一:
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false);
// normalization is always applied for the public version, used in
// user-written render functions.
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true);
解析:
这里我们先做个一个大胆的猜测:createElement() 方法的最后一个参数 是来判断是 开发者是否在调用vue的时候 使用了 render 函数,从而给了不同的 参数,去render。
后面,我们再来一一验证,前面的这些猜测.
找到 createElement() 方法
import { createElement } from '../vdom/create-element';
核心代码:
export function createElement(context, tag, data, children, normalizationType, alwaysNormalize) {
if (Array.isArray(data) || isPrimitive(data)) {
normalizationType = children;
children = data;
data = undefined;
}
if (isTrue(alwaysNormalize)) {
normalizationType = ALWAYS_NORMALIZE;
}
return _createElement(context, tag, data, children, normalizationType);
}
其中 createElement(context, tag, data, children, normalizationType, alwaysNormalize)
context // 上下文
tag // 标签
data // 数据对象 (hook, on , pendingInsert)
children // 子节点 (位置)
核心代码二:
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
!isUpdatingChildComponent && warn(`$attrs is readonly.`, vm);
}, true);
defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
!isUpdatingChildComponent && warn(`$listeners is readonly.`, vm);
}, true);
} else {
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true);
defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true);
}
其中 常见的 一个 vue 的方法是 defineReactive()
在 observe 文件夹下 找到 index.js 的 defineReactive()
核心代码:
export function defineReactive(obj, key, val, customSetter, shallow) {
const dep = new Dep();
const property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return;
}
// cater for pre-defined getter/setters
const getter = property && property.get;
const setter = property && property.set;
if ((!getter || setter) && arguments.length === 2) {
val = obj[key];
}
let childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value;
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || newVal !== newVal && value !== value) {
return;
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
dep.notify();
}
});
}
这个核心的代码,就是 Vue 的 实现数据监听以及 单向数据流的 主要方式。
二、initInjections 初始化
核心代码 :
export function initInjections(vm) {
const result = resolveInject(vm.$options.inject, vm);
if (result) {
toggleObserving(false);
Object.keys(result).forEach(key => {
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
defineReactive(vm, key, result[key], () => {
warn(`Avoid mutating an injected value directly since the changes will be ` + `overwritten whenever the provided component re-renders. ` + `injection being mutated: "${key}"`, vm);
});
} else {
defineReactive(vm, key, result[key]);
}
});
toggleObserving(true);
}
}
三、initState 初始化
核心代码 :
export function initState(vm) {
vm._watchers = [];
const opts = vm.$options;
if (opts.props) initProps(vm, opts.props);
if (opts.methods) initMethods(vm, opts.methods);
if (opts.data) {
initData(vm);
} else {
observe(vm._data = {}, true /* asRootData */);
}
if (opts.computed) initComputed(vm, opts.computed);
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
判断传入的 options 对象中是否有 props methods data computed watch 等属性
如果有的话, 会分别去 进行实例化操作。
initProps(vm, opts.props)
defineReactive(props, key, value)
initMethods(vm, opts.methods)
for (const key in methods) {
...
vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
}
initData(vm)
function initData(vm) {
...
// observe data
observe(data, true /* asRootData */);
}
initComputed(vm, opts.computed)
const watchers = vm._computedWatchers = Object.create(null);
// computed properties are just getters during SSR
const isSSR = isServerRendering();
...
if (!isSSR) {
// create internal watcher for the computed property.
watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions);
}
initWatch(vm, opts.watch)
createWatcher(vm, key, handler)
function createWatcher(vm, expOrFn, handler, options) {
if (isPlainObject(handler)) {
options = handler;
handler = handler.handler;
}
if (typeof handler === 'string') {
handler = vm[handler];
}
return vm.$watch(expOrFn, handler, options);
}
看到了 这里是不是 突然有种 豁然开朗的感觉, 各种属性方法的实例化,让我们比较清楚的知道了在
props methods data computed watch 等属性或者方法中 的内部变化。
好了,今天先写到这里,回家继续~
VueJs 源码解析 (四) initRender.Js的更多相关文章
- vueJs 源码解析 (三) 具体代码
vueJs 源码解析 (三) 具体代码 在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm.compiler.watcher 这三要素,那么今天我们就从这三 ...
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- Sentinel源码解析四(流控策略和流控效果)
引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...
- Dubbo 源码解析四 —— 负载均衡LoadBalance
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...
- iOS即时通讯之CocoaAsyncSocket源码解析四
原文 前言: 本文为CocoaAsyncSocket源码系列中第二篇:Read篇,将重点涉及该框架是如何利用缓冲区对数据进行读取.以及各种情况下的数据包处理,其中还包括普通的.和基于TLS的不同读取操 ...
- React的React.createContext()源码解析(四)
一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...
- vuex 源码解析(四) mutation 详解
mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下: state ;当前命名空间对应的state payload ...
- AFNetworking2.0源码解析<四>
结构 AFURLResponseSerialization负责解析网络返回数据,检查数据是否合法,把NSData数据转成相应的对象,内置的转换器有json,xml,plist,image,用户可以很方 ...
- Celery 源码解析四: 定时任务的实现
在系列中的第二篇我们已经看过了 Celery 中的执行引擎是如何执行任务的,并且在第三篇中也介绍了任务的对象,但是,目前我们看到的都是被动的任务执行,也就是说目前执行的任务都是第三方调用发送过来的.可 ...
随机推荐
- Algorithm --> 投资组和求最大利润
投资组和求最大利润 题目: 投资人出资一笔费用mount,投资给不同的公司(A,B,C....),求最大获取利润? 例如:投资400百万,给出两家公司A和B: 1.如果投资一百万给A公司,投资3百万给 ...
- 21.C++- "++"操作符重载、隐式转换之explicit关键字、类的类型转换函数
++操作符重载 ++操作符分为前置++和后置++,比如: ++a; a++; ++操作符可以进行全局函数或成员函数重载 重载前置++操作符不需要参数 重载后置++操作符需要一个int类型的占位参数 ...
- 02-Python的下载和安装_Python编程之路
原文发布在特克斯博客www.susmote.com 之前给大家讲了关于python的背景知识,还有Python的优点和缺点,相信通过之前的介绍很多人已经清楚自己到底要不要选择学习Python,如果已经 ...
- css3 背景色 实现边框渐变运动动画
css3 #body_id { animation: myfirst 10s ease-in-out -2s infinite alternate; /* Firefox: */ -moz-anima ...
- 火狐浏览器中如何删除保存的cookie
大致分为三步即可: 打开浏览器并查看图示,按照图示操作即可完成:
- 2018上C语言程序设计(高级)博客作业样例
要求一(20分) 完成PTA中题目集名为<usth-C语言高级-第1次作业>中的所有题目. 要求二 PTA作业的总结(20分+30分) 将PTA第1次作业作业中以下2道题的解题思路按照规定 ...
- 20162320刘先润第三周Bag类测试
前言 以下内容是本周Bag代码的课后作业,要求是完成伪代码.产品代码和测试代码,为了书写方便我将伪代码以注释的形式写在了产品代码的后面 测试步骤 1.首先对Bag类引用BagInterface的代码进 ...
- 敏捷冲刺每日报告——Day4
1.情况简述 Alpha阶段第一次Scrum Meeting 敏捷开发起止时间 2017.10.28 00:00 -- 2017.10.29 00:00 讨论时间地点 2017.10.28晚9:30, ...
- 关于安装wordpress出现500 Internal Server Error的解决方案
安装新版本wordpress出现500 Internal Server Error的问题: 在./wp-includes/class-http.php的268行,改成 $request_order = ...
- 洛谷 P3797 妖梦斩木棒
https://www.luogu.org/problem/show?pid=3797 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了 ...