做网站怎么找图,网站模板吧,网站备案信息找回,wordpress readmeVue#xff0c;现在前端的当红炸子鸡#xff0c;随着热度指数上升#xff0c;实在是有必要从源码的角度#xff0c;对它功能的实现原理一窥究竟。个人觉得看源码主要是看两样东西#xff0c;从宏观上来说是它的设计思想和实现原理#xff1b;微观上来说就是编程技巧…Vue现在前端的当红炸子鸡随着热度指数上升实在是有必要从源码的角度对它功能的实现原理一窥究竟。个人觉得看源码主要是看两样东西从宏观上来说是它的设计思想和实现原理微观上来说就是编程技巧也就是俗称的骚操作。我们这次的侧重点是它的实现原理。好吧让我们推开它那神秘的大门进入Vue的世界~vue是什么vue究竟是什么为什么就能实现这么多酷炫的功能不知道大家有没有思考过这个问题。其实在每次初始化vue使用new Vue({...})时不难发现vue其实是一个类。不过即使在ES6已经如此普及的今天vue的定义却是普通构造函数定义的为什么没有采用ES6的class呢这个我们稍后回答通过层层追踪终于找到了vue被定义的地方function Vue(options) {...this._init(options)
}因为是原理解析flow的类型检测及一些边界情况如使用方式不对或参数不对或不是主要逻辑的代码我们就省略掉吧。比如省略号这里边界情况是使用时必须是new Vue()的形式否则会报错。其实vue源码就像一棵树我们看之前最好要确定看什么功能然后避开那些分叉逻辑我们接下来的目标就是以new Vue()开始走完一整条从初始化、数据、模板到真实Dom的这整个流程。这就是vue最初始被定义的地方你没看错就是这么简单。当执行new Vue时内部会执行一个方法 this._init(options)将初始化的参数传入。这里需要说明一点在vue的内部_符号开头定义的变量是供内部私有使用的而$ 符号定义的变量是供用户使用的而且用户自定义的变量不能以_或$开头以防止内部冲突。我们接着看import { initMixin } from ./init
import { stateMixin } from ./state
import { renderMixin } from ./render
import { eventsMixin } from ./events
import { lifecycleMixin } from ./lifecyclefunction Vue(options) {...this._init(options)
}initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)现在可以回答之前的问题了为什么不采用ES6的class来定义因为这样可以方便的把vue的功能拆分到不同的目录中去维护将vue的构造函数传入到以下方法内 initMixin(Vue)定义_init方法。 stateMixin(Vue)定义数据相关的方法$set,$delete,$watch方法。 eventsMixin(Vue)定义事件相关的方法$on$once$off$emit。 lifecycleMixin(Vue)定义_update及生命周期相关的$forceUpdate和$destroy。 * renderMixin(Vue)定义$nextTick_render将render函数转为vnode。这些方法都是在各自的文件内维护的从而让代码结构更加清晰易懂可维护。如this._init方法被定义在export function initMixin(Vue) {Vue.prototype._init function(options) {...当执行new Vue时进行一系列初始化并挂载}
}再这些xxxMixin完成后接着会定义一些全局的APIexport function initGlobalAPI(Vue) {Vue.set方法Vue.delete方法Vue.nextTick方法...内置组件keep-alivetransitiontransition-group...initUse(Vue)Vue.use方法initMixin(Vue)Vue.mixin方法initExtend(Vue)Vue.extend方法initAssetRegisters(Vue)Vue.componentVue.directiveVue.filter方法
}这里有部分API和xxxMixin定义的原型方法功能是类似或相同的如this.$set和Vue.set他们都是使用set这样一个内部定义的方法。这里需要提一下vue的架构设计它的架构是分层式的。最底层是一个ES5的构造函数再上层在原型上会定义一些_init、$watch、_render等这样的方法再上层会在构造函数自身定义全局的一些API如set、nextTick、use等(以上这些是不区分平台的核心代码)接着是跨平台和服务端渲染(这些暂时不在讨论范围)及编译器。将这些属性方法都定义好了之后最后会导出一个完整的构造函数给到用户使用而new Vue就是启动的钥匙。这就是我们陌生且又熟悉的vue至于Vue.prototype._init内部做了啥我们下章节再说吧因为还有很多其他的要补充。目录结构刚才是从比较微观的角度近距离的观察了vue现在我们从宏观角度来了解它内部的代码结构是如何组建起来的。 目录如下:|-- dist 打包后的vue版本
|-- flow 类型检测3.0换了typeScript
|-- script 构建不同版本vue的相关配置
|-- src 源码|-- compiler 编译器|-- core 不区分平台的核心代码|-- components 通用的抽象组件|-- global-api 全局API|-- instance 实例的构造函数和原型方法|-- observer 数据响应式|-- util 常用的工具方法|-- vdom 虚拟dom相关|-- platforms 不同平台不同实现|-- server 服务端渲染|-- sfc .vue单文件组件解析|-- shared 全局通用工具方法
|-- test 测试flowjavaScript是弱类型语言使用flow以定义类型和检测类型增加代码的健壮性。src/compiler将template模板编译为render函数。 src/core与平台无关通用的逻辑可以运行在任何javaScript环境下如web、Node.js、weex嵌入原生应用中。 src/platforms针对web平台和weex平台分别的实现并提供统一的API供调用。src/observervue检测数据数据变化改变视图的代码实现。src/vdom将render函数转为vnode从而patch为真实dom以及diff算法的代码实现。dist存放着针对不同使用方式的不同的vue版本。vue版本vue使用的是rollup构建的具体怎么构建的不重要总之会构建出很多不同版本的vue。按照使用方式的不同可以分为以下三类 UMD通过script标签直接在浏览器中使用。 CommonJS使用比较旧的打包工具使用如webpack1。 * ES Module配合现代打包工具使用如webpack2及以上。而每个使用方式内又分为了完整版和运行时版本这里主要以ES Module为例有了官方脚手架其他两类应该没多少人用了。再说明这两个版本的区别之前抱歉我又要补充点其他的。在vue的内部是只认render函数的我们来自己定义一个render函数也就是这么个东西:new Vue({data: {msg: hello Vue!},render(h) {return h(span, this.msg);}
}).$mount(#app);可能有人会纳闷了既然只认render函数同时我们开发好像从来并没有写过render函数而是使用的template模板。这是因为有vue-loader它会将我们在template内定义的内容编译为render函数而这个编译就是区分完整版和运行时版本的关键所在完整版就自带这个编译器而运行时版本就没有如下面这段代码如果是在运行时版本环境下就会报错了new Vue({data: {msg: hello Vue! },template: div{{msg}}/div
})vue-cli默认是使用运行时版本的更改或覆盖脚手架内的默认配置将其更改为完整版即可通过编译vue$: vue/dist/vue.esm.js推荐还是使用运行时版本。好吧具体区别最后我们以一个面试时经常会被问到的问题作为本章节的结束。面试官微笑而又不失礼貌的问到 * 请问runtime和runtime-only这两个版本的区别 怼回去主要是两点不同最明显的就是大小的区别带编译器会比不带的版本大6kb。编译的时机不同编译器是运行时编译性能会有一定的损耗运行时版本是借助loader做的离线编译运行性能更高。 顺手点个赞或关注呗找起来也方便~胡成你可能会用的上的一个vue功能组件库持续完善中...zhuanlan.zhihu.com