【js】vue 2.5.1 源码学习 (十) $mount 挂载函数的实现

大体思路(九)
本节内容:
1. $mount 挂载函数的实现。
  
 1  // 将Vue.prototype.$mount 缓存下来
 2     ==>mountComponet(this,el) {
 3         // 组建挂载的时候做的事情
 4         var uodateComponent = function(){
 5             // 1. render返回生产的虚拟节点
 6             // 2. _update 将虚拟节点变为正真的dom
 7         }
 8         // 渲染函数的观察者对象 初识 Watcher undateComponent被观察目标
 9         new Watcher(vm,undateComponent,noop,{},true);
10     }
11     
12 
13     Vue.prototype.$mount= function(){
14         el = el && query(el)
15         if(el === document.body || document.documentElement){
16             warn('禁止将组件挂载到html 和 body上')
17         }
18         options = this.$options
19         if(!options.render){
20             template = options.template;
21             // 自定义渲染函数  把模版编译为渲染函数 
22             if(template){
23                 if(typeof template === 'string'){
24                     if(template.charAt(0) === '#'){
25                         template = idToTemplate(template)
26 
27                     }
28                 }
29             }else if(el){
30                 template = getOuterHTML(el)
31             }
32             if(template){
33                 // 解析成渲染函数  编译  AST 虚拟DOM
34                 var res = compileToFuntions(template);
35                 options.render = res.render; // 渲染函数
36             }
37         }
38         return mount.call(this,el)
39     }
40     query(el) ===> el === 'string'? doeument.querySelector(el):el
41     idToTemplate(id){
42         var el = query(id)
43        return  el && el.innerHTML;
44     }
45     getOuterHTML(el){
46         if(el.outerHTML){
47             return el.outerHTML
48         }else{
49             var con = document.createElement('div');
50             con.appendChild(el.cloneNode(true));
51             return con.innerHTML
52 
53         }
54     }
2. 渲染函数的观察者
3. 初识Watcher
 
