vue 2.5.1 源码学习 之Vue.extend 和 data的合并策略


Posted in Javascript onJune 04, 2019

1. 子类父类

 2.Vue.extend()      //创建vue的子类

组件的语法器 Vue.extend(options)

Profile().$mount('#app') // 挂在app上,并替换app

新建 initExend

==》 Vue.extend

 3. strat.data

==> if(!vm){子组件中data的值是一个方法function ==> mergeDataorFn()} // 数据的合并

==> else {} //通过实例绑定的data 实际是一个函数 mergeDataorFn

==》 mergeDataorFn if(!vm) mergeDataFn ==> mergeData()

else ==》mergedInstanceDataFn ==>mergeData()

    mergeData(to,from) //终极合并

jquery.extend // 深copy和浅copy

// 大体思路 (二)
// 1. 子类父类 
/* 
   2.Vue.extend()  //创建vue的子类
   组件的语法器 Vue.extend(options)
   Profile().$mount('#app') // 挂在app上,并替换app
   新建 initExend  
     ==》 Vue.extend
*/
/* 3. strat.data  
  ==> if(!vm){子组件中data的值是一个方法function ==> mergeDataorFn()} // 数据的合并
  ==> else {} //通过实例绑定的data 实际是一个函数 mergeDataorFn 
  ==》 mergeDataorFn if(!vm) mergeDataFn ==> mergeData()  
     else ==》mergedInstanceDataFn ==>mergeData()
  mergeData(to,from) //终极合并
  jquery.extend // 深copy和浅copy
*/
(function(global,factory){
  // 兼容 cmd 
  typeof exports === 'object' && module !== 'undefined' ? module.exports = factory():  
  // Amd
  typeof define === 'function' && define.amd ? define(factory) : global.Vue = factory();
})(this,function(){
  var uip = 0;
  function warn(string){
    console.error('Vue Wran:' + string)
  }
  function resolveConstructorOptions(Con){
    var options = Con.options;
    // 判断是否为vm的实例 或者是子类
     return options
  }
  var hasOwnPropeerty = Object.prototype.hasOwnProperty
  function hasOwn(obj , key){
    return hasOwnPropeerty.call(obj,key)
  }
  function makeMap(str, expectsLoweraseC){
    if(expectsLoweraseC){
      str = str.toLowerCase()
    }
    var map = Object.create(null)
    var list = str.split(',')
    for(var i = 0 ; i < list.length; i++){
      map[list[i]] = true
    }
    return function(key){
      return map[key]
    }
  }
  var isbuiltInTag = makeMap('slot,component',true)
  var isHTMLTag = makeMap(
    'html,body,base,head,link,meta,style,title,' +
    'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
    'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
    'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
    's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
    'embed,object,param,source,canvas,script,noscript,del,ins,' +
    'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
    'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
    'output,progress,select,textarea,' +
    'details,dialog,menu,menuitem,summary,' +
    'content,element,shadow,template,blockquote,iframe,tfoot'
  );
  var isSVG = makeMap(
    'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
    'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
    'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
    true
  );
  var isReservedTag = function(key){
    return isHTMLTag(key) || isSVG(key) 
  }
  function validataComponentName(key){
    //检测component 的自定义名称是否合格 
    // 只能是字母开头或下划线,必须是字母开头
    if(!(/^[a-zA-Z][\w-]*$/g.test(key))){
      warn('组件的名称必须是字母或中横线,必须由字母开头')
    }
    // 1. 不能为内置对象,2.不能是html ,和avg的内部标签
    if( isbuiltInTag(key) || isReservedTag(key)){
      warn('不能为html标签或者avg的内部标签')
    } 
  }
  function checkComonpents(child){
    for(var key in child.component){
      validataComponentName(key)
    }
  }
  // 配置对象
  var config = {
    // 自定义的策略
    optionMergeStrategies:{}
  }
  var strats = config.optionMergeStrategies
  strats.el = function(parent,child , key , vm){
     if(!vm){
       warn('选项'+key+'只能在vue实例用使用')
     }
     return defaultStrat(parent,child , key , vm)
  }
  function mergeData(to,form){
    // 终极合并
    if(!form){
      return to
    }
  }
  function mergeDataorFn(parentVal,childVal,vm){
    // 合并 parentVal childVal 都是函数
    if(!vm){
      if(!childVal){
        return parentVal
      }
      if(!parentVal){
        return childVal
      }
      return function mergeDataFn(parentVal,childVal,vm){//只是一个函数  什么样的情况下调用 加入响应式系统 
        // 合并子组件对应的data 和  父组件对应的data
        return mergeData( 
          typeof parentVal === 'function' ? parentVal.call(this,this) : parentVal,  // -----忘记写
          typeof childVal === 'function' ? childVal.call(this,this): childVal)   // -----忘记写
      }
    }else{ // vue实例
      return function mergeInstanceDataFn(parentVal,childVal,vm){//只是一个函数  什么样的情况下调用 加入响应式系统 
        var InstanceData = typeof childVal === 'function' ? childVal.call(vm,vm): childVal;  // -----忘记写
        var defaultData = typeof parentVal === 'function' ? parent.call(vm,vm): parentVal;  // -----忘记写
        if(InstanceData){
          return mergeData(parentVal,childVal)
        }else{        // -----忘记写
          defaultData
        }
      }
    }
  }
  strats.data = function(parent,child , key , vm){
    if(!vm){
     // console.log(typeof child === 'function')
      if(child && !(typeof child === 'function')){
        warn('data必须返回是一个function')
      }
      return mergeDataorFn(parent,child)
    }
    return mergeDataorFn(parent,child,vm)
  }
  function defaultStrat(parent,child , key , vm){
    return child === undefined ? parent :child ;
  }
  function mergeOptions(parent,child,vm){
    var options = {}
    // 检测是component 是否是合法的 
    checkComonpents(child)
    // console.log(parent, child)
    for(key in parent){
      magerField(key)
    }
    for(key in child){
      if(!hasOwn(parent ,key)){ // parent 中循环过地方不进行循环
        magerField(key) // ----忘记写
      }
    }
    // 默认合并策略
    function magerField(key){ 
      // 自定义策略 默认策略 
      // console.log(key)
      var result = strats[key] || defaultStrat    // ---忘记写
      options[key] = result(parent[key],child[key] , key , vm)
    }
    // console.log(options)
    return options
  }
  function initMinxin(options){
    Vue.prototype._init = function(options){
      var vm = this 
      // 记录生成的vue实例对象 
      vm._uip = uip++ //  //-------忘记写
       vm.$options =mergeOptions(resolveConstructorOptions(vm.constructor),options,vm)
    }
  }
  function Vue(options){
    // 安全机制
    if(!(this instanceof Vue)){   //-------忘记写
      warn('Vue是一个构造函数,必须是由new关键字调用') 
    }
    this._init(options)
  }
  initMinxin() // 初始化选项1: 规范 2: 合并策略。
  Vue.options = {
    components: {},
    directives:{},
    _bash: Vue
  }
  function initExend(Vue){
    Vue.extend = function(extendOptions){
      extendOptions = extendOptions || {}  // -----忘记写
      var Super = this 
      var Child = function VueComponent() {
        this._init(options)
      }
      Child.prototype = Object.create(Super.prototype)
      Child.prototype.constructor = Child  // 改变constructor 的指向
      Child.options = mergeOptions(Super.options,extendOptions)
      // 子类继承父类的静态方法。
      Child.extend = Vue.extend
      return Child
    }
  }
  initExend(Vue)
  return Vue
})
<body>
  <div id="app">
    <huml></huml>
  </div>
  <script src="vue.js"></script>
  <!-- <script src="vue2.5.1.js"></script> -->
  <script type="text/javascript">
    var componentA = {
      el: "#app"
    }
    var vm = new Vue({
      el:"#app",
      data: {
        message: "hello Vue",
        key: "wodow"
      },
      components:{
        huml: componentA
      }
    })
    // console.log(Vue)
    var Parent = Vue.extend({
      data: function() {}
    })
    var Child = Parent.extend({});
    console.log(vm.$options)
  </script>
