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