vue.js 如下
  1 //  大体思路(九)
  2 //  本节内容:
  3 // 1. $mount 挂载函数的实现。
  4 //    // 将Vue.prototype.$mount 缓存下来
  5 //     ==>mountComponet(this,el) {
  6 //         // 组建挂载的时候做的事情
  7 //         var uodateComponent = function(){
  8 //             // 1. render返回生产的虚拟节点
  9 //             // 2. _update 将虚拟节点变为正真的dom
 10 //         }
 11 //         // 渲染函数的观察者对象 初识 Watcher undateComponent被观察目标
 12 //         new Watcher(vm,undateComponent,noop,{},true);
 13 //     }
 14     
 15 
 16 //     Vue.prototype.$mount= function(){
 17 //         el = el && query(el)
 18 //         if(el === document.body || document.documentElement){
 19 //             warn('禁止将组件挂载到html 和 body上')
 20 //         }
 21 //         options = this.$options
 22 //         if(!options.render){
 23 //             template = options.template;
 24 //             // 自定义渲染函数  把模版编译为渲染函数 
 25 //             if(template){
 26 //                 if(typeof template === 'string'){
 27 //                     if(template.charAt(0) === '#'){
 28 //                         template = idToTemplate(template)
 29 
 30 //                     }
 31 //                 }
 32 //             }else if(el){
 33 //                 template = getOuterHTML(el)
 34 //             }
 35 //             if(template){
 36 //                 // 解析成渲染函数  编译  AST 虚拟DOM
 37 //                 var res = compileToFuntions(template);
 38 //                 options.render = res.render; // 渲染函数
 39 //             }
 40 //         }
 41 //         return mount.call(this,el)
 42 //     }
 43 //     query(el) ===> el === 'string'? doeument.querySelector(el):el
 44 //     idToTemplate(id){
 45 //         var el = query(id)
 46 //        return  el && el.innerHTML;
 47 //     }
 48 //     getOuterHTML(el){
 49 //         if(el.outerHTML){
 50 //             return el.outerHTML
 51 //         }else{
 52 //             var con = document.createElement('div');
 53 //             con.appendChild(el.cloneNode(true));
 54 //             return con.innerHTML
 55 
 56 //         }
 57 //     }
 58 // 2. 渲染函数的观察者
 59 // 3. 初识Watcher
 60 
 61 
 62 
 63 
 64 (function (global, factory) {
 65     // 兼容 cmd  
 66     typeof exports === 'object' && module !== 'undefined' ? module.exports = factory() :
 67     // Amd
 68     typeof define === 'function' && define.amd ? define(factory) : global.Vue = factory();
 69 })(this, function () {
 70     var uip = 0;
 71 
 72     function warn(string) {
 73         console.error('Vue Wran:' + string)
 74     }
 75 
 76     function warnNonpresent(target, key) {
 77         warn('属性方法' + key + '未在实例对象上定义,渲染功能正在尝试访问这个不存在的属性!')
 78     }
 79 
 80     function resolveConstructorOptions(Con) {
 81         var options = Con.options;
 82         // 判断是否为vm的实例 或者是子类
 83         return options
 84     }
 85     var hasOwnPropeerty = Object.prototype.hasOwnProperty
 86    
 87     function hasOwn(obj, key) {
 88         return hasOwnPropeerty.call(obj, key)
 89     }
 90 
 91     function makeMap(str, expectsLoweraseC) {
 92         if (expectsLoweraseC) {
 93             str = str.toLowerCase()
 94         }
 95         var map = Object.create(null)
 96         var list = str.split(',')
 97         for (var i = 0; i < list.length; i++) {
 98             map[list[i]] = true
 99         }
100         return function (key) {
101             return map[key]
102         }
103     }
104     var isbuiltInTag = makeMap('slot,component', true)
105     var isHTMLTag = makeMap(
106         'html,body,base,head,link,meta,style,title,' +
107         'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
108         'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
109         'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
110         's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
111         'embed,object,param,source,canvas,script,noscript,del,ins,' +
112         'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
113         'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
114         'output,progress,select,textarea,' +
115         'details,dialog,menu,menuitem,summary,' +
116         'content,element,shadow,template,blockquote,iframe,tfoot'
117     );
118     var isSVG = makeMap(
119         'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
120         'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
121         'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
122         true
123     );
124    
125     var ASSET_TYPES = [
126         'component',
127         'directive',
128         'filter'
129     ];
130 
131     var LIFECYCLE_HOOKS = [
132         'beforeCreate',
133         'created',
134         'beforeMount',
135         'mounted',
136         'beforeUpdate',
137         'updated',
138         'beforeDestroy',
139         'destroyed',
140         'activated',
141         'deactivated',
142         'errorCaptured'
143     ];
144     var methods = [
145         'push',
146         'pop',
147         'shift',
148         'unshift',
149         'splice',
150         'sort',
151         'reverse'
152     ];
153     var cacheArrProto = Array.prototype
154     var shell = Object.create(Array.prototype)
155     methods.forEach(function(method){
156         var cacheMethod = cacheArrProto[method]
157         def(shell,method,function(){
158             var args = []
159             var len = arguments.length
160             while(len--) args[len] = arguments[len]
161             var result = cacheMethod.apply(this,args)  // 调用原来的方法
162             var ob = this.__ob__;
163             var inserted ;
164             switch(method){
165                 case 'push' : 
166                 case 'unshift': 
167                 inserted = args
168                 case 'splice': 
169                 inserted = args.slice(2);
170             }
171             if(inserted){
172                 ob.observeArray(inserted)  // 奖新加入的数组加入到显示系统里面。
173             }
174             ob.dep.notify();
175             return result;  //返回数组原来的答案,
176         })
177     })
178     var arrayKeys = Object.getOwnPropertyNames(shell)
179     var hasProto = '__proto__' in {}
180     var noop = function () {}
181     var isReservedTag = function (key) {
182         return isHTMLTag(key) || isSVG(key)
183     }
184     // 检测data的属性名称是否为 _ 或者$ 开始的,这些的话是vue的其他属性的值。
185     function isReserved(key) {
186         var c = key.charCodeAt(0)
187         return c === 0x24 || c === 0x5F
188     }
189     // 检查是否为对象
190     function isObject(val) {
191         return val !== null && typeof val === 'object'
192     }
193 
194     function validataComponentName(key) {
195         //检测component 的自定义名称是否合格 
196         // 只能是字母开头或下划线,必须是字母开头
197         if (!(/^[a-zA-Z][w-]*$/g.test(key))) {
198             warn('组件的名称必须是字母或中横线,必须由字母开头')
199         }
200         // 1. 不能为内置对象,2.不能是html ,和avg的内部标签
201         if (isbuiltInTag(key) || isReservedTag(key)) {
202             warn('不能为html标签或者avg的内部标签')
203         }
204     }
205 
206     function checkComonpents(child) {
207         for (var key in child.components) {
208             validataComponentName(key)
209         }
210     }
211     // 配置对象
212     var config = {
213         // 自定义的策略
214         optionMergeStrategies: {}
215     }
216     var strats = config.optionMergeStrategies
217     strats.el = function (parent, child, key, vm) {
218 
219         if (!vm) {
220             warn('选项' + key + '只能在vue实例用使用')
221         }
222         return defaultStrat(parent, child, key, vm)
223     }
224 
225     function mergeData(to, form) {
226         // 终极合并
227         if (!form) {
228             return to
229         }
230         // 具体合并。  
231     }
232 
233     function mergeDataorFn(parentVal, childVal, vm) {
234         // 合并 parentVal childVal  都是函数
235         if (!vm) {
236             if (!childVal) {
237                 return parentVal
238             }
239             if (!parentVal) {
240                 return childVal
241             }
242             return function mergeDataFn(parentVal, childVal, vm) { //只是一个函数   什么样的情况下调用 加入响应式系统 
243                 // 合并子组件对应的data 和   父组件对应的data
244                 return mergeData(
245                     typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal, // -----忘记写
246                     typeof childVal === 'function' ? childVal.call(this, this) : childVal) // -----忘记写
247             }
248         } else { // vue实例
249             return function mergeInstanceDataFn() { //只是一个函数   什么样的情况下调用 加入响应式系统 
250                 var InstanceData = typeof childVal === 'function' ? childVal.call(vm, vm) : childVal; // -----忘记写
251                 var defaultData = typeof parentVal === 'function' ? parentVal.call(vm, vm) : parentVal; // -----忘记写
252                 if (InstanceData) {
253                     return mergeData(InstanceData, defaultData)
254                 } else { // -----忘记写
255                     return defaultData
256                 }
257 
258             }
259         }
260     }
261     strats.data = function (parent, child, key, vm) {
262         if (!vm) {
263             // console.log(typeof child === 'function')
264             if (child && !(typeof child === 'function')) {
265                 warn('data必须返回是一个function')
266             }
267             return mergeDataorFn(parent, child)
268         }
269         return mergeDataorFn(parent, child, vm)
270     }
271     // 生命周期策略的合并,值等于一个function 如果是有两个,放到一个数组里面。
272     function mergeHook(parentVal, childVal, key, vm) {
273         // console.log(key)
274         // console.log(parentVal.concat(childVal) )
275         return childVal ? parentVal ? parentVal.concat(childVal) :
276             Array.isArray(childVal) ? childVal : [childVal] : parentVal
277     }
278     LIFECYCLE_HOOKS.forEach(function (key) {
279         strats[key] = mergeHook
280     });
281     // 检测是否为object
282     function isPlainObject(obj) {
283         return Object.prototype.toString.call(obj) === '[object Object]'
284     }
285 
286     function assetObjectType(obj) {
287         if (!isPlainObject(obj)) {
288             warn('选项的值' + obj + '无效:必须是一个对象的')
289         }
290     }
291     // 对parent实现链式调用。
292     function extend(to, form) {
293         for (key in form) {
294 
295             to[key] = form[key]
296         }
297         return to
298     }
299     // 实现Assets 的策略合并  conmponents  filter  diretive   
300     function mergeAssets(parentVal, childVal, key, vm) {
301         var parent = Object.create(parentVal || null) // 保证子类的每个值的指向都是一个新的object。否则回出现相互引用的现象。
302         if (childVal) {
303             assetObjectType(childVal)
304             return extend(parent, childVal)
305         }
306         return parent
307     }
308     ASSET_TYPES.forEach(function (key) {
309         strats[key + 's'] = mergeAssets
310     })
311     // 实现watch的策略和并,将相同的属性放到一个数组里面。
312     strats.watch = function (parentVal, childVal, key, vm) {
313         if (!childVal) {
314             return Object.create(parentVal)
315         }
316         var res = {}
317         res = extend(res, parentVal)
318         for (var key in childVal) {
319             var parent = res[key]
320             var child = childVal[key]
321             res[key] = parent ? Array.isArray(parent) ? parent.concat(child) : [parent].concat(child) :
322                 Array.isArray(child) ? child : [child];
323         }
324         return res
325     }
326     // 实现props指令的合并策略
327     strats.props = function (parentVal, childVal, key, vm) {
328         if (!childVal) {
329             return parentVal
330         }
331         var res = Object.create(null)
332         extend(res, parentVal)
333         if (childVal) {
334             extend(res, childVal)
335         }
336         return res
337     }
338 
339     function defaultStrat(parent, child, key, vm) {
340         return child === undefined ? parent : child;
341     }
342     var cmalizeRE = /-(w)/g
343 
344     function camelize(val) {
345         return val.replace(cmalizeRE, function (c, m) {
346             return m ? m.toUpperCase() : ""
347         })
348     }
349 
350     function normalizeProps(options) {
351         var props = options.props
352         if (!props) {
353             return
354         }
355         var i, val, name
356         var res = {}
357         if (Array.isArray(props)) {
358             i = props.length
359             while (i--) {
360                 val = props[i]
361                 if (toString.call(val) === '[object String]') {
362                     name = camelize(val)
363                     res[name] = {
364                         type: null
365                     }
366                 } else {
367                     warn('使用数组愈发时props成员' + val + '必须时一个数组')
368                 }
369 
370 
371             }
372         } else if (isPlainObject(props)) {
373             for (var key in props) {
374                 val = props[key]
375                 name = camelize(key)
376                 res[name] = isPlainObject(val) ? val : {
377                     type: val
378                 }
379             }
380         } else {
381             warn('选项props的值必须是一个对象或者是数组')
382         }
383         options.props = res
384     }
385 
386     function mormalizeDirectives(options) {
387         var dir = options.directives
388         var res = {}
389         if (!dir) {
390             return
391         }
392         if (dir) {
393             for (var key in dir) {
394                 var val = dir[key]
395                 var name = camelize(key)
396                 if (isPlainObject(val)) {
397                     res[name] = val
398                 }
399                 if (toString.call(val) === '[object Function]') {
400                     res[name] = {
401                         bind: val,
402                         upata: val
403                     }
404                 }
405             }
406         }
407         options.directives = res
408 
409     }
410 
411     function mergeOptions(parent, child, vm) {
412         var options = {}
413         // 检测是component 是否是合法的  
414         checkComonpents(child)
415         // 规范props 
416         normalizeProps(child)
417         // 规范 dirctives 
418         mormalizeDirectives(child)
419 
420         // console.log(parent, child)
421         for (key in parent) {
422             magerField(key)
423         }
424         for (key in child) {
425             if (!hasOwn(parent, key)) { // parent 中循环过地方不进行循环
426                 magerField(key) // ----忘记写
427             }
428 
429         }
430         // 默认合并策略
431         function magerField(key) {
432             // 自定义策略  默认策略 
433             // console.log(key)
434             var result = strats[key] || defaultStrat // ---忘记写
435             options[key] = result(parent[key], child[key], key, vm)
436         }
437         // console.log(options)
438         return options
439     }
440 
441     var allowedGlobals = makeMap(
442         'Infinity,undefined,NaN,isFinite,isNaN,' +
443         'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
444         'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
445         'require' // for Webpack/Browserify
446     );
447 
448     function isNative(Ctor) {
449         return typeof Ctor !== undefined && /native code/.test(toString.call(Ctor))
450     }
451     var hasproxy = typeof Proxy !== undefined && isNative(Proxy)
452     var hasHeadler = {
453         has: function (target, key) {
454             var val = key in target
455             // key 是否是全局对象 或者内置方法 _
456             var isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_')
457             if (!val && !isAllowed) {
458                 warnNonpresent(target, key)
459             }
460             return val || !isAllowed
461         }
462     }
463     var getHeadler = {
464         get: function (target, key) {
465             if (typeof key === 'string' && !(key in target)) {
466                 warnNonpresent(target, key)
467             }
468             return target[key]
469         }
470     }
471 
472     // 数据代理
473     function initProxy(vm) {
474         var options = vm.$options
475         // 判断是否是es6 是否存在Proxy
476         if (hasproxy) {
477             // 渲染函数拦截那些操作。 1. has 查询 2. get 或者
478             var headler = options.render && options.render._withStripeed ?
479                 getHeadler :
480                 hasHeadler;
481             vm._renderPorxy = new proxy(vm, headler)
482         } else {
483             // 如果不支es6  Proxy
484             vm._renderPorxy = vm
485         }
486     }
487 
488 
489     // 初始化当前实例的$children 和$parent 的指向
490     function initLifeCycle(vm) {
491         var options = vm.$options
492         // 当前组件 父实例 
493         var parent = options.parent // 组件的实例对象
494         // 是否抽象组件 
495         if (parent && !parent.abstrat) {
496             while (parent.$options.abstrat && parent.$parent) {
497                 parent = parent.$options.parent
498             }
499             parent.$children.push(vm)
500         }
501         vm.$parent = parent
502         vm.$root = parent ? parent.$root : vm;
503 
504         vm.$children = [];
505         vm.$refs = {};
506 
507         vm._watcher = null;
508         vm._inactive = null;
509         vm._directInactive = false;
510         vm._isMounted = false; // 是否挂载 
511         vm._isDestroyed = false; // 是否销毁
512         vm._isBeingDestroyed = false; // 是否正在销毁
513 
514     }
515 
516     function callHook(vm, hook) {
517         var options = vm.$options
518         var obj = options[hook]
519         if (obj) {
520             for (var i = 0; i < obj.length; i++) {
521                 obj[i].call(vm)
522             }
523         }
524 
525     }
526 
527     function getData(data, vm) {
528         return data.call(vm, vm)
529     }
530 
531     //共享的访问器对象
532     var sharedProperty = {
533         enumerable: true,
534         configurable: true,
535         get: noop,
536         set: noop
537     };
538 
539     function proxy(vm, data, key) {
540 
541         sharedProperty.get = function () {
542                 // console.log("我监听到你访问了我")
543                 return this[data][key]
544             },
545             sharedProperty.set = function (newVal) {
546                 console.log("我设置了data的值" + key + "==" + newVal)
547                 this[data][key] = newVal
548 
549             }
550         Object.defineProperty(vm, key, sharedProperty)
551     }
552 
553     function initData(vm) {
554         var opts = vm.$options
555         var data = vm.$options.data
556         // 通过之前strats 里面合成好的数据,data是一个function ,为了独立数据调用的空间。拿到data的值。
557         data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
558         if (!isPlainObject(data)) {
559             data = {}
560             warn('data选项应该是object对象')
561         }
562         // data methods props 里面属性名称不能相同
563         var props = opts.props
564         var methods = opts.methods
565         for (let key in data) {
566             if (props && hasOwn(props, key)) {
567                 warn("props " + key + "选项已经定义为data的属性.")
568             } else if (methods && hasOwn(methods, key)) {
569                 warn("methods: " + key + "选项已经定义为data的属性.")
570             } else if (!isReserved(key)) {
571                 proxy(vm, "_data", key)
572             }
573 
574         }
575         observe(data, true)
576     }
577     var shouldObserve = true
578     var toggleObserving = function (value) {
579         shouldObserve = value
580     }
581 
582     function Dep() {
583         this.subs = []
584     }
585     Dep.prototype.addSub = function (sub) {
586         this.subs.push(sub)
587     }
588     Dep.prototype.depend = function () {
589         console.log("收集依赖"); //Watch 观察者
590     }
591     Dep.prototype.notify = function () {
592         var subs = this.subs.slice()
593         for (var i = 0; i < subs.length; i++) {
594             subs[i].updata() // 数据更新的操作   Watch
595         }
596     }
597     Dep.target = null
598 
599     function def(obj, key, val) { // data._ob_  实例对象 指向 Observer
600         Object.defineProperty(obj, key, {
601             value: val,
602             enumerable: false, //不可枚举
603             configrable: true
604         })
605     }
606 
607     function Observe(value) {
608         this.value = value;
609         this.vmCount = 0;
610         this.dep = new Dep() //回调列表 依赖在什么情况调用 
611         def(value, '_ob_', this)
612         if(Array.isArray(value)){
613             var augment = hasProto ?  protoAugment : copyAugment ;
614             augment(value,shell,arrayKeys)
615         }else{
616             this.walk(value)
617         }
618        
619     }
620     function protoAugment(target,src){
621         target.__proto__ = src
622     }
623     function copyAugment(target,src,keys){
624         for(var i =0, j=keys.length; i<j; i++){
625             var key = keys[i];
626             def(target, key, src[key]);
627         }
628         console.log(target)
629     }
630     // 加入响应式系统   添加   setter  getter
631     function defindReactive(obj, key, val, shallow) {
632         var dep = new Dep() // 收集依赖  回调列表
633         var property = Object.getOwnPropertyDescriptor(obj, key)
634         var getter = property && property.get
635         var setter = property && property.set
636         // getter 和 setter 都不存在。或者都存在则为 true ===》 (!getter || setter)
637         // console.log((!getter || setter),arguments)
638         if ((!getter || setter) && arguments.length === 2) {
639             val = obj[key] // 深度观测  
640         }
641         var childOb = !shallow && observe(val)
642         Object.defineProperty(obj, key, {
643             get: function () {
644                 var value = getter ? getter.call(obj) : val
645                 if (Dep.target) {
646                     dep.depend()  // 收集依赖
647                     if (childOb) {
648                         childOb.dep.depend()  // 收集依赖
649                     }
650                 }
651                 return value
652             },
653             set: function (newVal) {
654                 var value = setter ? setter.call(obj) : val
655                 // is NaN !== NaN
656                 if (newVal === value || (value !== value && newVal !== newVal)) {
657                     return
658                 }
659                 if (setter) {
660                     setter.call(obj, newVal)
661                 } else {
662                     val = newVal
663                 }
664                 console.log('我监听到data变化' + newVal)
665                 // 如果改变的新值为 object 或者Array 就在进行深度检测,递归。
666                 childOb = !shallow && observe(val)
667                 dep.notify() //通知依赖更新
668             }
669         })
670     }
671     Observe.prototype.walk = function (value) {
672         var keys = Object.keys(value)
673         for (var i = 0; i < keys.length; i++) {
674             defindReactive(value, keys[i])
675         }
676     }
677     Observe.prototype.observeArray = function(items){
678         items.forEach(function(item){
679             observe(item)
680         })
681     }
682     // 响应式系统
683     function observe(value, asRootData) {
684         var ob
685         if (!isObject(value)) {
686             return;
687         }
688         if(hasOwn(value,'_ob_') && value._ob_ instanceof Observe){
689             ob= value._ob_
690 
691         }else if (shouldObserve && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) {
692             ob = new Observe(value)
693         }
694         if (ob && asRootData) {
695             ob.vmCount++
696         }
697 
698         return ob
699     }
700 
701     function initState(vm) {
702         var opts = vm.$options
703         // 初始化props
704         if (opts.props) {
705             initProps(vm, opts.props)
706         }
707         // 初始化methods
708         if (opts.methods) {
709             initMethods(vm, opts.methods)
710         }
711         // 初始化computed
712         if (opts.computed) {
713             initComputed(vm, opts.computed)
714         }
715         // 初始化data 如果存在就initData
716         if (opts.data) {
717             initData(vm)
718         } else {
719             // 放在响应式系统里面
720             observe(vm._data = {}, true)
721         }
722     }
723    
724     function initMinxin(options) {
725         Vue.prototype._init = function (options) {
726             var vm = this
727             // 记录生成的vue实例对象 
728             vm._uip = uip++ //   //-------忘记写
729             // 是否可扩展
730             vm.is_Vue = true;
731             //合并选项
732             vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options, vm)
733             // // 初始化数值代理
734             initProxy(vm)
735             // 初始化当前实例的$children 和$parent 的指向
736             initLifeCycle(vm)
737             // 调用beforeCreate 的钩子函数
738             callHook(vm, 'beforeCreate')
739             // 初始化数据
740             initState(vm)
741             //调用created钩子
742             callHook(vm,'created') 
743             // 挂载组件
744             if(vm.$options.el){
745                 vm.$mount(vm.$options.el)
746             }
747 
748              
749         }
750     }
751     // 检查是否为正确的el
752     function query(el){
753         if(typeof el === 'string'){
754             var element = document.querySelector(el)
755             if(!element){
756                 warn('connet fined element' + el)
757             }
758             return element
759         }else {
760             return el
761         }
762     }
763     // 输出html的模版
764     function isToTemplate(el){
765         var el = el && query(el)
766         return el && el.innerHTML
767     }
768       // 输出html的模版
769     function getOuterHTML(el){
770         if(el.outerHTML){
771             return el.outerHTML
772         }else {
773             var dom = document.createElement('div')
774             dom.appendChild(el.clone(true))
775             return dom.innerHTML
776         }
777     }
778     // 挂载转体统  
779     function mountComponent(){
780        // 组建挂载的时候做的事情
781         var uodateComponent = function(){
782             // 1. render返回生产的虚拟节点
783             // 2. _update 将虚拟节点变为正真的dom
784         }
785         // 渲染函数的观察者对象 初识 Watcher undateComponent被观察目标
786         new Watcher(vm,undateComponent,noop,{},true);
787     }
788      // 挂载系统
789      Vue.prototype.$mount = function(el){
790         var el = el && query(el)
791         // 挂载组件,  生成虚拟dom   编译为真实dom节点
792         return mountComponent(this,el)
793     }
794     var mount = Vue.prototype.$mount
795     // 重写了$mount
796     Vue.prototype.$mount = function(el){
797         var el = el && query(el)
798         // console.log(el)
799         // 不能绑定在body 和html上。 
800         if(el === document.body || el === document.documentElement){
801             warn('禁止组件挂载在html 或者body上')
802         }
803         var options = this.$options
804         // 自定义渲染函数  把模版编译为渲染函数 
805         if(!options.render){
806            var  template = options.template
807            if(template){
808                if(typeof template === 'string' && template.charAt(0) === "#"){
809                   template = isToTemplate(template)
810                }
811            }else if(el){
812                   template = getOuterHTML(el)
813            }
814            if(template){
815                 //解析成渲染函数    编译  AST   虚拟DOM
816               
817                var res = compileToFunctions(template)
818                this.render = res.render  //渲染函数
819            }
820         }
821         return mount.call(this.el)
822     }
823     function Vue(options) {
824         // 安全机制
825         if (!(this instanceof Vue)) { //-------忘记写
826             warn('Vue是一个构造函数,必须是由new关键字调用')
827         }
828         this._init(options)
829     }
830     initMinxin() //  初始化选项1: 规范 2: 合并策略。
831     Vue.options = {
832         components: {
833             transtions: {},
834             keepAlive: {},
835             solt: {},
836             transtionsGroup: {}
837         },
838         directives: {},
839         _bash: Vue
840     }
841 
842     function initExend(Vue) {
843         Vue.extend = function (extendOptions) {
844             extendOptions = extendOptions || {} // -----忘记写
845             var Super = this
846             var Child = function VueComponent(options) {
847                 this._init(options)
848             }
849             Child.prototype = Object.create(Super.prototype)
850             Child.prototype.constructor = Child // 改变constructor 的指向
851             Child.options = mergeOptions(Super.options, extendOptions)
852             // 子类继承父类的静态方法。
853             Child.extend = Vue.extend
854             // console.log(new Child({}))
855             return Child
856         }
857     }
858     initExend(Vue)
859     return Vue
860 })
View Code

html代码如下

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7     <title>第九课</title>
 8 </head>
 9 <body>
10     <div id="app">
11         <!-- <huml></huml> -->
12        
13     </div>
14     <script src="vue.js"></script>
15     <!-- <script src="vue2.5.1.js"></script> -->
16     <script type="text/javascript">
17         var componentA = {
18             el: "#app"
19         }
20         var vm = new Vue({
21             el:"#app",
22             data: { 
23                 message: "hello Vue",
24                 key: "wodow",
25                 test: 1,
26                
27                 list: {
28                     b:1
29                 },
30                 aa:{
31                     b: [1,2,3]
32                 }
33             },
34             beforeCreate: function(){
35                 console.log('我钩子函数beforeCreate')
36                 
37             },
38             mounted: function(){
39                 this.url = 'eeeee'
40             },
41             components:{
42                 humle: componentA
43             } 
44         })
45         vm.test = 2;
46         // console.log(vm.aa)
47     </script>
48 </body>
49 </html>
原文地址:https://www.cnblogs.com/yeujuan/p/11170171.html