【js】vue 2.5.1 源码学习 (四) 钩子函数 资源选项 watch 的合并策略

2019年12月14日 阅读数:21
这篇文章主要向大家介绍【js】vue 2.5.1 源码学习 (四) 钩子函数 资源选项 watch 的合并策略,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。
大致思路 (三)
   1.钩子函数 自定义策略
      LIFECYCLE_HOOKS= []
     created = [function(){} , function(){}] 组装方法。
     ==> starts[hook]= mergeHook
           ==>  mergeHook(parent,child) // 合并parentVal 和childVal
 2.资源选项 自定义策略
        ==> ASSET_TYPES = []
              ==> starts[type] = mergeAssets
              mergeAssets  ==> Object.create(parentVal || null)
              ===> if(childVal) assetObjectType // 检测conponents 值是不是object
              ===> extend(res,childVal) // 合并
 3.选择watch 合并策略 监听vue实例数据的变化
    ==> strats.watch   
vue.js  以下
  1 //  大致思路  (三)
  2 // 1.钩子函数  自定义策略
  3 /** LIFECYCLE_HOOK= []   
  4  * created = [function(){}  , function(){}] 组装方法。 
  5  *  ==>  starts.[hook]= mergeHook
  6  *       mergeHook(parent,child) // 合并parentVal 和childVal
  7 */
  8 /*  2.资源选项  自定义策略
  9 *   ==> ASSET_TYPES = []
 10 *   ==> starts.[type] = mergeAssets  
 11 *       ==>  Object.create(parentVal || null)
 12         ==>  if(childVal) assetObjectType  //  检测conponents 值是不是object
 13         ==>  extend(res,childVal)  // 合并      
 14 *   
 15 */
 16 // 3.选择watch 合并策略  监听vue实例数据的变化
 17 /*   ==> strats.watch */
 18   
 19 
 20 (function(global,factory){
 21     // 兼容 cmd  
 22     typeof exports === 'object'  && module !== 'undefined' ? module.exports = factory():   
 23     // Amd
 24     typeof define  === 'function' && define.amd ?  define(factory) : global.Vue = factory();
 25 })(this,function(){
 26     var uip = 0;
 27     function warn(string){
 28         console.error('Vue Wran:' + string)
 29     }
 30     function resolveConstructorOptions(Con){
 31         var options = Con.options;
 32         // 判断是否为vm的实例 或者是子类
 33           return options
 34     }
 35     var hasOwnPropeerty = Object.prototype.hasOwnProperty
 36     function hasOwn(obj , key){
 37         return hasOwnPropeerty.call(obj,key)
 38     }
 39     function makeMap(str, expectsLoweraseC){
 40         if(expectsLoweraseC){
 41             str = str.toLowerCase()
 42         }
 43         var map = Object.create(null)
 44         var list = str.split(',')
 45         for(var i = 0 ; i < list.length; i++){
 46             map[list[i]] = true
 47         }
 48         return function(key){
 49             return map[key]
 50         
 51         }
 52     }
 53     var  isbuiltInTag = makeMap('slot,component',true)
 54     var isHTMLTag = makeMap(
 55         'html,body,base,head,link,meta,style,title,' +
 56         'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
 57         'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
 58         'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
 59         's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
 60         'embed,object,param,source,canvas,script,noscript,del,ins,' +
 61         'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
 62         'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
 63         'output,progress,select,textarea,' +
 64         'details,dialog,menu,menuitem,summary,' +
 65         'content,element,shadow,template,blockquote,iframe,tfoot'
 66     );
 67     var isSVG = makeMap(
 68         'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
 69         'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
 70         'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
 71         true
 72     );
 73     var ASSET_TYPES = [
 74         'component',
 75         'directive',
 76         'filter'
 77     ];
 78 
 79     var LIFECYCLE_HOOKS = [
 80         'beforeCreate',
 81         'created',
 82         'beforeMount',
 83         'mounted',
 84         'beforeUpdate',
 85         'updated',
 86         'beforeDestroy',
 87         'destroyed',
 88         'activated',
 89         'deactivated',
 90         'errorCaptured'
 91     ];
 92 
 93     var isReservedTag = function(key){
 94         return isHTMLTag(key) || isSVG(key) 
 95     }
 96     function validataComponentName(key){
 97         //检测component 的自定义名称是否合格 
 98         // 只能是字母开头或下划线,必须是字母开头
 99         if(!(/^[a-zA-Z][\w-]*$/g.test(key))){
100            warn('组件的名称必须是字母或中横线,必须由字母开头')
101         }
102         // 1. 不能为内置对象,2.不能是html ,和avg的内部标签
103         if( isbuiltInTag(key) || isReservedTag(key)){
104             warn('不能为html标签或者avg的内部标签')
105         } 
106     }
107     function checkComonpents(child){
108         for(var key in child.components){
109             validataComponentName(key)
110         }
111     }
112    // 配置对象
113     var config = {
114         // 自定义的策略
115         optionMergeStrategies:{}
116     }
117     var strats = config.optionMergeStrategies
118     strats.el = function(parent,child , key , vm){
119        
120           if(!vm){
121               warn('选项'+key+'只能在vue实例用使用')
122           }
123           return defaultStrat(parent,child , key , vm)
124     }
125     function mergeData(to,form){
126         // 终极合并
127         if(!form){
128             return to
129         }
130         // 具体合并。  
131     }
132     function mergeDataorFn(parentVal,childVal,vm){
133         // 合并 parentVal childVal  都是函数
134         if(!vm){
135             if(!childVal){
136                 return parentVal
137             }
138             if(!parentVal){
139                 return childVal
140             }
141            return  function mergeDataFn(parentVal,childVal,vm){//只是一个函数   什么样的状况下调用 加入响应式系统 
142                // 合并子组件对应的data 和   父组件对应的data
143                return mergeData( 
144                    typeof parentVal === 'function' ? parentVal.call(this,this) : parentVal,    // -----忘记写
145                    typeof childVal === 'function' ? childVal.call(this,this): childVal)      // -----忘记写
146            }
147         }else{ // vue实例
148             return function mergeInstanceDataFn(parentVal,childVal,vm){//只是一个函数   什么样的状况下调用 加入响应式系统 
149                 var InstanceData = typeof childVal === 'function' ? childVal.call(vm,vm): childVal;   // -----忘记写
150                 var defaultData = typeof parentVal === 'function' ? parent.call(vm,vm): parentVal;   // -----忘记写
151                 if(InstanceData){
152                     return mergeData(parentVal,childVal)
153                 }else{                // -----忘记写
154                     defaultData
155                 }
156                 
157             }
158         }
159     }
160     strats.data = function(parent,child , key , vm){
161         if(!vm){
162           // console.log(typeof child === 'function')
163             if(child && !(typeof child === 'function')){
164                 warn('data必须返回是一个function')
165             }
166            return mergeDataorFn(parent,child)
167         }
168         return mergeDataorFn(parent,child,vm)
169     }
170     // 生命周期策略的合并,值等于一个function 若是是有两个,放到一个数组里面。
171     function mergeHook(parentVal,childVal,key,vm){
172         // console.log(key)
173         // console.log(parentVal.concat(childVal) )
174         return childVal ?  parentVal ? parentVal.concat(childVal):
175                 Array.isArray(childVal) ?  childVal : [childVal] : parentVal
176     }
177     LIFECYCLE_HOOKS.forEach(function(key){
178         strats[key] = mergeHook
179     });
180     // 检测是否为object
181     function isPlainObject(obj){
182         return Object.prototype.toString.call(obj) === '[object Object]'
183     }
184     function assetObjectType(obj){
185         if(!isPlainObject(obj)){
186             marn('选项的值'+obj+'无效:必须是一个对象的')
187         }
188     }
189     // 对parent实现链式调用。
190     function extend(to,form){
191         for(key in form){
192             to[key] = form[key]
193         }
194         return to
195     }
196     // 实现Assets 的策略合并  conmponents  filter  diretive   
197     function mergeAssets(parentVal,childVal,key,vm){
198         var parent = Object.create(parentVal || null)   // 保证子类的每一个值的指向都是一个新的object。不然回出现相互引用的现象。
199         if(childVal){
200             assetObjectType(childVal)
201             return extend(parent,childVal)
202         }    
203         return parent
204     }
205     ASSET_TYPES.forEach(function(key){
206         strats[key+'s'] = mergeAssets
207     })
208     // 实现watch的策略和并,将相同的属性放到一个数组里面。
209     strats.watch = function(parentVal,childVal , key , vm){
210         if(!childVal){
211             return Object.create(parentVal)
212         }
213         var res = {}
214         res =  extend(res,parentVal) 
215         for(var key in childVal){
216             var parent = res[key]
217             var child  = childVal[key]
218             res[key] = parent ? Array.isArray(parent) ? parent.concat(child) : [parent].concat(child) : 
219             Array.isArray(child) ? child : [child] ;
220          }
221         return res
222     }
223     function defaultStrat(parent,child , key , vm){
224         return child === undefined ? parent :child ;
225     }
226     function mergeOptions(parent,child,vm){
227         var options = {}
228         // 检测是component 是不是合法的  
229      
230         checkComonpents(child)
231         
232         // console.log(parent, child)
233         for(key in parent){
234             magerField(key)
235         }
236         for(key in child){
237             if(!hasOwn(parent ,key)){  // parent 中循环过地方不进行循环
238                 magerField(key)  // ----忘记写
239             }
240               
241         }
242         // 默认合并策略
243         function magerField(key){  
244             // 自定义策略  默认策略 
245             // console.log(key)
246             var result = strats[key] || defaultStrat        // ---忘记写
247             options[key] = result(parent[key],child[key] , key , vm)
248         }
249         // console.log(options)
250         return options
251     }
252     function initMinxin(options){
253         Vue.prototype._init = function(options){
254             var vm = this 
255             // 记录生成的vue实例对象 
256             vm._uip =  uip++ //   //-------忘记写
257           
258              vm.$options =mergeOptions(resolveConstructorOptions(vm.constructor),options,vm)
259         }
260     }
261     function Vue(options){
262         // 安全机制
263         if(!(this instanceof Vue)){     //-------忘记写
264             warn('Vue是一个构造函数,必须是由new关键字调用')  
265         }
266         this._init(options)
267     }
268     initMinxin()  //  初始化选项1: 规范 2: 合并策略。
269     Vue.options = {
270         components: {
271             transtions: {},
272             keepAlive:{},
273             solt:{},
274             transtionsGroup:{}
275         },
276         directives:{},
277         _bash: Vue
278     }
279     function initExend(Vue){
280         Vue.extend = function(extendOptions){
281             extendOptions = extendOptions || {}   // -----忘记写
282             var Super = this 
283             var Child = function VueComponent(options) {
284                 this._init(options)
285             }
286             Child.prototype = Object.create(Super.prototype)
287             Child.prototype.constructor = Child   // 改变constructor 的指向
288             Child.options = mergeOptions(Super.options,extendOptions)
289             // 子类继承父类的静态方法。
290             Child.extend = Vue.extend
291             // console.log(new Child({}))
292             return Child
293         }
294     }
295     initExend(Vue)
296     return Vue
297 })
View Code

 dome.html  代码以下javascript

 1 <body>
 2     <div id="app">
 3         <huml></huml>
 4     </div>
 5     <script src="vue.js"></script>
 6     <!-- <script src="vue2.5.1.js"></script> -->
 7     <script type="text/javascript">
 8         var componentA = {
 9             el: "#app"
10         }
11         var vm = new Vue({
12             el:"#app",
13             data: {
14                 message: "hello Vue",
15                 key: "wodow"
16             },
17             components:{
18                 humle: componentA
19             }
20             
21         })
22         // console.log(Vue)
23         var Parent = Vue.extend({
24             data: function() {},
25             components:{
26                 huml: componentA
27             },
28             created : function(){
29 
30             },
31             watch: {
32                 test: function(){}
33             }
34         })
35         var Child = Parent.extend({
36              components:{
37                 humlt: componentA
38             },
39             created: function(){
40 
41             },
42             watch: {
43                 aa: function(){},
44                 test: function(){}
45             }
46         });
47         // console.log(vm.$options)
48         console.log (Parent.options)
49         console.log(Child.options)
50     </script>
51 </body>

以上仅为我的学习笔记,若有疑问,请评论回复html