1.Vue2源码学习笔记 - 7.响应式原理一基础
2.面试中的码研网红Vue源码解析之虚拟DOM,你知多少呢?深入解读diff算法_百度...
3.学习vue源码(18)三探生命周期之初始化provide与inject
4.Vue2源码解析?2?初始化
5.为什么很多人说尤雨溪根本不懂vue?
6.å
¬å¸ç¨vueè¿ç¨åçå(大å
¬å¸å¾å°ç¨vue)
Vue2源码学习笔记 - 7.响应式原理一基础
深入研究 Vue 的响应式核心,了解响应式机制在 Vue 中的码研核心地位。Vue 的码研响应式原理,让数据模型简单直接地管理状态,码研无需侵入性操作。码研
当你将普通 JavaScript 对象作为 Vue 实例的码研支付后复制源码 data 选项时,Vue 会遍历对象属性并使用 Object.defineProperty 转换为 getter 和 setter。码研此特性仅在 ES5 中可用,码研不支持 IE8 及以下浏览器。码研
这些 getter 和 setter 在内部追踪依赖,码研当属性被访问或修改时,码研会通知 Vue。码研类似于 PHP 的码研魔术方法或 Java 的 getXXX\setXXX,但实现上存在差异。码研Java 可能拥有更接近的码研实现,比如 CGLib。
每个 Vue 组件实例对应一个 watcher,记录接触过的数据属性为依赖。当依赖项的 setter 触发时,watcher 被通知,组件重新渲染。
简单 demo 通过 defineReactive 实现响应式设置,允许访问 data 中的属性,设值触发 setter,引用触发 getter。此方法依赖于 Object.defineProperty,是响应式原理的核心。
Proxy 是爱客影院源码 3.4 ES 定义的类,用于创建对象代理,实现基本操作拦截和自定义。通过简单的 demo 可见,更新和引用数据时会调用 setter/getter 方法。Vue2 使用 Proxy,但用途不多。
总结,学习 Object.defineProperty 和 Proxy 实现响应式的底层方法。它们在数据更新和引用时触发特定方法,执行期望的操作实现响应式。下篇深入 Vue 响应式实现。
面试中的网红Vue源码解析之虚拟DOM,你知多少呢?深入解读diff算法_百度...
虚拟DOM(Virtual DOM)是Vue的一个核心概念,它是一种用JavaScript对象来表示真实DOM结构的轻量级抽象。通过使用虚拟DOM,Vue可以在内存中构建和操作DOM,并通过Diff算法来高效地更新真实DOM。
虚拟DOM工作原理:
1. 在Vue中,每个组件都有一个对应的虚拟DOM树,它是一个以组件根节点为起点的JavaScript对象。
2. 当数据发生改变时,Vue会重新计算虚拟DOM树的结构,并和旧的虚拟DOM树进行比较。
3. 在比较过程中,Vue使用Diff算法来找出两棵树之间的差异,并将差异记录下来。
4. 最后,Vue根据差异的网页浏览器源码记录,批量更新真实DOM,只更新需要改变的部分。
Diff算法:
Diff算法是虚拟DOM的核心,它用于比较新旧虚拟DOM树之间的差异。Vue中使用的是经典的Diff算法,具体包括以下几个步骤:
1. Walk:遍历新旧虚拟DOM树,对比节点,并记录差异。
2. Update:根据差异进行更新。如果节点类型不同,直接替换整个节点;如果节点类型相同,比较其属性和子节点。
3. Diff Attributes:比较节点的属性差异。添加、删除或更新属性。
4. Diff Children:比较节点的子节点差异。通过递归调用Diff算法,找出子节点之间的差异。
5. Keyed Diff:Vue还提供了基于key的优化方式。通过使用唯一的key来识别和复用相同节点类型的子节点,提高Diff算法的效率。
Diff算法的核心思想是最小化操作,只对有差异的部分进行更新,避免不必要的DOM操作,提高性能和效率。
需要注意的是,虚拟DOM和Diff算法并不是大漠注册怎么封装源码Vue独有的概念,其他前端框架如React也采用了类似的原理。它们都通过虚拟DOM和Diff算法来提高渲染效率,减少对真实DOM的操作次数。
深入理解和研究Vue源码的虚拟DOM和Diff算法,可以帮助开发者更好地了解Vue框架的工作原理,并且在实际开发中更有效地使用和优化Vue应用程序。
学习vue源码()三探生命周期之初始化provide与inject
在深入研究Vue源码()的学习中,我们重点关注了初始化阶段的生命周期钩子——initInjections和initProvide。这两个概念在created钩子函数触发前,beforeCreate钩子之后,为组件间的通信提供了重要手段。
provide和inject是一对核心概念,它们的作用在于跨层级组件间的数据传递。父组件通过provide方法提供数据,而子组件则通过inject方法注入这些数据。它们解决了多级组件间数据共享的问题,避免了过多的$parent属性调用和代码结构的混乱。
provide是一个对象或返回对象的函数,通常包含子孙组件可注入的属性,可以使用ES6的Symbols作为键。而inject则接受字符串数组或对象,用于在本地绑定中查找并设置数据。通过实例,我们看到它们的工作原理:提供者通过vm._provided传递数据,消费者通过resolveInject方法查找并设置接收的数据。
源码分析显示,provide将提供数据存储在Vue实例的电脑主图指标源码全局数据中,而inject则在搜索到提供者的数据后,为这些数据设置getter和setter。在写inject时,通常需要为from属性指定的键或默认值,或者提供一个默认工厂方法。
总的来说,理解并熟练运用provide和inject,是构建高效、可维护的Vue组件架构的关键。接下来,我们会详细研究initState,以全面探索Vue的初始化过程。
Vue2源码解析?2?初始化
活着,最有意义的事情,就是不遗余力地提升自己的认知,拓展自己的认知边界。在搭建源码调试环境一节中,我们已经找到了Vue的构造函数,接下来开始探索Vue初始化的流程。
一个小测试在精读源码之前,我们可以在一些重要的方法内打印一下日志,熟悉一下这些关键节点的执行顺序。(执行npmrundev后,源码变更后会自动生成新的Vue.js,我们的测试html只需要刷新即可)
在初始化之前,Vue类的构建过程?在此过程中,大部分都是原型方法和属性,意味着实例vm可以直接调用
注意事项:
1、以$为前缀的属性和方法,在调用_init原型方法的那一刻即可使用
2、以_为前缀的原型方法和属性,谨慎使用
3、本章旨在了解Vue为我们提供了哪些工具(用到时,深入研究,不必要在开始时花过多精力,后边遇到时会详细说明)
4、类方法和属性在newVue()前后都可以使用,原型方法和属性只能在newVue()后使用
定义构造函数//src/core/instance/index.jsfunctionVue(options){ //形式上很简单,就是一个_init方法this._init(options)}挂载原型方法:_init//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }挂载与state相关的原型属性和原型方法//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}挂载与事件相关的原型方法//src/core/instance/events.jsconsthookRE=/^hook:/Vue.prototype.$on=function(event:string|Array<string>,fn:Function):Component{ }Vue.prototype.$once=function(event:string,fn:Function):Component{ }Vue.prototype.$off=function(event?:string|Array<string>,fn?:Function):Component{ }Vue.prototype.$emit=function(event:string):Component{ }挂载与生命周期相关的原型方法//src/core/instance/lifecycle.jsVue.prototype._update=function(vnode:VNode,hydrating?:boolean){ }Vue.prototype.$forceUpdate=function(){ }Vue.prototype.$destroy=function(){ }挂载与渲染相关的原型方法//installruntimeconveniencehelpersinstallRenderHelpers(Vue.prototype)Vue.prototype.$nextTick=function(fn:Function){ }Vue.prototype._render=function():VNode{ }挂载Vue类方法和类属性//src/core/global-api/index.js//configconstconfigDef={ }configDef.get=()=>configObject.defineProperty(Vue,'config',configDef)Vue.util={ warn,extend,mergeOptions,defineReactive}Vue.set=setVue.delete=delVue.nextTick=nextTick//2.6explicitobservableAPIVue.observable=<T>(obj:T):T=>{ observe(obj)returnobj}Vue.options=Object.create(null)ASSET_TYPES.forEach(type=>{ Vue.options[type+'s']=Object.create(null)})Vue.options._base=Vueextend(Vue.options.components,builtInComponents)initUse(Vue)//挂载类方法use,用于安装插件(特别特别重要)initMixin(Vue)//挂载类方法mixin,用于全局混入(在Vue3中被新特性取代)initExtend(Vue)//实现Vue.extend函数initAssetRegisters(Vue)//实现Vue.component,Vue.directive,Vue.filter函数挂载平台相关的属性,挂载原型方法$mount//src/platforms/web/runtime/index.js//installplatformspecificutilsVue.config.mustUseProp=mustUsePropVue.config.isReservedTag=isReservedTagVue.config.isReservedAttr=isReservedAttrVue.config.getTagNamespace=getTagNamespaceVue.config.isUnknownElement=isUnknownElement//installplatformruntimedirectives&componentsextend(Vue.options.directives,platformDirectives)extend(Vue.options.components,platformComponents)//installplatformpatchfunctionVue.prototype.__patch__=inBrowser?patch:noopconsole.log('挂载$mount方法')//publicmountmethodVue.prototype.$mount=function(el?:string|Element,hydrating?:boolean):Component{ }拓展$mount方法//src/platforms/web/entry-runtime-with-compiler.jsconstmount=Vue.prototype.$mount//保存之前定义的$mount方法Vue.prototype.$mount=function(el?:string|Element,hydrating?:boolean):Component{ //执行拓展内容returnmount.call(this,el,hydrating)//执行最初定义的$mount方法}Vue的初始化过程(很重要哦!!!)熟悉了初始化过程,就会对不同阶段挂载的实例属性了然于胸,了解Vue是如何处理options中的数据,将初始化流程抽象成一个模型,从此,当你看到用户编写的options选项,都可以在这个模型中演练。
前边我们提到过,Vue的构造函数中只调用了一个_init方法
执行_init方法//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ constvm:Component=this//此刻,Vue的实例已经创建,只是雏形,但Vue的所有原型方法可以调用//aflagtoavoidthisbeingobserved//(observe会在后面的响应式章节详细说明)vm._isVue=true//mergeoptionsif(options&&options._isComponent){ //在后面的Vue组件章节会详细说明//optimizeinternalcomponentinstantiation//sincedynamicoptionsmergingisprettyslow,andnoneofthe//internalcomponentoptionsneedsspecialtreatment.initInternalComponent(vm,options)}else{ vm.$options=mergeOptions(//合并optionsresolveConstructorOptions(vm.constructor),//主要处理包含继承关系的实例()options||{ },vm)}//exposerealselfvm._self=vminitLifecycle(vm)//初始化实例中与生命周期相关的属性initEvents(vm)//处理父组件传递的事件和回调initRender(vm)//初始化与渲染相关的实例属性callHook(vm,'beforeCreate')//调用beforeCreate钩子,即执行beforeCreate中的代码(用户编写)initInjections(vm)//resolveinjectionsbeforedata/props获取注入数据initState(vm)//初始化props、methods、data、computed、watchinitProvide(vm)//resolveprovideafterdata/props提供数据注入callHook(vm,'created')//执行钩子created中的代码(用户编写)if(vm.$options.el){ //DOM容器(通常是指定id的div)vm.$mount(vm.$options.el)//将虚拟DOM转换成真实DOM,然后插入到DOM容器内}}initLifecycle:初始化与生命周期相关的实例属性//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }0initEvents(vm):处理父组件传递的事件和回调//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }1initRender(vm):初始化与渲染相关的实例属性//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }2CallHook(vm,'beforeCreate'):执行beforeCreate钩子执行options中,用户编写在beforeCreate中的代码
//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }3initInjections(vm):resolveinjectionsbeforedata/props获取注入数据//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }4initState(vm):初始化props、methods、data、computed、watch(划重点啦!!!)//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }5initProps:初始化props此处概念比较多,propsData、props、vm._props、propsOptions,后续会结合实例来分析其区别,此处只做大概了解。
//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }6initMethods:初始化methods//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }7initData:初始化data//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }8initComputed:初始化computed选项//src/core/instance/init.jsVue.prototype._init=function(options?:Object){ }9initWatch:初始化watchcreateWatcher:本质上执行了vm.$watch(expOrFn,handler,options)
//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}0initProvide(vm):提供数据注入为什么provide初始化滞后与inject,后续补充
//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}1CallHook(vm,'created'):执行created钩子中的代码callHook的相关逻辑,参考上面的callHook(vm,'beforeCreate')
执行挂载执行$mount扩展通过下面的代码可知:当用户代码中同时包含render,template,el时,它们的优先级依次为:render、template、el
//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}2$mount方法中,首先获取挂载容器,然后执行mountComponent方法
//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}3//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}4在_update方法中,通过_vnode属性判断是否初次渲染,patch其实就是patch方法,关于patch的详细逻辑,将在diff算法章节详细说明。
//src/core/instance/state.jsconstdataDef={ }dataDef.get=function(){ returnthis._data}constpropsDef={ }propsDef.get=function(){ returnthis._props}Object.defineProperty(Vue.prototype,'$data',dataDef)Object.defineProperty(Vue.prototype,'$props',propsDef)Vue.prototype.$set=setVue.prototype.$delete=delVue.prototype.$watch=function(expOrFn:string|Function,cb:any,options?:Object):Function{ //略}5原文:/post/为什么很多人说尤雨溪根本不懂vue?
在Vue的世界里,关于尤雨溪是否真正理解Vue的争议不绝于耳。尽管尤雨溪在Vue的面试过程中曾遇到过一些棘手的问题,让一些观察者质疑他的全面掌握,但单纯说他‘不懂’Vue是否有些过于武断。有些人指出,他在深入研究框架的过程中确实遇到了官方文档未曾详述的特定用法,但这是否意味着他对Vue的原理和实践缺乏深入理解呢? 确实,尤雨溪作为Vue的重要开发者,他的技术实力不容小觑。然而,任何人都不可能对一个庞大且不断演进的框架做到无所不知。Vue的复杂性和灵活性意味着,即使是经验丰富的开发者,也可能在某些边缘或新颖的用法上遇到挑战。这并不等同于不懂,而是一个学习和探索的过程。 重要的是,尤雨溪对Vue的贡献和他对开源社区的贡献是显而易见的,他的工作推动了框架的发展,并激发了无数开发者的学习热情。我们不能仅凭偶尔的失误或未被官方提及的用法,就否定他作为Vue核心人物的地位。 因此,尽管有些人会指出尤雨溪在Vue理解上的局限性,但更公正的评价应该是,他在Vue领域的深厚造诣和他对技术的持续追求,使他成为了一个值得尊敬和学习的开发者。我们应该以开放的态度看待他的学习过程,而不是简单地贴上“不懂”的标签。å ¬å¸ç¨vueè¿ç¨åçå(å¤§å ¬å¸å¾å°ç¨vue)
vueæå æappè·åçAPP对æ¯
webapp项ç®å·²ç»éè¿vue-cliæ建çèææ¶å好äºï¼ç¶åéè¿webpackæå æä¸ä¸ªé¨ç½²æ件listï¼å¦ä¸ï¼æå¼HBuliderï¼æå¼ç®å½ï¼éæ©è¿ä¸ªlistï¼é¡¹ç®å称èªå·±æ´æ¹ã
vueåuni-appçåºå«å¦ä¸ï¼uni-appå¯ä»¥éè¿æå å®ç°ä¸å¥ä»£ç å¤ç«¯è¿è¡ï¼èvueä¸è¡ãuni-appæèªå¨çæ¡æ¶é¢è½½ï¼å 载页é¢çé度æ´å¿«ï¼vue没æãuniapp使ç¨å°ç¨åºçæ ç¾ï¼vue使ç¨web端çæ ç¾ã
å¯ä»¥çå¢ï¼éè¿ç¬¬ä¸æ¹çæ··åå¼åå·¥å ·é½å¯ä»¥æè¿ä¸ªæå åæAPPã
å¨App端ï¼å¦æ使ç¨vue页é¢ï¼å使ç¨webview渲æãå¦æ使ç¨nvue页é¢ï¼nativevueç缩åï¼ï¼å使ç¨åç渲æãä¸ä¸ªAppä¸å¯ä»¥åæ¶ä½¿ç¨ä¸¤ç§é¡µé¢ï¼æ¯å¦é¦é¡µä½¿ç¨nvueï¼äºçº§é¡µä½¿ç¨vue页é¢ï¼hellouniapp示ä¾å°±æ¯å¦æ¤ã
è¿ç§æ åµåå å¦ä¸ï¼æ ¹æ®æ¥è¯¢ä¸å½ç¼ç¨ç½ä¿¡æ¯æ¾ç¤ºï¼vueçtemplateç¼è¯å¨ï¼vueå°templateç¼è¯æäºrenderfunctionï¼ä½¿å¾å¨æµè§å¨ä¸æ é解ætemplateå符串ï¼è¿å¤§å¹ 度åå°äºvueæå åçä½ç§¯ã
为ä»ä¹å¤§å ¬å¸å¾å°ç¨vue?
1ãå¦æè¿å®¶å ¬å¸åè¯ä½ ï¼ä»ä»¬å°±åªä¼ç¨Vueï¼ä½ è¦å°å¿äºï¼å 为ï¼è¿ç§å ¬å¸ä¸å®å æ¥çåç§å端å°ç½ï¼è¿äºäººæ²¡ç¨è¿å ¶å®ä»»ä½æ¡æ¶ï¼çè³è¿å¿«éå¦ä¹ ä¸é¨æ°çç¼ç¨è¯è¨é½æå°é¾ï¼ä½æ¯è¿ä¸å¦¨ç¢ä»ä»¬æèµ·é®çåºæ¥è¡è¯´å «éã
2ãä¸æ¯ä¸ç¨ï¼ä¹ä¸æ¯Vue驾é©ä¸äºï¼èæ¯Vuexä¸æ¯æä¼è§£æ¹æ¡ãVuexçOptionsAPIéç项ç®çè§æ¨¡åå¤ææ§çå¢é¿ï¼ç»´æ¤çææ¬å¢å ãé 读ææ¬ç¿»åãå没æä¸ç§å¾å¥½çé»è¾å¤ç¨æ¹å¼ãé¢æ¡å¼ä»£ç æ æ³é¿å ã
3ãå 为Vueæ¯ä¸ä¸ªåºäºJavaScriptçæ¡æ¶ï¼å®çç¹æ§å æ¬æ¡æ¶çç®åæ§ï¼æäºéæï¼ç¨æ·å好æ§ï¼è¾å°çéå¶ï¼è¿äºåå å·²ç»å¸®å©Vueä¸AngularåReactç«äºã
4ãç¨æ·ä½éªä¸å¤å¥½ä¸ç®¡å产åè¿æ¯åæå¡ï¼å硬件è¿æ¯å软件ï¼æ¯å¨äºèç½è¿æ¯ä¼ ç»è¡ä¸ï¼ææ ¸å¿æ¯æ¼çæ¯ç¨æ·ä½éªã
5ãé¨é¨ä¹é´çåè°æçä¸ï¼å 为大å项ç®ä¸æ¯ä¸ä¸¤ä¸ªäººï¼ä¸äºä¸ªäººè½å¤å®æçãä¸ä¸ªé¡¹ç®ä¹æ以称为大项ç®æ¯å¨äºå®æ¯å ¬å¸å¤§éé¨é¨åååä½ä¸ç产ç©ãä¹å°±æ¯è¯´ï¼è§£å³äºé¡¹ç®ååçé®é¢ï¼ä½¿ç¨vueåreacté½æ¯å¯ä»¥çã
6ãå½å ç¨vueå¼å项ç®çç¹å«å¤ï¼æ¯ç«ç¨vueä¸æå¿«ï¼å¼åææ¬ä½ã
çµååå°ç®¡çç³»ç»çå端ææ¯æ ---vue1ã该项ç®ä¸»è¦æ¯ä¸ä¸ªçµåçåå°ç®¡çç³»ç»ï¼å¯å®ç°ç®¡çç¨æ·è´¦å·ï¼å³ç»å½ãéåºãç¨æ·ç®¡çãæé管ççï¼åå管çï¼å³åååç±»ãåç±»åæ°ãååä¿¡æ¯ï¼è®¢åä¿¡æ¯ç以åæ°æ®ç»è®¡ã
2ãçµå管çå¹³å°ä¸»è¦ä½¿ç¨vueçWebææ¯å¯¹å ¶è¿è¡ç 究设计ä¸å®ç°ï¼æ¨å¨æ´å é«æã便æ·å°ç®¡çåå°ä¼ å ¥çæ°æ®ï¼ä¸è½å¤å¸®å©ä½¿ç¨è æ´å¥½å°è¿è¡ç¨æ·ï¼åå以å订å管çã
3ãVue.jsæ¯ä¸å¥æ建ç¨æ·çé¢çæ¸è¿å¼æ¡æ¶ï¼Vueéç¨èªä¸åä¸å¢éå¼åç设计ï¼å ¶æ ¸å¿åºåªå ³æ³¨è§å¾å±ï¼æäºä¸æï¼åæ¶vueå®å ¨æè½å驱å¨éç¨åæ件ç»ä»¶åVueçæç³»ç»æ¯æçåºå¼åçå¤æå页åºç¨ã
4ãæ³è¦å°å端Vue+åå°ç®¡çç³»ç»ä¸çº¿ï¼éè¦ä»¥ä¸æ¥éª¤ï¼å°å端Vueç¨åºæå 为éææ件ï¼ä½¿ç¨npmæyarnè¿è¡å½ä»¤ï¼npmrunbuildæyarnbuildãå¨ä½ çæå¡å¨ä¸ï¼å¯ä»¥ä½¿ç¨FTPæSCPçå·¥å ·å°éææ件ä¸ä¼ å°æå¡å¨ã
5ãuni-appï¼uni-appæ¯ä¸ä¸ªä½¿ç¨Vue.jså¼åææå端åºç¨çæ¡æ¶ï¼å¼åè ç¼åä¸å¥ä»£ç ï¼å¯åå¸å°iOSãAndroidãH以ååç§å°ç¨åºï¼å¾®ä¿¡/æ¯ä»å®/ç¾åº¦/头æ¡/QQ/éé/æ·å®ï¼ãå¿«åºç¨çå¤ä¸ªå¹³å°ã
为ä»ä¹æ²¡æ人å¼åvue转åçè¿ç§å ¬å¸çææ¯è´è´£äººå¾å¯è½æ¯ä¸ªå°ç½ï¼è³å°æ¯ä¸ªç²ç®çè·é£è ãä»èªå·±æ¯ä¸ä¼å»ç 究ææ¯çï¼å¬å«äººå¿½æ 就好äºãä½ å»å¸®è¿ç§äººåäºï¼æ³¨å®æ¯ä¸æå¡«åçå½è¿ãè¿ç§å ¬å¸ä¸å®æ²¡æè§èçå¼åæµç¨ï¼å¯è½è¿CIç³»ç»é½æ²¡æã
对äºåä¸å ¬å¸ä¸è¬èµ·æ¥ç产åé½æ¯ä¿¡æ¯ç±»ï¼æ¯å¦ç¥ä¹ãå¾®åãååç±»ï¼å¹¶æ²¡æ太å¤å¯¹åºå±ç¡¬ä»¶çä¾èµçåºç¨ï¼çios+å®å客æ·ã
å¯ä»¥çå¢ï¼éè¿ç¬¬ä¸æ¹çæ··åå¼åå·¥å ·é½å¯ä»¥æè¿ä¸ªæå åæAPPã
APPæ§è½æ¹é¢ï¼åçAppï¼è½å¤ä¸ç§»å¨ç¡¬ä»¶è®¾å¤çåºå±åè½ï¼æ¯å¦ä¸ªäººä¿¡æ¯ï¼æå头以åéåå éå¨ççãç½ç«å¶ä½çAppï¼åªè½ä½¿ç¨æéç移å¨ç¡¬ä»¶è®¾å¤åè½ã
ç¥å度ä½ãvue3ç¨ç人太å°äºæ¯ç±äºç¥å度ä½ï¼vue3æä¾äºæ´å¥½çæ§è½ï¼æ´å°çæç»å ä½ç§¯ï¼æ´å¥½çTSéæï¼ç¨äºå¤ç大è§æ¨¡ç¨ä¾çæ°APIã0çæ¬çvueï¼å¼åå¨æé¿è¾¾ä¸¤å¹´å¤ã
å¶å°ç¢°å°HBuilderè¿ä¸ªå½äººå·¥å ·ï¼è½ç´æ¥å°WebAppï¼HTML+CSS+javascriptï¼ï¼æå æåçå®åAppï¼é£å°±è¯è¯å§Webåºç¨æå æææºAppï¼éç¹èæ¥ï¼æµç ç¨åº¦åè½å®å度å¼å便æ·åº¦ãã
å¤§å ¬å¸å端ä¸è¬ç¨vueè¿æ¯react1ãæ ¹æ®ä¸åæ¡æ¶ä¼ç¹ï¼æ们å¨å®é 项ç®å¼åéåä¸ä¸è¬ä¸å°å项ç®æ们ä¼éæ©ä½¿ç¨Vueï¼å¤§å项ç®ä¼éæ©Reactã
2ãä½ä¸ºä¸ä¸ªä¸ä¸å端ï¼å»ºè®®åæå¦Vueï¼åæåå¦Reactï¼åä¹ï¼å¦æä¹åç´æ¥å¦çReactï¼åä¸è¬ä¸éè¦åå»å¦Vueäºï¼å项ç®ï¼éä¸ä¸ªå°±è¡äºã
3ãé½ç¨ãvueåreactå¨å¤§å ¬å¸ä¸é½å¾å¸¸ç¨ãå¹´Reactå·©åºäºå®ä½ä¸ºå端æ¡æ¶ä¹ççå°ä½ï¼è¿ä¸å¹´ä¸å¯ä»¥çå°å®å¨Web端å移å¨ç«¯çå¿«éæé¿ï¼åæ¶ç¨³ç¨³é¢å äºå®ç主è¦ç«äºå¯¹æAngularã
vueæ ¹æ®åççæ¬å·è¿è¡çæ¬æ§å¶1ãvuecliæ¹esçæ¬éè¿ä»¥ä¸ä¸¤ä¸ªæ¥éª¤å®æãå¸è½½å½åçæ¬ï¼ä½¿ç¨å½ä»¤npmuninstall-g@vue/cliå³å¯ã使ç¨å½ä»¤npmi-g@vue/cli@0.4å®è£ esçæ¬å³å¯ã
2ãå¨Vueè·¯ç±ç³»ç»ä¸å¯ä»¥æ¹åçæ¬å·ï¼åªéå¨é¡¹ç®çpackage.jsonæ件ä¸æ¾å°å段versionï¼ç¶åæ´æ¹å ¶å¼å³å¯ã
3ãæ¤å¤ï¼æ¶é´æ³é常æ¯ä»¥ç§ä¸ºåä½ï¼èçæ¬å·ä¸è½ä»¥ç§ä¸ºåä½ï¼å æ¤éè¦åä¸äºå¤çæè½ç¨æ¶é´æ³å½çæ¬å·ãå¦å¤ï¼ç¨æ¶é´æ³åçæ¬å·ä¸å©äºçæ¬æ§å¶åå¤ä»½ï¼å 为æ¶é´æ³å¯è½ä¼ååï¼è¿æ ·å°±ä¼å¯¹çæ¬æ§å¶äº§çå½±åã
4ãvueï¼4ï¼2vue-template-compilerï¼4ï¼ï¼æ³¨ï¼å¦ä¸æ示çæ¬å·åä¸ºæ ·ä¾ï¼å ·ä½å®ç°è¯·å°ä¼ä¼´ä»¬æ ¹æ®èªå·±ççæ¬å·å¯¹åºï¼ç¶åæ§è¡ï¼npmupdateå°±å¯ä»¥äºã
5ãçæ¬å·å¨package.jsonéæï¼å¦ææå¾ççæ¬å·å°±å®è£ ææ°çï¼æ§è¡npminstallneo-async@latestï¼ææ°çå¯è½ä¸å ¶ä»å ä¸å ¼å®¹ï¼ææ建议åpackage.jsonä¸ä¿æä¸è´ï¼ãå¦å¤installæ¶ï¼å»ºè®®ä½¿ç¨æ·å®éåï¼å¯ä»¥åèè¿ç¯æç« ã
6ãè°ç äºå¾å¤æ¡æ¶å模å¼ï¼æåèªå·±ä¸æ¼è¥¿åæåºæ¥äºè¿ä¹ä¸ä¸ªç©æãæå¡ç«¯æ¯«æ çé®ä½¿ç¨nodeï¼ä½¿ç¨typescriptå¯ä»¥ææçå¨ç¼ç åæ¶æ¥éï¼å¼ºç±»åè¯è¨åæå¡ç«¯æ¯«æ ååã
ç°å¨ç¨vueçå ¬å¸å¤å(ç°å¨ç¨vueçå ¬å¸å¤åç¥ä¹)
个人ç½ç«ä¸»é¡µä¸è¬ç¨vueå
个人ç½ç«ä¸»é¡µä¸è¬ä¸ç¨vueãå½å çå¦ä¸ç½ç«ç¨äºvueæ¡æ¶ï¼bilibiliæéBç«ï¼ç®ä¹¦ï¼å¾®ä¿¡çå¼åææ¡£ç½ç«ãVueåªå ³æ³¨è§å¾å±ï¼éç¨èªåºåä¸å¢éå¼åç设计ï¼Vueçç®æ æ¯éè¿å°½å¯è½ç®åçAPIå®ç°ååºçæ°æ®ç»å®åç»åçè§å¾ç»ä»¶ã个人ç½ç«ä¸»é¡µä¸è¬ä¸ç¨ã
å½å ååå¸vueåreactå æ¯7:3ãå½å ååå¸vueåreactå æ¯7:3ãå¨å½å 大é¨åå端ç¨åºåç¨Vueæ¯è¾å¤ï¼æ¯è¾å¥½ä¸æï¼å¨å ä¸å¯¹ä¸æå好ï¼éå°é®é¢æç´¢åºçä¸æç»ææ¯è¾å¤ï¼èä¸å¯¹äºä¸äºå½å ä¸å°åå ¬å¸ï¼å¤§å¤æ°é½æ¯éç¨Vueå¼åã
å¤§å ¬å¸å¾å°ç¨vueçåå 为ä»ä¹å¾å°ç¨vueå¦æä»åè¯ä½ åªä¼Vueï¼ä½ ä¸å®è¦å°å¿äºï¼åå ï¼
1ãå¦æä»åªä¼Vueï¼é£ä»å°±ççåªä¼è¿ä¸ä¸ªä¸è¥¿äºãä½æ¯ï¼å¦æä»åæ¶è¿ä¼Angularæè å ¶å®ä¸äºå端æ¡æ¶ï¼ä¸è¬å°±æå³çè¿ä¸ªäººçæ§ä»·æ¯ä¼é常é«ãé¦å ï¼å¦æä»ä¼Angularï¼é£ä¹éä½ä¸ä¸ªç»´åº¦å»åVueæ¯å®å ¨æ²¡æé®é¢çï¼æ¯ç«Vueéé¢å¤§é¨åå 容é½æ¯ä»AngularJS1.xï¼èä¸æ¯æ°çæ¬Angularï¼éé¢æåºæ¥çãå ¶æ¬¡ï¼å¤§éçAngularå¼åè é½åæ¶ä¼ä¸ç§æå ç§å端è¯è¨ï¼å¦JavaåC#ï¼è¿å°±æå³çä½ ç¨åæ ·çå·¥é±æå°äºä¸ä¸ªè½å¹²æ´å¤äºæ ç人ã
2ãåªä¼Vueç人缺ä¹å¦ä¹ è½åï¼ä½ æå°çå¯è½åªæ¯ä¸ªâæ·è´å·¥ç¨å¸âãä½ ç»å¸¸çå°è¿ç§å°ç½ä¼å槽Typeæ¯ä»äººçéè·¯ä¸çéç¢ï¼èå®é ä¸Typeç大é¨åè¯æ³é½æ¥èªäºES6ï¼è¿æES7ï¼ï¼å¦æè¿ä¸ªäººè¿Typeé½è¯´é¾ï¼åªè½è¯´æä¸ä»¶äºæ ï¼ä»æ ¹æ¬å°±æ²¡å»å¦ES6åES7ï¼æè¿ES8ä¹åºæ¥äºï¼ãå®é ä¸Typeçå欢è¿ç¨åº¦è¿è¿è¶ è¶ä½ 们çæ³è±¡ï¼å æ¬ç®åæç«çå端å¼åå·¥å ·VSCodeæ¬èº«ä¹æ¯ç¨Typeå¼åçï¼åºå±æ¯Electronãä»å¦ä¸ä¸ªè§åº¦çï¼iOSä¸çå¼åè¯è¨å·²ç»æ¼è¿å°äºSwiftï¼Androidä¸ä¹å¼å§ä½¿ç¨æ°è¯è¨Kotlinäºï¼éç计ç®æºææ¯çå éåå±ï¼åç§ç¼ç¨è¯è¨è¿ä¼å éæ¼è¿ãæ以ï¼Typeä¸æ¯ä»äººçéè·¯ä¸çéç¢ï¼ä»æ大çéç¢æ¯ä»èªå·±ã
3ãåäºè§å¤©ãä¸è¬æ¥è¯´ï¼è½åæ¶ä½¿ç¨å¤ç§æ¡æ¶çå¼åè ï¼å¿é对åç§ææ¯é½æèªå·±ç¬å°çç解ãä»ä»¬ç¥éæ´ä¸ªäºèç½çåå±å²ãç¥éJavaè¯è¨æ¯æä¹ä¸æ¥ä¸æ¥åå±å°ä»å¤©çãç¥éECMAæ åæ¯æä¹ä¸åäºãç¥éåç§å端æ¡æ¶å¨è®¾è®¡ææ³ä¸çå¼åï¼å¨ä»çå¿éæä¸ä¸ªé常å®è§çç解ã
4ãç³ç³çè±ææ°´å¹³ãæå¾å¤äººåè¯è¿æï¼ä»ä»¬ä¹æ以ç¨ä¸äºVueï¼æ¯ä»¥ä¸ºä¸æææ¡£åå¾å¥½ï¼è¿ä¸ç¹æèµåï¼ãåè¿æ¥è¯´æï¼è¿å¸®äººè±ææ°´å¹³æ¯è¾ç³ç³ãä¸ç´ä»¥æ¥ï¼è®¡ç®æºææ¯çåæºå°é½æ¯ç¡ è°·ï¼å°ä»å¤©ä¾ç¶å¦æ¤ãç¡ è°·ä¸ç´å¨åé åç§åæ ·çæ°ææ¯ãæ°ææ³ï¼èè¿äºä¸è¥¿æåé½æ¯è±æççãä¸æ¬ä¹¦ä»è±æçåºæ¥ï¼å°ç¬¬ä¸æ¬ä¸æçé¢å¸ï¼ç»å¸¸è¦å»¶è¿6个æ以ä¸çæ¶é´ï¼å¦æä½ æèçå¼åè è¿é 读è±æææ¯ææ¡£é½æå°é¾ï¼ä½ ä»¬å ¬å¸å°ä¼æ°¸è¿ææ¡äºæèµæã
5ãç³ç³çå¢éåä½ãä»ä¹åæç« ä¸é¢çè¯è®ºè½çåºæ¥ï¼åªä¼Vueçå°ç½å¯¹ä»ä»¬æç¨çæ¡æ¶å 满çå®æè¬çççï¼åªåä»ä»¬åºæ¥é»å«äººï¼å«äººå¦æèæ¢åºæ¥åªææ¯æ¾æ¸ ä¸ä¸ï¼é©¬ä¸å°±ååºç¬ä¸æ ·ç¸æ¯ãè¿ç§äººä¼æä½ çå¢éæ å¾ä¸å¢ç³ï¼è¿éçé½æ²¡æ³è®²ãåè¿æ¥ä¹æ¯æç«çï¼å¯¹äºæ£å¨è·³æ§½æè æç®æ¾å·¥ä½çå¼åè ï¼å½ä½ å»ä¸å®¶å ¬å¸é¢è¯çæ¶åï¼ä¹è¦é¿ä¸ªå¿ç¼å¿ï¼ä½ ä¸å®è¦é®ä¸é®ï¼ä»ä»¬å ¬å¸æ£å¨ä½¿ç¨ï¼æè æ¾ç»ç¨è¿ï¼åªäºå端æ¡æ¶ãå¦æè¿å®¶å ¬å¸åè¯ä½ ï¼ä»ä»¬å°±åªä¼ç¨Vueï¼ä½ è¦å°å¿äºï¼å 为ï¼
6ãè¿ç§å ¬å¸ä¸å®å æ¥çåç§å端å°ç½ï¼è¿äºäººæ²¡ç¨è¿å ¶å®ä»»ä½æ¡æ¶ï¼çè³è¿å¿«éå¦ä¹ ä¸é¨æ°çç¼ç¨è¯è¨é½æå°é¾ï¼ä½æ¯è¿ä¸å¦¨ç¢ä»ä»¬æèµ·é®çåºæ¥è¡è¯´å «éãä½ å»äºä¹åå¯è½è¦ç»ä»ä»¬æä¾ä¿å§ä¸æ ·çæå¡ï¼çè³è¿è¦æä»ä»¬å¦ä½æ建Nodeç¯å¢ã
7ãè¿ç§å ¬å¸çææ¯è´è´£äººå¾å¯è½æ¯ä¸ªå°ç½ï¼è³å°æ¯ä¸ªç²ç®çè·é£è ãä»èªå·±æ¯ä¸ä¼å»ç 究ææ¯çï¼å¬å«äººå¿½æ 就好äºãä½ å»å¸®è¿ç§äººåäºï¼æ³¨å®æ¯ä¸æå¡«åçå½è¿ã
8ãè¿ç§å ¬å¸ä¸å®æ²¡æè§èçå¼åæµç¨ï¼å¯è½è¿CIç³»ç»é½æ²¡æã以Vue为ä¾ï¼æ¡æ¶åå·¥å ·é½æ²¡æ对éææµè¯åä»»ä½æ¯æï¼æ以è¿ç§å ¬å¸ä¸å®ä»æ¥ä¸åéææµè¯çï¼å¦åä»ä»¬èæ©å°±ä¼åç°è¿ä¸ªé®é¢äºãä½ å»è¿æ ·çå ¬å¸ï¼é¤äºè®©å·²ç»å¦ä¼çæè½ä¸æéåè¿è½å¦å°ä»ä¹æ°ä¸è¥¿ï¼
9ãè¿ç§å ¬å¸æ²¡æé¿è¿æç®ãå¨ææ¯éåä¸ççè§å°±æå³ç管çå±æ¬èº«æ¯çè§çï¼ä»ä»¬ä»æ¥æ²¡æé¿è¿çæç®ï¼åå®ä¸ä¸ªä¸è¥¿æ¶ä¸æ³¢é±å®äºï¼è³äºç¨ä»ä¹ææ¯æ´å¥½ï¼ä¸ç¹é½ä¸éè¦ãå¨è¿æ ·çå ¬å¸åææ¯ï¼å«éäºãä»ä»¬ä¹æ以è¦ä½ å»ï¼åªæ¯æ³è®©ä½ éææ建ç¹å¿ä»ä¹ä¸è¥¿ï¼æ客æ·çé±å¿½æ å°æèå·²ã
vue3.0åé¢å¤å°å ¬å¸ä¼ç¨
é¨åå ¬å¸ãæ ¹æ®æ¥è¯¢vue3.0ç¸å ³ä¿¡æ¯å¾ç¥ï¼vue3.0åé¢æé¨åå ¬å¸å¨ä½¿ç¨ã7ææ¥ï¼Vue3.0è¿å ¥äºRC.2é¶æ®µãRCé¶æ®µå³æ¯åè¡åéçæ¬ï¼å¦ææªåºç°é®é¢åå¯åå¸æ为æ£å¼çæ¬ã
vue runtime源码分析学习——day4:createApp
在深入研究vue runtime源码时,我们首先确定了分析的路径和方法。
createApp这个关键入口点位于@vue/runtime-dom包中,它是开发者项目启动的起点。
在开始代码分析前,我们选择在packages\vue\__tests__\index.spec.ts中的测试用例进行,通常选择第一个即可,因为这里模拟的是客户端环境,但需确保testEvironment配置正确并配合jsdom库使用。
createApp方法内部包含一些开发环境特有的检查,如injectCompilerOptionsCheck和injectNativeTagCheck,它们在生产环境不会执行。通过Object.defineProperty绑定,可以防止这些检查被意外修改。
createApp的主要任务包括调用ensureRenderer、createAppApi和mount等。其中,ensureRenderer涉及到typescript的重载,而createAppApi则是通过缓存render和hydrate方法,优化性能。
在render部分,我们首次遇到reload,这是与vue-loader中热更新功能的联系点。尽管loader中的reload方法不接受参数,但它们本质上是处理相同逻辑的。
mount方法的核心内容是将js代码转化为DOM,它会处理createVNode和vnode的生成,以及与container._vnode的更新和比对,即旧vnode与新vnode的差异处理。
虽然今天的内容可能略显琐碎,但createApp的总体流程已经清晰了。后续将继续深入解析其他关键部分。