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