zoukankan      html  css  js  c++  java
  • 【js】vue 2.5.1 源码学习 (七) 初始化之 initState 响应式系统基本思路

    大体思路(六)
    本节内容:
    一、生命周期的钩子函数的实现
      ==》 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 })
    View Code

    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>
    View Code
  • 相关阅读:
    死啃了String源码之后
    springBoot中Bean的生命周期
    @RequestMapping,@RequsetBody等注解说明
    mybatis的逆向工程的使用
    java中的Arrays这个工具类你真的会用吗
    Search in Rotated Sorted Array leetcode的第33道题
    看了Java的Class的源码,我自闭了
    面试被问了三次的http状态码到底有什么
    搞懂HashMap,这一篇就够了
    十大排序的java实现(配有动图)
  • 原文地址:https://www.cnblogs.com/yeujuan/p/10998577.html
Copyright © 2011-2022 走看看