</body>

总结

以上所述是小编给大家介绍的vue 2.5.1 源码学习 之Vue.extend 和 data的合并策略,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
JS实现打开本地文件或文件夹
Mar 09 Javascript
JXTree对象,读取外部xml文件数据,生成树的函数
Apr 02 Javascript
JS 事件绑定函数代码
Apr 28 Javascript
zeroclipboard复制到剪切板的flash
Aug 04 Javascript
从数组中随机取x条不重复数据的JS代码
Dec 24 Javascript
全面了解函数声明与函数表达式、变量提升
Aug 09 Javascript
基于LayUI实现前端分页功能的方法
Jul 22 Javascript
详解webpack require.ensure与require AMD的区别
Dec 13 Javascript
使用D3.js创建物流地图的示例代码
Jan 27 Javascript
js实现简单模态框实例
Nov 16 Javascript
node.js基于socket.io快速实现一个实时通讯应用
Apr 23 Javascript
react结合bootstrap实现评论功能
May 30 Javascript
vue实现分环境打包步骤(给不同的环境配置相对应的打包命令)
Jun 04 #Javascript
JavaScript实现页面中录音功能的方法
Jun 04 #Javascript
vue elementUI 表单校验功能之数组多层嵌套
Jun 04 #Javascript
小程序根据手机机型设置自定义底部导航距离
Jun 04 #Javascript
js回文数的4种判断方法示例
Jun 04 #Javascript
Vue对象赋值视图不更新问题及解决方法
Jun 03 #Javascript
在 Vue 应用中使用 Netlify 表单功能的方法详解
Jun 03 #Javascript
You might like
用PHP读取和编写XML DOM的实现代码
2011/02/03 PHP
php中用于检测一个地理IP地址是否可用的代码
2012/02/19 PHP
PHP中把对象数组转换成普通数组的方法
2015/07/10 PHP
PHP多维数组转一维数组的简单实现方法
2015/12/23 PHP
分享十五个最佳jQuery 幻灯插件和教程
2010/03/27 Javascript
jQuery中closest和parents的区别分析
2015/05/07 Javascript
jQuery Ajax和getJSON获取后台普通json数据和层级json数据用法分析
2016/06/08 Javascript
Bootstrap select多选下拉框实现代码
2016/12/23 Javascript
JS常用知识点整理
2017/01/21 Javascript
JS正则表达式判断有效数实例代码
2017/03/13 Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
2018/09/26 Javascript
JavaScript解析及序列化JSON的方法实例分析
2019/01/04 Javascript
原生js实现针对Dom节点的CRUD操作示例
2019/08/26 Javascript
js面向对象之实现淘宝放大镜
2020/01/15 Javascript
使用Webpack 搭建 Vue3 开发环境过程详解
2020/07/28 Javascript
[02:22]《新闻直播间》2017年08月14日
2017/08/15 DOTA
[26:50]2018完美盛典DOTA2表演赛
2018/12/17 DOTA
python在windows命令行下输出彩色文字的方法
2015/03/19 Python
使用Django的模版来配合字符串翻译工作
2015/07/27 Python
Python中利用Scipy包的SIFT方法进行图片识别的实例教程
2016/06/03 Python
Python内置模块logging用法实例分析
2018/02/12 Python
十分钟利用Python制作属于你自己的个性logo
2018/05/07 Python
Python3实现统计单词表中每个字母出现频率的方法示例
2019/01/28 Python
Python后台开发Django的教程详解(启动)
2019/04/08 Python
python实现坦克大战游戏 附详细注释
2020/03/27 Python
Python如何把多个PDF文件合并代码实例
2020/02/13 Python
python分别打包出32位和64位应用程序
2020/02/18 Python
增大python字体的方法步骤
2020/07/05 Python
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
2021/01/20 HTML / CSS
大学旷课检讨书
2014/01/28 职场文书
本科毕业论文答辩稿
2015/06/23 职场文书
运动会加油稿50字
2015/07/21 职场文书
军训决心书范文
2015/09/22 职场文书
python制作图形界面的2048游戏, 基于tkinter
2021/04/06 Python
Javascript中async与await的捕捉错误详解
2022/03/03 Javascript
Windows server 2012搭建FTP服务器
2022/04/29 Servers