ustbhuangyi / vue-analysis Goto Github PK
View Code? Open in Web Editor NEW:thumbsup: Vue.js 源码分析
Home Page: https://ustbhuangyi.github.io/vue-analysis/
License: MIT License
:thumbsup: Vue.js 源码分析
Home Page: https://ustbhuangyi.github.io/vue-analysis/
License: MIT License
老师 电子书 怎么打不开了呀
In chapter 'Vue 实例挂载的实现' with line 7,the file path describe 'src/platform/web/entry-runtime-with-compiler.js' should be 'src/platforms/web/entry-runtime-with-compiler.js'.
It's a little mistake ofcourse.
还是得用Vue.set(example1.items, newLength-1)实现响应式改变数组长度.
package.json中的deploy命令使用的是 deploy.sh
:
"deploy": "sh deploy.sh"
但是在仓库中只看到 build.sh
文件,这个文件应该是 deploy.sh
吧?
你好:
我很尊重你开源了很多的作品,这几天发生了DD前负责人的事情。Vue权威指南刚出来的时候,我在前端的一个公共号买了这本书,因为喜欢Vue,希望可以对vue有新的见解,也是对Vue的喜欢。谁知道收了这本书,我看了大部分都是Vue官网的例子和API,索然无趣。。。。我回复了公共号的人,对我说 请不要侮辱我的团队的努力什么的,原话不记得了。那个时候如果书里有你们对vue的剖析之类的,应该会很满意这本书的。只是发个唠叨。。。仅此而已==
计算属性的最终的值 不变时 也是会重新渲染的
依赖的值发生了变化就会dep.notify() computed watcher将dirty置为true 渲染watcher还是会执行
不是说这是个优化吗 为什么又去掉了?
根据大佬 HuangYi 的 vue-analysis 的项目内容,做的一个思维导图的项目(包括 Vue | Vue-Router | Vuex ),对大家应该有帮助。
大佬您好,看您文章Vuex-API-数据获取中示例代码中,有一处
getters: {
total (state, getters, localState, localGetters) {
// 可访问全局 state 和 getters,以及如果是在 modules 下面,可以访问到局部 state 和 局部 getters
return state.a + state.b
}
}
这个地方是不是写错了?
根据源码:
store._wrappedGetters[type] = function wrappedGetter (store) {
return rawGetter(
local.state, // local state
local.getters, // local getters
store.state, // root state
store.getters // root getters
)
}
代码中total的参数有错误,应该更改为:
getters: {
total (state, getters, rootState, rootGetters) {
// 可访问全局 state 和 getters,以及如果是在 modules 下面,可以访问到局部 state 和 局部 getters
return state.a + state.b
}
}
export function proxy (target: Object, sourceKey: string, key: string) { sharedPropertyDefinition.get = function proxyGetter () { return this[sourceKey][key] } sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val } Object.defineProperty(target, key, sharedPropertyDefinition)通过 Object.defineProperty 把 target[sourceKey][key] 的读写变成了对 target[key] 的读写。所以对于 props 而言,对 vm._props.xxx 的读写变成了 vm.xxx 的读写,而对于 vm._props.xxx 我们可以访问到定义在 props 中的属性,所以我们就可以通过 vm.xxx 访问到定义在 props 中的 xxx 属性了
我理解的是执行Object.defineProperty(target, key, sharedPropertyDefinition)
后,对target[key]的读写会变为对target[sourceKey][key]的读写,与您文中的描述恰好相反,所以对此抱有困惑,望您能为我解疑,谢谢。
还有请问视频一次收费后终身使用吗?有没期限的呢?
计算属性
a(){
const b = this.b;
return 1;
}
逻辑上a对b是没有依赖关系的, 但是Vue能分辨吗? getter执行时一样会进入b的getter并添加依赖呀.
Vue内部有这部分处理的相关代码吗?
对比vue文档.
在nextTick实现里,有一段关于macrotask和microtask的执行顺序的模拟:
for (macroTask of macroTaskQueue) {
// 1. Handle current MACRO-TASK
handleMacroTask();
// 2. Handle all MICRO-TASK
for (microTask of microTaskQueue) {
handleMicroTask(microTask);
}
}
是不是将第二点提到第一点之上更合适:
for (macroTask of macroTaskQueue) {
// 1. Handle all MICRO-TASK
for (microTask of microTaskQueue) {
handleMicroTask(microTask);
}
// 2. Handle current MACRO-TASK
handleMacroTask();
}
根据尤雨溪的注释,好像是因为重新绘制之前更改状态时出现问题并且在事件处理程序中使用(宏)任务会导致一些奇怪的行为,所以还是改回之前的将micro task拆分在各处使用,文章的解析说的microTimerFunc与macroTimerFunc变量的定义在源码没找到了
观点1:
掘金 https://juejin.im/post/5d5b4c2df265da03dd3d73e5
下面阮一峰老师链接 https://www.cnblogs.com/dailc/p/8325991.html
观点2:
掘金 https://juejin.im/post/5d57994ef265da03bd051969
下面参考链接 aooy/blog#5
编译入口章节提到了 compileToFunctions。在 vue-template-compiler 也包含 compileToFunctions,这两个应该都是同一个函数吧。
我希望通过把调用该函数把 template 转成 render 函数。
compiler.compileToFunctions('<div>x</div>').render.toString()
// function anonymous() {\nwith(this){return _c(\'div\',{},[_v("x")])}\n}
我期望的返回值是:render 函数中不要包含 with 语句,就像 vue-loader 处理后生成的 render 函数。
var render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c('div',{},[_vm.v("x")])
}
请问该如何做到这一步?
看完大佬的分享,十分仰慕,大佬可否提供一个一个社交账号(例如微信),有一些技术问题想和您探讨
keep-alive 生命周期:
原文:这里判断如果是被<keep-alive> 包裹的组件已经 mounted,那么则执行 queueActivatedComponent(componentInstance)。
建议:‘被<keep-alive> 包裹的组件已经 mounted ’ 应该改为 ‘<keep-alive> 组件的父组件已经 mounted’。毕竟上面那条 if 语句的作用就是调用 '被<keep-alive> 包裹的组件' 的 mounted 钩子。
以下是原文
从上面的代码可以看到,mountComponent 核心就是先调用 vm._render 方法先生成虚拟 Node,再实例化一个渲染Watcher,在它的回调函数中会调用 updateComponent 方法,最终调用 vm._update 更新 DOM。
我的疑问是vm._render方法是在updateComponent里面执行的吧,怎么会发生在实例化渲染watcher之前呢?
首先介绍一下代理,代理的作用是把
props
和data
上的属性代理到vm
实例上,这也就是为什么比如我们定义了如下 props,却可以通过 vm 实例访问到它。let comP = { props: { msg: 'hello' }, methods: { say() { console.log(this.msg) } } }
您在文中提到代理的作用是把 props 和 data 上的属性代理到 vm 实例上
,而我在分析 defineReactive 和 proxy 方法时理解的 defineReactive 方法的作用是将每个 prop 对应的值变成响应式,并可通过 vm._props.xxx 访问到定义 props 中对应的属性;proxy 方法的作用是把 vm.xxx 的访问代理到 vm._props.xxx 上。
当访问 vm 实例时会先将 vm.xxx 的访问代理到 vm._props.xxx 上(通过 proxy 实现),而访问 vm._props.xxx 又会被代理到 vm.props.xxx上(通过 defineReactive 实现),所以当定义了上述 props 时可以通过 vm 实例访问到它是通过 defineReactive 和 proxy 方法的双重代理实现的。
与您的理解有些不相符,望您能为我解答,谢谢。
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例。
vm.$vnode 应该就是自己的vnode吧,mount的时候第一次调用 updateComponent
,此时 $vnode 是 null,要触发一下 mounted hook 的回调 。如果是数据变化导致的 mountComponent
,则$vnode 就不是 null 了,而是上一次render 的 vnode.
不知道我理解的对不对。
这是部署好的地址
https://mywebsky.gitee.io/vue-analysis
如果有不妥的地方我会删除或修改
Hi, can you add English version?
It is very interesting to learn more deeply vue.js.
请教一下,我在data中定义一个空对象,在模板中使用这个对象,给输入框绑定v-model="obj.name", 他也能保证响应性,我记得之前看文档不是会先遍历data中存在的属性值,给变成响应式数据,难道在解析模板的时候也会动态给这些属性加响应性?但是如果我直接在模板中v-model一个不存在的属性它是会报错的,比如 v-model="name"
export function getData (data: Function, vm: Component): any {
// #7573 disable dep collection when invoking data getters
pushTarget()
try {
return data.call(vm, vm) // 为什么还要传一个vm的参数呢
} catch (e) {
handleError(e, vm, data()
)
return {}
} finally {
popTarget()
}
}
请问作者,Vue-Router源码分析时使用的是哪一个版本?
function invokeCreateHooks (vnode, insertedVnodeQueue) {
for (let i = 0; i < cbs.create.length; ++i) {
cbs.create[i](emptyNode, vnode)
}
i = vnode.data.hook // Reuse variable
if (isDef(i)) {
if (isDef(i.create)) i.create(emptyNode, vnode)
if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
}
}
core/vdom/patch 里有这个方法
我找了好久都没找到 create
hook的来源,我去我的一个项目里加了断点,测了几个地方发现这个地方根本没有执行,所以i.create(emptyNode, vnode)
这一句到底是什么作用?
在 2.6.x
版本中,我看到 Vue
把 nextTick
又重新换成 mircoTask
的实现了, 那很好奇 2.4.x
之前版本中就是 microTask
,也存在一些问题,诸如 #4521
, #6690
,#6566
等。那这次重新回归到 microTask
, Vue
又是怎么解决了上述问题的,我用最新版本测试了一下,好像都是ok的。
next-tick.js
/* @flow */
/* globals MutationObserver */
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
export let isUsingMicroTask = false
const callbacks = []
let pending = false
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
// Here we have async deferring wrappers using microtasks.
// In 2.5 we used (macro) tasks (in combination with microtasks).
// However, it has subtle problems when state is changed right before repaint
// (e.g. #6813, out-in transitions).
// Also, using (macro) tasks in event handler would cause some weird behaviors
// that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109).
// So we now use microtasks everywhere, again.
// A major drawback of this tradeoff is that there are some scenarios
// where microtasks have too high a priority and fire in between supposedly
// sequential events (e.g. #4521, #6690, which have workarounds)
// or even between bubbling of the same event (#6566).
let timerFunc
// The nextTick behavior leverages the microtask queue, which can be accessed
// via either native Promise.then or MutationObserver.
// MutationObserver has wider support, however it is seriously bugged in
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
// completely stops working after triggering a few times... so, if native
// Promise is available, we will use it:
/* istanbul ignore next, $flow-disable-line */
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
// In problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
// PhantomJS and iOS 7.x
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
// Use MutationObserver where native Promise is not available,
// e.g. PhantomJS, iOS7, Android 4.4
// (#6466 MutationObserver is unreliable in IE11)
let counter = 1
const observer = new MutationObserver(flushCallbacks)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
// Fallback to setImmediate.
// Techinically it leverages the (macro) task queue,
// but it is still a better choice than setTimeout.
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
// Fallback to setTimeout.
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
if (!pending) {
pending = true
timerFunc()
}
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
在Vue构造函数那段说,不用class是方便Vue按功能分散到多个模块对prototype进行扩展,而class难以实现,这里不太明白。class应该只是语法糖,对class的prototype也是可以扩展的,而且效果一样。不明白有何区别,还请老师指点
黄老师,电子书打不开了
你好, 在 派发 更新 中,我怎么没有看到确定哪个 数据 需要 更新呢 , 求老师指教
子组件调用$emit函数,返回值是该组件的this,作者为啥要返回this,别的不行吗
代码如下:
https://jsfiddle.net/afenotes/bkjxvr07/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>VUE</title>
<script src="https://unpkg.com/[email protected]"></script>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<ul id="list">
<li v-for="(l,index) in list" v-bind:key="index" :ref='"li"+index'>{{l}}</li>
</ul>
<script>
var ul = new Vue({
el: '#list',
data: {
list: ['apple','banana','orange']
}
})
setTimeout(function(){
// $('<li>grape</li>').prependTo($('#list'))
$('#list').children().first().text('grape')
}, 3000);
setTimeout(function(){
ul.list = ['Bob','Tom','Jim']
}, 6000);
</script>
</body>
</html>
初始渲染结果:
3s后,渲染结果:
6s后,实际渲染结果:
期望结果:
为什么第一个元素没有更新?猜测virtual dom到真实dom之间的映射丢了,求指点。
(知道这个混用不对,好奇背后的原理)
你好,我阅读vue的源码,发觉在setter已经做了次差值比较,watcher也经过了去重处理,然后却又再watcher.run做了一次新旧值比较(只比对primitive类型),才决定是否执行cb回调。那这个比较会在什么情景下会有用?还是其实基本是多余的?
麻烦指点一下,谢谢
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.