大体思路(六)
本节内容:
一、生命周期的钩子函数的实现
==》 callHook(vm , 'beforeCreate')
beforeCreate 实例创建之后 事件数据还未创建
二、初始化initState
==>initState(vm) // 初始化数据
==> initProps(vm,opts.props) 待续
==> initMethods 待续
==> initComputed 待续
==> if data initData else { observer(vm._data={},true)}
initData
==> getData(data,vm) 如果是一个函数直接调用这个函数
==> data methods props 里面属性名称不能相同
==> proxy(vm,data,key) 双向数据绑定的地方 defineProperty(vm,key,sharedProperty)
==> sharedProperty // 公共访问器对象
vue.js代码如下
1 // 大体思路(六) 2 // 本节内容: 3 // 生命周期的钩子函数的实现 4 // ==》 callHook(vm , 'befroeCreate') 5 // beforeCreate 实例创建之后 事件数据还未创建 6 // ==>initState(vm) // 初始化数据 7 // ==> initProps(vm,opts.props) 待续 8 // ==> initMethods 待续 9 // ==> initComputed 待续 10 // ==> if data initData else { observer(vm._data={},true)} 11 // initData 12 // ==> getData(data,vm) 如果是一个函数直接调用这个函数 13 // ==> data methods props 里面属性名称不能相同 14 // ==> proxy(vm,data,key) 双向数据绑定的地方 defineProperty(vm,key,sharedProperty) 15 // ==> sharedProperty // 公共访问器对象 16 // 响应式系统 17 18 19 (function(global,factory){ 20 // 兼容 cmd 21 typeof exports === 'object' && module !== 'undefined' ? module.exports = factory(): 22 // Amd 23 typeof define === 'function' && define.amd ? define(factory) : global.Vue = factory(); 24 })(this,function(){ 25 var uip = 0; 26 function warn(string){ 27 console.error('Vue Wran:' + string) 28 } 29 function warnNonpresent(target,key){ 30 warn('属性方法'+ key + '未在实例对象上定义,渲染功能正在尝试访问这个不存在的属性!') 31 } 32 function resolveConstructorOptions(Con){ 33 var options = Con.options; 34 // 判断是否为vm的实例 或者是子类 35 return options 36 } 37 var hasOwnPropeerty = Object.prototype.hasOwnProperty 38 function hasOwn(obj , key){ 39 return hasOwnPropeerty.call(obj,key) 40 } 41 function makeMap(str, expectsLoweraseC){ 42 if(expectsLoweraseC){ 43 str = str.toLowerCase() 44 } 45 var map = Object.create(null) 46 var list = str.split(',') 47 for(var i = 0 ; i < list.length; i++){ 48 map[list[i]] = true 49 } 50 return function(key){ 51 return map[key] 52 53 } 54 } 55 var isbuiltInTag = makeMap('slot,component',true) 56 var isHTMLTag = makeMap( 57 'html,body,base,head,link,meta,style,title,' + 58 'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' + 59 'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' + 60 'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' + 61 's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' + 62 'embed,object,param,source,canvas,script,noscript,del,ins,' + 63 'caption,col,colgroup,table,thead,tbody,td,th,tr,' + 64 'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' + 65 'output,progress,select,textarea,' + 66 'details,dialog,menu,menuitem,summary,' + 67 'content,element,shadow,template,blockquote,iframe,tfoot' 68 ); 69 var isSVG = makeMap( 70 'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' + 71 'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' + 72 'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view', 73 true 74 ); 75 var ASSET_TYPES = [ 76 'component', 77 'directive', 78 'filter' 79 ]; 80 81 var LIFECYCLE_HOOKS = [ 82 'beforeCreate', 83 'created', 84 'beforeMount', 85 'mounted', 86 'beforeUpdate', 87 'updated', 88 'beforeDestroy', 89 'destroyed', 90 'activated', 91 'deactivated', 92 'errorCaptured' 93 ]; 94 var noop = function (){} 95 var isReservedTag = function(key){ 96 return isHTMLTag(key) || isSVG(key) 97 } 98 // 检测data的属性名称是否为 _ 或者$ 开始的,这些的话是vue的其他属性的值。 99 function isReserved(key) { 100 var c = key.charCodeAt(0) 101 return c === 0x24 || c === 0x5F 102 } 103 function validataComponentName(key){ 104 //检测component 的自定义名称是否合格 105 // 只能是字母开头或下划线,必须是字母开头 106 if(!(/^[a-zA-Z][w-]*$/g.test(key))){ 107 warn('组件的名称必须是字母或中横线,必须由字母开头') 108 } 109 // 1. 不能为内置对象,2.不能是html ,和avg的内部标签 110 if( isbuiltInTag(key) || isReservedTag(key)){ 111 warn('不能为html标签或者avg的内部标签') 112 } 113 } 114 function checkComonpents(child){ 115 for(var key in child.components){ 116 validataComponentName(key) 117 } 118 } 119 // 配置对象 120 var config = { 121 // 自定义的策略 122 optionMergeStrategies:{} 123 } 124 var strats = config.optionMergeStrategies 125 strats.el = function(parent,child , key , vm){ 126 127 if(!vm){ 128 warn('选项'+key+'只能在vue实例用使用') 129 } 130 return defaultStrat(parent,child , key , vm) 131 } 132 function mergeData(to,form){ 133 // 终极合并 134 if(!form){ 135 return to 136 } 137 // 具体合并。 138 } 139 function mergeDataorFn(parentVal,childVal,vm){ 140 // 合并 parentVal childVal 都是函数 141 if(!vm){ 142 if(!childVal){ 143 return parentVal 144 } 145 if(!parentVal){ 146 return childVal 147 } 148 return function mergeDataFn(parentVal,childVal,vm){//只是一个函数 什么样的情况下调用 加入响应式系统 149 // 合并子组件对应的data 和 父组件对应的data 150 return mergeData( 151 typeof parentVal === 'function' ? parentVal.call(this,this) : parentVal, // -----忘记写 152 typeof childVal === 'function' ? childVal.call(this,this): childVal) // -----忘记写 153 } 154 }else{ // vue实例 155 return function mergeInstanceDataFn(){//只是一个函数 什么样的情况下调用 加入响应式系统 156 var InstanceData = typeof childVal === 'function' ? childVal.call(vm,vm): childVal; // -----忘记写 157 var defaultData = typeof parentVal === 'function' ? parentVal.call(vm,vm): parentVal; // -----忘记写 158 if(InstanceData){ 159 return mergeData(InstanceData,defaultData) 160 }else{ // -----忘记写 161 return defaultData 162 } 163 164 } 165 } 166 } 167 strats.data = function(parent,child , key , vm){ 168 if(!vm){ 169 // console.log(typeof child === 'function') 170 if(child && !(typeof child === 'function')){ 171 warn('data必须返回是一个function') 172 } 173 return mergeDataorFn(parent,child) 174 } 175 return mergeDataorFn(parent,child,vm) 176 } 177 // 生命周期策略的合并,值等于一个function 如果是有两个,放到一个数组里面。 178 function mergeHook(parentVal,childVal,key,vm){ 179 // console.log(key) 180 // console.log(parentVal.concat(childVal) ) 181 return childVal ? parentVal ? parentVal.concat(childVal): 182 Array.isArray(childVal) ? childVal : [childVal] : parentVal 183 } 184 LIFECYCLE_HOOKS.forEach(function(key){ 185 strats[key] = mergeHook 186 }); 187 // 检测是否为object 188 function isPlainObject(obj){ 189 return Object.prototype.toString.call(obj) === '[object Object]' 190 } 191 function assetObjectType(obj){ 192 if(!isPlainObject(obj)){ 193 warn('选项的值'+obj+'无效:必须是一个对象的') 194 } 195 } 196 // 对parent实现链式调用。 197 function extend(to,form){ 198 for(key in form){ 199 200 to[key] = form[key] 201 } 202 return to 203 } 204 // 实现Assets 的策略合并 conmponents filter diretive 205 function mergeAssets(parentVal,childVal,key,vm){ 206 var parent = Object.create(parentVal || null) // 保证子类的每个值的指向都是一个新的object。否则回出现相互引用的现象。 207 if(childVal){ 208 assetObjectType(childVal) 209 return extend(parent,childVal) 210 } 211 return parent 212 } 213 ASSET_TYPES.forEach(function(key){ 214 strats[key+'s'] = mergeAssets 215 }) 216 // 实现watch的策略和并,将相同的属性放到一个数组里面。 217 strats.watch = function(parentVal,childVal , key , vm){ 218 if(!childVal){ 219 return Object.create(parentVal) 220 } 221 var res = {} 222 res = extend(res,parentVal) 223 for(var key in childVal){ 224 var parent = res[key] 225 var child = childVal[key] 226 res[key] = parent ? Array.isArray(parent) ? parent.concat(child) : [parent].concat(child) : 227 Array.isArray(child) ? child : [child] ; 228 } 229 return res 230 } 231 // 实现props指令的合并策略 232 strats.props = function(parentVal,childVal , key , vm){ 233 if(!childVal){ 234 return parentVal 235 } 236 var res = Object.create( null) 237 extend(res,parentVal) 238 if(childVal){ 239 extend(res,childVal) 240 } 241 return res 242 } 243 function defaultStrat(parent,child , key , vm){ 244 return child === undefined ? parent :child ; 245 } 246 var cmalizeRE = /-(w)/g 247 function camelize(val){ 248 return val.replace(cmalizeRE,function(c,m){ 249 return m ? m.toUpperCase(): "" 250 }) 251 } 252 function normalizeProps(options){ 253 var props = options.props 254 if(!props){ 255 return 256 } 257 var i , val , name 258 var res = {} 259 if(Array.isArray(props)){ 260 i = props.length 261 while(i--){ 262 val = props[i] 263 if(toString.call(val) === '[object String]'){ 264 name = camelize(val) 265 res[name] = {type: null} 266 }else{ 267 warn('使用数组愈发时props成员' +val+ '必须时一个数组') 268 } 269 270 271 } 272 }else if(isPlainObject(props)){ 273 for(var key in props){ 274 val = props[key] 275 name = camelize(key) 276 res[name] = isPlainObject(val) ? val : {type: val} 277 } 278 }else { 279 warn('选项props的值必须是一个对象或者是数组') 280 } 281 options.props = res 282 } 283 function mormalizeDirectives(options){ 284 var dir = options.directives 285 var res = {} 286 if(!dir){ 287 return 288 } 289 if(dir){ 290 for(var key in dir){ 291 var val = dir[key] 292 var name = camelize(key) 293 if(isPlainObject(val)){ 294 res[name] = val 295 } 296 if(toString.call(val) === '[object Function]'){ 297 res[name] = { 298 bind: val, 299 upata: val 300 } 301 } 302 } 303 } 304 options.directives = res 305 306 } 307 function mergeOptions(parent,child,vm){ 308 var options = {} 309 // 检测是component 是否是合法的 310 checkComonpents(child) 311 // 规范props 312 normalizeProps(child) 313 // 规范 dirctives 314 mormalizeDirectives(child) 315 316 // console.log(parent, child) 317 for(key in parent){ 318 magerField(key) 319 } 320 for(key in child){ 321 if(!hasOwn(parent ,key)){ // parent 中循环过地方不进行循环 322 magerField(key) // ----忘记写 323 } 324 325 } 326 // 默认合并策略 327 function magerField(key){ 328 // 自定义策略 默认策略 329 // console.log(key) 330 var result = strats[key] || defaultStrat // ---忘记写 331 options[key] = result(parent[key],child[key] , key , vm) 332 } 333 // console.log(options) 334 return options 335 } 336 337 var allowedGlobals = makeMap( 338 'Infinity,undefined,NaN,isFinite,isNaN,' + 339 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 340 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + 341 'require' // for Webpack/Browserify 342 ); 343 function isNative(Ctor){ 344 return typeof Ctor !== undefined && /native code/.test(toString.call(Ctor)) 345 } 346 var hasproxy = typeof Proxy !== undefined && isNative(Proxy) 347 var hasHeadler = { 348 has: function(target,key){ 349 var val = key in target 350 // key 是否是全局对象 或者内置方法 _ 351 var isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_') 352 if(!val && !isAllowed){ 353 warnNonpresent(target,key) 354 } 355 return val || !isAllowed 356 } 357 } 358 var getHeadler = { 359 get: function(target,key){ 360 if( typeof key === 'string' && !(key in target)){ 361 warnNonpresent(target,key) 362 } 363 return target[key] 364 } 365 } 366 367 // 数据代理 368 function initProxy(vm){ 369 var options = vm.$options 370 // 判断是否是es6 是否存在Proxy 371 if(hasproxy){ 372 // 渲染函数拦截那些操作。 1. has 查询 2. get 或者 373 var headler = options.render && options.render._withStripeed ? 374 getHeadler: 375 hasHeadler; 376 vm._renderPorxy= new proxy(vm,headler) 377 }else{ 378 // 如果不支es6 Proxy 379 vm._renderPorxy = vm 380 } 381 } 382 383 384 // 初始化当前实例的$children 和$parent 的指向 385 function initLifeCycle(vm){ 386 var options = vm.$options 387 // 当前组件 父实例 388 var parent = options.parent // 组件的实例对象 389 // 是否抽象组件 390 if(parent && !parent.abstrat){ 391 while(parent.$options.abstrat && parent.$parent){ 392 parent = parent.$options.parent 393 } 394 parent.$children.push(vm) 395 } 396 vm.$parent = parent 397 vm.$root = parent ? parent.$root : vm; 398 399 vm.$children = []; 400 vm.$refs = {}; 401 402 vm._watcher = null; 403 vm._inactive = null; 404 vm._directInactive = false; 405 vm._isMounted = false; // 是否挂载 406 vm._isDestroyed = false; // 是否销毁 407 vm._isBeingDestroyed = false; // 是否正在销毁 408 409 } 410 function callHook(vm,hook){ 411 var options = vm.$options 412 var obj = options[hook] 413 if(obj){ 414 for(var i =0 ; i < obj.length ; i++){ 415 obj[i].call(vm) 416 } 417 } 418 419 } 420 function getData(data,vm){ 421 return data.call(vm,vm) 422 } 423 424 //共享的访问器对象 425 var sharedProperty = { 426 enumerable:true, 427 configurable:true, 428 get:noop, 429 set:noop 430 }; 431 function proxy(vm,data,key){ 432 433 sharedProperty.get = function(){ 434 console.log("我监听到你访问了我") 435 return this[data][key] 436 }, 437 sharedProperty.set =function(newVal){ 438 console.log("我设置了data的值"+key+"==" +newVal) 439 this[data][key] = newVal 440 441 } 442 Object.defineProperty(vm,key,sharedProperty) 443 } 444 function initData(vm){ 445 var opts = vm.$options 446 var data = vm.$options.data 447 // 通过之前strats 里面合成好的数据,data是一个function ,为了独立数据调用的空间。拿到data的值。 448 data = vm._data = typeof data === 'function' ? getData(data,vm) : data || {} 449 if(!isPlainObject(data)){ 450 data = {} 451 warn('data选项应该是object对象') 452 } 453 // data methods props 里面属性名称不能相同 454 var props = opts.props 455 var methods = opts.methods 456 for(let key in data){ 457 if(props && hasOwn(props,key)){ 458 warn("props " + key + "选项已经定义为data的属性.") 459 }else if(methods && hasOwn(methods,key)){ 460 warn("methods: " + key + "选项已经定义为data的属性.") 461 }else if(!isReserved(key)){ 462 proxy(vm,"_data",key) 463 } 464 465 } 466 467 } 468 function observer(){ 469 // 相应试系统 470 } 471 function initState(vm){ 472 var opts = vm.$options 473 // 初始化props 474 if(opts.props){ 475 initProps(vm,opts.props) 476 } 477 // 初始化methods 478 if(opts.methods){ 479 initMethods(vm,opts.methods) 480 } 481 // 初始化computed 482 if(opts.computed){ 483 initComputed(vm,opts.computed) 484 } 485 // 初始化data 如果存在就initData 486 if(opts.data ){ 487 initData(vm) 488 }else{ 489 // 放在响应式系统里面 490 observer(vm._data={},true) 491 } 492 } 493 function initMinxin(options){ 494 Vue.prototype._init = function(options){ 495 var vm = this 496 // 记录生成的vue实例对象 497 vm._uip = uip++ // //-------忘记写 498 //合并选项 499 vm.$options =mergeOptions(resolveConstructorOptions(vm.constructor),options,vm) 500 // // 初始化数值代理 501 initProxy(vm) 502 // 初始化当前实例的$children 和$parent 的指向 503 initLifeCycle(vm) 504 // 调用beforeCreate 的钩子函数 505 callHook(vm, 'beforeCreate') 506 // 初始化数据 507 initState(vm) 508 } 509 } 510 function Vue(options){ 511 // 安全机制 512 if(!(this instanceof Vue)){ //-------忘记写 513 warn('Vue是一个构造函数,必须是由new关键字调用') 514 } 515 this._init(options) 516 } 517 initMinxin() // 初始化选项1: 规范 2: 合并策略。 518 Vue.options = { 519 components: { 520 transtions: {}, 521 keepAlive:{}, 522 solt:{}, 523 transtionsGroup:{} 524 }, 525 directives:{}, 526 _bash: Vue 527 } 528 function initExend(Vue){ 529 Vue.extend = function(extendOptions){ 530 extendOptions = extendOptions || {} // -----忘记写 531 var Super = this 532 var Child = function VueComponent(options) { 533 this._init(options) 534 } 535 Child.prototype = Object.create(Super.prototype) 536 Child.prototype.constructor = Child // 改变constructor 的指向 537 Child.options = mergeOptions(Super.options,extendOptions) 538 // 子类继承父类的静态方法。 539 Child.extend = Vue.extend 540 // console.log(new Child({})) 541 return Child 542 } 543 } 544 initExend(Vue) 545 return Vue 546 })
dome.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 </div> 13 <script src="vue.js"></script> 14 <!-- <script src="vue2.5.1.js"></script> --> 15 <script type="text/javascript"> 16 var componentA = { 17 el: "#app" 18 } 19 var vm = new Vue({ 20 el:"#app", 21 data: { 22 message: "hello Vue", 23 key: "wodow", 24 test: 1 25 }, 26 beforeCreate: function(){ 27 console.log('我钩子函数beforeCreate') 28 }, 29 components:{ 30 humle: componentA 31 } 32 33 }) 34 35 vm.test = 2; 36 console.log(vm) 37 </script> 38 </body> 39 </html>