1.Vue2源码解析?2?初始化
2.每天学点Vue源码: 关于vm.$watch()内部原理
3.Vue中创建的main.js代码解析
4.Vue2源码细读-new Vue()初始化
5.Vue2.6x源码解析(一):Vue初始化过程
6.Vue computed 的内部实现原理
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的activerecord 源码实例已经创建,只是雏形,但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源码: 关于vm.$watch()内部原理
深入探讨Vue源码,解析vm.$watch()的内部原理,让我们从整体结构入手。使用vm.$watch()时,首先数据属性被整个对象a进行观察,itellyou源码这个过程产生一个名为ob的Observe实例。在该实例中,存在dep,它代表依赖关系,而依赖关系在Observe实例内部进行存储。接下来,我们聚焦于内部实现细节,深入理解vm.$watch()在源码中的运作机制。
在Vue的源代码中,实现vm.$watch()功能的具体位置位于`vue/src/core/instance/state.js`文件。从这里开始,我们移步至`vue/src/core/observer/watcher.js`文件,探寻更深入的实现逻辑。此文件内,watcher.js承担了关键角色,管理着观察者和依赖关系的关联。
在深入解析源码过程中,我们发现,当使用vm.$watch()时,Vue会创建一个Watcher实例,这个实例负责监听特定属性的变化。每当被观察的属性值发生变化时,Watcher实例就会触发更新,确保视图能够相应地更新。这一过程通过依赖的管理来实现,即在Observe实例内部,依赖关系被封装并存储,确保在属性变化时能够准确地通知相关的Watcher实例。
总的来说,vm.$watch()的内部实现依赖于Vue框架的观察者模式,通过创建Observe实例和Watcher实例来实现数据变化的监听和响应。这一机制保证了Vue应用的响应式特性,使得开发者能够轻松地在数据变化时触发视图更新,从而构建动态且灵活的应用程序。
Vue中创建的main.js代码解析
Vue.js 应用程序的入口文件 main.js 包含关键步骤,确保应用能够运行并与用户交互。
首行引入了 createApp 函数,这是 Vue 3 中创建应用实例的标准方法。这个函数生成一个用于创建 Vue 应用的新实例。
接下来,导入了根组件 App.vue,jediscluster源码这是整个应用的基础构建模块。所有其他组件和页面都是在这个组件的上下文中定义的。
导入 Vue Router 配置,该配置在文件 ./router 中定义了应用的路由规则。这允许应用实现页面间的导航,提供用户流畅的交互体验。
使用 createApp 函数创建了一个新的 Vue 应用实例,并传入了 App 组件。这个实例是整个应用的核心,所有功能模块都将挂载在这个实例上。
将 Vue Router 实例添加到应用实例中,激活了路由功能,允许定义多个页面并实现页面间导航。
最后,通过 app.mount('#app') 将应用实例挂载到 HTML 页面的指定元素上。这里 '#app' 是一个选择器,通常对应于 HTML 文件中的某个元素,比如
标签。这一步确保了应用的内容能够显示在网页的特定部分。
整个 main.js 文件的目的是初始化并启动 Vue.js 应用程序。它创建应用实例、配置路由,并将应用挂载到 DOM,实现了组件、路由等各部分的集成,形成一个完整、动态的交互式应用。
挂载应用到 DOM 是指将 Vue 应用的内容插入到 HTML 页面的一个特定区域。Vue 框架接管了这个区域,并根据应用逻辑动态渲染和更新内容。这一过程使得应用成为动态、可交互的界面,提供给用户无缝的体验。
总的来说,main.js 文件是 Vue.js 应用的核心,它负责启动应用、配置组件和路由,并将应用内容挂载到页面上,实现了应用的完整运行和用户交互。
Vue2源码细读-new Vue()初始化
Vue.js 是一个数据驱动的前端框架,其核心是proxy源码通过数据生成视图,开发者更关注数据模型与流转而非视图生成。
从 new Vue() 开始,我们将探索 Vue 实例的创建过程。新创建的 Vue 实例本质上是一个 Vue 的实例对象。Vue 作为构造函数,只能通过 new 操作符创建实例,核心功能是调用初始化方法 _init,并传入参数。
Vue 的实现中,构造函数定义了多个 mixin,这些 mixin 被挂载到 Vue.prototype,以降低耦合度,便于维护。初始化流程包括多个模块的挂载,如初始化、数据状态、事件发布订阅、生命周期与渲染。
初始化过程主要分为三个阶段:手动调用场景和组件场景。手动调用场景指直接创建的 Vue 实例,优先级高于组件场景。组件场景涉及全局或局部注册的组件,组件创建和继承通过 Vue.extend 实现。
组件创建过程中,Vue.extend 用于获取组件构造函数,createComponent 则生成初始的 VNode。组件实例的创建发生在 patch 过程中,此时调用 init 钩子,真正创建组件实例。
组件实例的 options 包含组件配置,通过对象赋值保存到实例中。在组件场景中,initInternalComponent 函数处理组件实例的初始化,包括设置组件选项和相关属性。
综上所述,new Vue() 过程涉及构造函数的初始化、混合功能的挂载、配置的合并与组件的创建。这一过程在后续篇章中将详细分析。
参考资料:
Vue2.6x源码解析(一):Vue初始化过程
Vue2.6x源码解析(一):Vue初始化过程
Vue.js的核心代码在src/core目录,它在任何环境都能运行。项目入口通常在src/main.js,引入的Vue构造函数来自dist/vue.runtime.esm.js,这个文件导出了Vue构造函数,允许我们在创建Vue实例前预置全局API和原型方法。
初始化前,Vue构造函数在src/core/instance/index.js中定义,它预先挂载了全局API如set、delete等。即使不通过new Vue初始化,Vue本身已具备所需功能。
当执行new Vue时,实际上是调用了_init方法,这个过程会在src/core/index.js的initGlobalAPI(Vue)中初始化全局API和原型方法。接着,组件实例的初始化与根实例基本一致,包括组件构造函数的定义,以及组件的生命周期、渲染和挂载。
组件初始化过程中,关键步骤包括数据转换为响应式、事件注册和watcher的创建。例如,组件的渲染函数会触发渲染方法,而watcher的更新则通过异步更新队列机制确保性能。
在开发环境,Vue-template-compiler插件负责模板编译,然后runtime中的$mount方法负责实际的渲染和挂载。整个过程涉及组件的构建、渲染函数生成、依赖响应式数据的更新和异步调度。
Vue computed 的内部实现原理
Vue.js的魅力在于其强大的视图层管理,其中computed属性就是一项关键技术,它简化了模板中的复杂逻辑,确保代码的清晰易读。让我们通过实例深入理解它的内部运作原理。简洁的模板与计算属性
想象一下这样的场景:<div id="example">
<p>Original message: { { message }}</p>
<p>Computed reversed message: { { reversedMessage }}</p>
</div>
<script>
new Vue({
el: '#example',
data: { message: 'Hello' },
computed: {
reversedMessage: function () {
return this.message.split('').reverse().join('');
}
}
});
运行这段代码,你会看到Original message显示"Hello",Computed reversed message则是"olleH"。这是computed属性的直观应用,它确保了在模板中只显示经过计算的结果,而非原始逻辑。响应式与缓存机制
Vue的计算属性并非一劳永逸地运行,而是基于依赖关系和缓存策略。当数据改变时,只有相关的计算属性才会重新计算。这就意味着,即使依赖的数据更新,只要结果没有变化,Vue会利用缓存来避免不必要的渲染,提升了性能。 深入源码,你会发现计算属性在组件初始化时,会为每个属性创建一个Watcher对象,lazy属性默认开启,只有在首次访问时才会触发计算。这确保了在数据变化时,计算的高效执行。计算属性内部实现
Vue的计算属性是通过getter方法实现的,其核心代码如下:<strong>getter实现: </strong>
Object.defineProperty(target, key, {
enumerable: true,
configurable: true,
get: (isServerRendering() ? noop : createComputedGetter(key)),
set: (userDef.get ? (shouldCache && !userDef.cache ? createComputedGetter(key) : createGetterInvoker(userDef.get)) : noop)
});
getter内部,当依赖的数据发生变化时,计算属性的Watcher会检测到并调用evaluate方法重新计算值,同时更新其dirty标志以标记是否需要渲染。优化与性能
Vue巧妙地处理了计算属性的更新策略,当值未变时,避免了不必要的组件渲染,确保了性能。这在依赖数据变化频繁但结果稳定的场景中尤为重要。计算属性与方法、watch的比较
计算属性利用缓存,仅在依赖更新时重新计算,降低了对性能的影响。
相比之下,methods是无缓存的,一旦满足条件,函数立即执行,没有依赖跟踪。
对于异步或耗时操作,watch更适合,因为它可以更灵活地处理变化,包括设置回调和监听。
总结来说,Vue的computed属性是高效、智能的解决方案,它将复杂的逻辑隐藏在背后,让你的模板保持简洁,同时保证了数据的实时性和性能。通过理解其内部实现,我们可以更好地利用和优化Vue应用中的计算属性。这 8 个超赞的 Vue 开源项目你一定要知道
Vue.js作为热门且前景广阔的前端框架,以其数据驱动和组件化思想,提供了简洁且易于理解的API,快速推动了前端项目的构建与开发。以下精选8个Vue开源项目,涵盖了各种用途,助你提升开发效率与技能:VuePress- 一个基于Vue的静态站点生成器,以其vue、vue-router以及vue ssr等技术为核心,简化了文档编写与开发过程。Markdown语法的友好支持让开发者能专心于内容创作,而Vue组件的灵活运用则为自定义功能提供了可能。它不仅是一个强大的文档管理系统,也是一款小型CMS,适合搭建个人博客,GitHub星数为K。
Vuegg- 低代码开发的先锋,通过可视化界面和拖拽功能,Vuegg极大地简化了Vue.js项目的构建流程。设计与原型制作在单一平台上完成,生成的代码质量高且易于理解,GitHub星数为2.2K。
Vuetify- 一个专注Material设计规范的UI组件库,为开发者提供了一套时尚、易用的Material风格界面。遵循Google的Material Design语言,Vuetify不仅提供了丰富的组件,还配套了详尽的开发文档和视频教程,获得Vue.js创始人尤雨溪的认可,GitHub星数达到.6K。
Buefy- 基于Bulma的轻量级UI组件库,提供一系列即用即装的组件,虽然数量有限,但其简洁性与轻量化设计使其成为小型项目或特定需求的理想选择。GitHub星数为9.3K。
awesome-vue- Vue.js官方推荐的学习与资源项目,集合了一系列精选的Vue.js内容,涵盖了从初学者到高级开发者的各种需求,包含丰富的学习资料与示例代码,GitHub星数为.5K。
YesPlayMusic- 一款基于Vue全家桶开发的网易云音乐播放器,兼容Windows、macOS与Linux系统,界面美观,GitHub星数为.2K。
Nuxt.js- 一个专为Vue.js设计的通用应用框架,提供SSR(Server-Side Rendering)功能,通过nuxt.config.js配置文件整合了开发所需的各种工具,简化了客户端与服务端的开发流程,GitHub星数为.8K。
Statusfy- 简单的开源状态页系统,以Vue、Nuxt.js和Tailwind CSS为基础,支持静态生成与服务器渲染,让开发者轻松创建并维护状态页面,GitHub星数为2.7K。
这些Vue开源项目覆盖了从文档编写、低代码开发、UI组件设计、资源学习到应用框架与状态页系统等多个方面,是提升Vue.js开发技能与项目效率的有力工具。用Vue轻松打造你的网站:零基础教程
Vue.js 是一个高效、灵活且易于上手的JavaScript框架,受到许多开发者的喜爱。本文将用金字塔结构、多举例和打比方的方式,让小白也能轻松入门Vue.js。
一、Vue.js是什么?
Vue.js 就像一个模板,帮助你快速搭建起一个网站。它是一个JavaScript框架,用于构建用户界面。Vue.js能让你更容易地将数据和视图关联起来,处理各种网站交互,提高开发效率。
二、Vue.js的核心概念
数据驱动:Vue.js将数据和视图分离,你只需关注数据的变化,视图会自动更新。组件化:Vue.js支持将复杂的界面分解为可复用的组件。指令:Vue.js提供了一些特殊的HTML属性,用于操作DOM元素。
三、Vue.js实战
安装与引入:使用CDN引入Vue.js或使用npm安装。创建一个Vue实例:显示“Hello Vue!”。双向绑定:Vue.js 提供了双向绑定功能,将数据与视图保持同步。条件渲染:通过v-if 指令,我们可以根据条件显示或隐藏元素。列表渲染:使用v-for 指令,我们可以轻松地渲染一个列表。事件处理:Vue.js 可以通过v-on 指令监听 DOM 事件,实现交互。
四、Vue.js生态
Vue.js 拥有丰富的生态系统,提供了许多工具与插件,帮助你更高效地开发。
五、总结
Vue.js 是一个强大、灵活且易于学习的框架,让你能快速搭建出高质量的网站。通过本文的介绍,你应该对 Vue.js 有了基本的了解。接下来,你可以去学习更多关于Vue.js的知识,实操技巧。