zoukankan      html  css  js  c++  java
  • 【js】 vue 2.5.1 源码学习(五) props directives规范化 props 合并策略

    大体思路 (四)
    上节回顾:
      A: 对于生命周期函数将父子组件的函数放到一个数组里面,特定时间点调用,保证父子组件函数都调用到。
      B: 对于directive,filters,components 等的资源选项,父选项将以原型的形势处理,正式因为这样子,在任何地方都可以用到内部自定义指令。
      C: 对于watch选项的合并,类似于生命周期,如果父子组件相同的观测字段,将合并为一个数组。
    本节内容:
      props normalizeProps normalizeDirective 规范化
      props 自定义策略
      directives 规范化
      normalizeProps(child) //规范props
        ==》while(i--) 找到每个props的元素。 “使用数组语法时 Props成员必须为字符串
        ==> camelize 将a-a变为aA 将中横线,转化为小驼峰命名。 每个元素 = {type:null}
        ==> camelizeRE = /-(w)/g ;
        ==> 非数组的情况 循环每个建,转为驼峰, 将值传给res[name] = object
        ==> else 选项porps必须时一个数组或者对象。
       mormalizeDirectives // 规范指令的选项
        ==> directives: {
            test1: {
              bind: function(){}
              upteat: function(){}
              },
            test2:function(){}
          }
      strats.props = 策略合并 ==> 如果都存在,就用child覆盖parent。
    vue.js 代码如下
      1 //  大体思路  (四)
      2 //  上节回顾:
      3 //  A: 对于生命周期函数将父子组件的函数放到一个数组里面,特定时间点调用,保证父子组件函数都调用到。
      4 //  B: 对于directive,filters,components 等的资源选项,父选项将以原型的形势处理,正式因为这样子,在任何地方都可以用到内部自定义指令。
      5 //  C: 对于watch选项的合并,类似于生命周期,如果父子组件相同的观测字段,将合并为一个数组。
      6 //  本节内容:
      7 //    props  normalizeProps normalizeDirective  规范化
      8 //    props   自定义策略  
      9 //    directives  规范化
     10 //    normalizeProps(child)  //规范props
     11 //      ==》while(i--) 找到每个props的元素。 “使用数组语法时 Props成员必须为字符串
     12 //      ==> camelize  将a-a变为aA 将中横线,转化为小驼峰命名。 每个元素 = {type:null}
     13 //      ==> camelizeRE = /-(w)/g ;  
     14 //      ==> 非数组的情况  循环每个建,转为驼峰, 将值传给res[name] = object
     15 //      ==> else 选项porps必须时一个数组或者对象。 
     16 //    mormalizeDirectives  // 规范指令的选项   
     17 //         ==> directives: {
     18 //             test1: {
     19 //                 bind: function(){
     20 
     21 //                 }
     22 //                 upteat: function(){
     23 
     24 //                 }
     25 //             },
     26 //             test2:function(){
     27 
     28 //             }        
     29 //         }  
     30 //  strats.props = 策略合并
     31 //  如果都存在,就用child覆盖parent。
     32 
     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 resolveConstructorOptions(Con){
     46         var options = Con.options;
     47         // 判断是否为vm的实例 或者是子类
     48           return options
     49     }
     50     var hasOwnPropeerty = Object.prototype.hasOwnProperty
     51     function hasOwn(obj , key){
     52         return hasOwnPropeerty.call(obj,key)
     53     }
     54     function makeMap(str, expectsLoweraseC){
     55         if(expectsLoweraseC){
     56             str = str.toLowerCase()
     57         }
     58         var map = Object.create(null)
     59         var list = str.split(',')
     60         for(var i = 0 ; i < list.length; i++){
     61             map[list[i]] = true
     62         }
     63         return function(key){
     64             return map[key]
     65         
     66         }
     67     }
     68     var  isbuiltInTag = makeMap('slot,component',true)
     69     var isHTMLTag = makeMap(
     70         'html,body,base,head,link,meta,style,title,' +
     71         'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
     72         'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
     73         'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
     74         's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
     75         'embed,object,param,source,canvas,script,noscript,del,ins,' +
     76         'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
     77         'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
     78         'output,progress,select,textarea,' +
     79         'details,dialog,menu,menuitem,summary,' +
     80         'content,element,shadow,template,blockquote,iframe,tfoot'
     81     );
     82     var isSVG = makeMap(
     83         'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
     84         'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
     85         'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
     86         true
     87     );
     88     var ASSET_TYPES = [
     89         'component',
     90         'directive',
     91         'filter'
     92     ];
     93 
     94     var LIFECYCLE_HOOKS = [
     95         'beforeCreate',
     96         'created',
     97         'beforeMount',
     98         'mounted',
     99         'beforeUpdate',
    100         'updated',
    101         'beforeDestroy',
    102         'destroyed',
    103         'activated',
    104         'deactivated',
    105         'errorCaptured'
    106     ];
    107 
    108     var isReservedTag = function(key){
    109         return isHTMLTag(key) || isSVG(key) 
    110     }
    111     function validataComponentName(key){
    112         //检测component 的自定义名称是否合格 
    113         // 只能是字母开头或下划线,必须是字母开头
    114         if(!(/^[a-zA-Z][w-]*$/g.test(key))){
    115            warn('组件的名称必须是字母或中横线,必须由字母开头')
    116         }
    117         // 1. 不能为内置对象,2.不能是html ,和avg的内部标签
    118         if( isbuiltInTag(key) || isReservedTag(key)){
    119             warn('不能为html标签或者avg的内部标签')
    120         } 
    121     }
    122     function checkComonpents(child){
    123         for(var key in child.components){
    124             validataComponentName(key)
    125         }
    126     }
    127    // 配置对象
    128     var config = {
    129         // 自定义的策略
    130         optionMergeStrategies:{}
    131     }
    132     var strats = config.optionMergeStrategies
    133     strats.el = function(parent,child , key , vm){
    134        
    135           if(!vm){
    136               warn('选项'+key+'只能在vue实例用使用')
    137           }
    138           return defaultStrat(parent,child , key , vm)
    139     }
    140     function mergeData(to,form){
    141         // 终极合并
    142         if(!form){
    143             return to
    144         }
    145         // 具体合并。  
    146     }
    147     function mergeDataorFn(parentVal,childVal,vm){
    148         // 合并 parentVal childVal  都是函数
    149         if(!vm){
    150             if(!childVal){
    151                 return parentVal
    152             }
    153             if(!parentVal){
    154                 return childVal
    155             }
    156            return  function mergeDataFn(parentVal,childVal,vm){//只是一个函数   什么样的情况下调用 加入响应式系统 
    157                // 合并子组件对应的data 和   父组件对应的data
    158                return mergeData( 
    159                    typeof parentVal === 'function' ? parentVal.call(this,this) : parentVal,    // -----忘记写
    160                    typeof childVal === 'function' ? childVal.call(this,this): childVal)      // -----忘记写
    161            }
    162         }else{ // vue实例
    163             return function mergeInstanceDataFn(parentVal,childVal,vm){//只是一个函数   什么样的情况下调用 加入响应式系统 
    164                 var InstanceData = typeof childVal === 'function' ? childVal.call(vm,vm): childVal;   // -----忘记写
    165                 var defaultData = typeof parentVal === 'function' ? parent.call(vm,vm): parentVal;   // -----忘记写
    166                 if(InstanceData){
    167                     return mergeData(parentVal,childVal)
    168                 }else{                // -----忘记写
    169                     defaultData
    170                 }
    171                 
    172             }
    173         }
    174     }
    175     strats.data = function(parent,child , key , vm){
    176         if(!vm){
    177           // console.log(typeof child === 'function')
    178             if(child && !(typeof child === 'function')){
    179                 warn('data必须返回是一个function')
    180             }
    181            return mergeDataorFn(parent,child)
    182         }
    183         return mergeDataorFn(parent,child,vm)
    184     }
    185     // 生命周期策略的合并,值等于一个function 如果是有两个,放到一个数组里面。
    186     function mergeHook(parentVal,childVal,key,vm){
    187         // console.log(key)
    188         // console.log(parentVal.concat(childVal) )
    189         return childVal ?  parentVal ? parentVal.concat(childVal):
    190                 Array.isArray(childVal) ?  childVal : [childVal] : parentVal
    191     }
    192     LIFECYCLE_HOOKS.forEach(function(key){
    193         strats[key] = mergeHook
    194     });
    195     // 检测是否为object
    196     function isPlainObject(obj){
    197         return Object.prototype.toString.call(obj) === '[object Object]'
    198     }
    199     function assetObjectType(obj){
    200         if(!isPlainObject(obj)){
    201             marn('选项的值'+obj+'无效:必须是一个对象的')
    202         }
    203     }
    204     // 对parent实现链式调用。
    205     function extend(to,form){
    206         for(key in form){
    207 
    208             to[key] = form[key]
    209         }
    210         return to
    211     }
    212     // 实现Assets 的策略合并  conmponents  filter  diretive   
    213     function mergeAssets(parentVal,childVal,key,vm){
    214         var parent = Object.create(parentVal || null)   // 保证子类的每个值的指向都是一个新的object。否则回出现相互引用的现象。
    215         if(childVal){
    216             assetObjectType(childVal)
    217             return extend(parent,childVal)
    218         }    
    219         return parent
    220     }
    221     ASSET_TYPES.forEach(function(key){
    222         strats[key+'s'] = mergeAssets
    223     })
    224     // 实现watch的策略和并,将相同的属性放到一个数组里面。
    225     strats.watch = function(parentVal,childVal , key , vm){
    226         if(!childVal){
    227             return Object.create(parentVal)
    228         }
    229         var res = {}
    230         res =  extend(res,parentVal) 
    231         for(var key in childVal){
    232             var parent = res[key]
    233             var child  = childVal[key]
    234             res[key] = parent ? Array.isArray(parent) ? parent.concat(child) : [parent].concat(child) : 
    235             Array.isArray(child) ? child : [child] ;
    236          }
    237         return res
    238     }
    239     // 实现props指令的合并策略
    240     strats.props = function(parentVal,childVal , key , vm){
    241         if(!childVal){
    242             return parentVal
    243         }
    244         var res = Object.create( null)
    245         extend(res,parentVal)
    246         if(childVal){
    247              extend(res,childVal)
    248         }
    249         return res
    250     }
    251     function defaultStrat(parent,child , key , vm){
    252         return child === undefined ? parent :child ;
    253     }
    254     var cmalizeRE = /-(w)/g
    255     function camelize(val){
    256         return val.replace(cmalizeRE,function(c,m){
    257             return m ? m.toUpperCase(): ""
    258         })   
    259     }
    260     function normalizeProps(options){
    261         var props = options.props
    262         if(!props){
    263             return 
    264         }
    265         var i , val , name
    266         var res = {}
    267         if(Array.isArray(props)){
    268             i = props.length
    269             while(i--){
    270                 val = props[i]
    271                 if(toString.call(val) === '[object String]'){
    272                     name  = camelize(val)
    273                     res[name] =  {type: null}
    274                 }else{
    275                     warn('使用数组愈发时props成员' +val+ '必须时一个数组')
    276                 }
    277                 
    278 
    279             }
    280         }else if(isPlainObject(props)){
    281             for(var key in props){
    282                 val = props[key]
    283                 name = camelize(key)
    284                 res[name] = isPlainObject(val) ? val : {type: val}
    285             }
    286         }else {
    287             warn('选项props的值必须是一个对象或者是数组')
    288         }
    289         options.props = res
    290     }
    291     function mormalizeDirectives(options){
    292         var dir = options.directives
    293         var res = {}
    294         if(!dir){
    295             return 
    296         }
    297         if(dir){
    298             for(var key in dir){
    299                 var val = dir[key]
    300                 var name = camelize(key)
    301                 if(isPlainObject(val)){
    302                     res[name] = val
    303                 }
    304                 if(toString.call(val) === '[object Function]'){
    305                     res[name] = {
    306                         bind: val,
    307                         upata: val
    308                     }
    309                 }
    310             }
    311         }
    312         options.directives = res
    313 
    314     }
    315     function mergeOptions(parent,child,vm){
    316         var options = {}
    317         // 检测是component 是否是合法的  
    318         checkComonpents(child)
    319         // 规范props 
    320         normalizeProps(child)
    321         // 规范 dirctives 
    322         mormalizeDirectives(child)
    323         
    324         // console.log(parent, child)
    325         for(key in parent){
    326             magerField(key)
    327         }
    328         for(key in child){
    329             if(!hasOwn(parent ,key)){  // parent 中循环过地方不进行循环
    330                 magerField(key)  // ----忘记写
    331             }
    332               
    333         }
    334         // 默认合并策略
    335         function magerField(key){  
    336             // 自定义策略  默认策略 
    337             // console.log(key)
    338             var result = strats[key] || defaultStrat        // ---忘记写
    339             options[key] = result(parent[key],child[key] , key , vm)
    340         }
    341         // console.log(options)
    342         return options
    343     }
    344     function initMinxin(options){
    345         Vue.prototype._init = function(options){
    346             var vm = this 
    347             // 记录生成的vue实例对象 
    348             vm._uip =  uip++ //   //-------忘记写
    349           
    350              vm.$options =mergeOptions(resolveConstructorOptions(vm.constructor),options,vm)
    351         }
    352     }
    353     function Vue(options){
    354         // 安全机制
    355         if(!(this instanceof Vue)){     //-------忘记写
    356             warn('Vue是一个构造函数,必须是由new关键字调用')  
    357         }
    358         this._init(options)
    359     }
    360     initMinxin()  //  初始化选项1: 规范 2: 合并策略。
    361     Vue.options = {
    362         components: {
    363             transtions: {},
    364             keepAlive:{},
    365             solt:{},
    366             transtionsGroup:{}
    367         },
    368         directives:{},
    369         _bash: Vue
    370     }
    371     function initExend(Vue){
    372         Vue.extend = function(extendOptions){
    373             extendOptions = extendOptions || {}   // -----忘记写
    374             var Super = this 
    375             var Child = function VueComponent(options) {
    376                 this._init(options)
    377             }
    378             Child.prototype = Object.create(Super.prototype)
    379             Child.prototype.constructor = Child   // 改变constructor 的指向
    380             Child.options = mergeOptions(Super.options,extendOptions)
    381             // 子类继承父类的静态方法。
    382             Child.extend = Vue.extend
    383             // console.log(new Child({}))
    384             return Child
    385         }
    386     }
    387     initExend(Vue)
    388     return Vue
    389 })
    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             },
    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.$options)
    69         console.log (Parent.options)
    70         console.log(Child.options)
    71     </script>
    72 </body>
    73 </html>
    View Code

    合并完效果

    以上为个人学习总结,如有问题,请回复。

  • 相关阅读:
    HDU 3681 Prison Break 越狱(状压DP,变形)
    POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
    ZOJ 3471 Most Powerful (状压DP,经典)
    POJ 2288 Islands and Bridges (状压DP,变形)
    HDU 3001 Travelling (状压DP,3进制)
    POJ 3311 Hie with the Pie (状压DP)
    POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
    FZU 2204 7
    POJ 3254 Corn Fields (状压DP,轮廓线DP)
    ZOJ 3494 BCD Code (数位DP,AC自动机)
  • 原文地址:https://www.cnblogs.com/yeujuan/p/10979154.html
Copyright © 2011-2022 走看看