大体思路(九)
本节内容:
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 })
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>