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 中的执行引擎是如何执行任务的,并且在第三篇中也介绍了任务的对象,但是,目前我们看到的都是被动的任务执行,也就是说目前执行的任务都是第三方调用发送过来的.可 ...
随机推荐
- Redis --> 为redis分配新的端口
为redis分配新的端口 为redis分配一个8888端口,操作步骤如下:1.$REDIS_HOME/redis.conf重新复制一份,重命名为redis8888.conf.2.打开redis8888 ...
- 网络通信 --> 互联网协议(一)
互联网协议 一.概述 如何分层有不同的模型,有的模型分七层,有的分四层.这里介绍把互联网分成五层. 最底下的一层叫做"实体层"(Physical Layer),最上面的一层叫做&q ...
- C语言描述链表的实现及操作
一.链表的创建操作 // 操作系统 win 8.1 // 编译环境 Visual Stuido 2017 #include<stdio.h> #include<malloc.h> ...
- SpringBoot03 项目热部署
1 问题 在编写springBoot项目时,经常需要修改代码:但是每次修改代码后都需重新启动,修改的代码才会生效 2 这么实现IDEA能够像Eclipse那样保存过后就可以自动进行刷新呢 将sprin ...
- beta冲刺总结-咸鱼
前言:emmmmmmm冲刺总结应该可以吐槽了?我发誓后面几篇冲刺我是很努力用正经语言描述了!!!!! 心得:emmmmm,说真的--到beta冲刺的时候才是真正感受到了组队的存在,基本上隔三差五就约一 ...
- C语言指针作业
一.PTA实验作业 题目1:6-5 判断回文字符串 1. 本题PTA提交列表 2. 设计思路 3.代码截图 4.本题调试过程碰到问题及PTA提交列表情况说明. 第一次做的时候我j直接等于count,其 ...
- QTableView
QTableView常用于实现数据的表格显示.下面我们如何按步骤实现学生信息表格: 一 添加表头 //准备数据模型 QStandardItemModel *student_model = ne ...
- iOS 播放音频的几种方法
Phone OS 主要提供以下了几种播放音频的方法: System Sound Services AVAudioPlayer 类 Audio Queue Services OpenAL 1. Syst ...
- 【iOS】swift-如何理解 if let 与guard?
著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者:黄兢成 链接:http://www.zhihu.com/question/36448325/answer/68614858 ...
- 2017 国庆湖南 Day5
期望得分:76+80+30=186 实际得分:72+10+0=82 先看第一问: 本题不是求方案数,所以我们不关心 选的数是什么以及的选的顺序 只关心选了某个数后,对当前gcd的影响 预处理 cnt[ ...