zoukankan      html  css  js  c++  java
  • 【js】vue 2.5.1 源码学习 (十) $mount 挂载函数的实现

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

    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                
    27                 list: {
    28                     b:1
    29                 },
    30                 aa:{
    31                     b: [1,2,3]
    32                 }
    33             },
    34             beforeCreate: function(){
    35                 console.log('我钩子函数beforeCreate')
    36                 
    37             },
    38             mounted: function(){
    39                 this.url = 'eeeee'
    40             },
    41             components:{
    42                 humle: componentA
    43             } 
    44         })
    45         vm.test = 2;
    46         // console.log(vm.aa)
    47     </script>
    48 </body>
    49 </html>
  • 相关阅读:
    It is unuseful to regret
    越难熬的时候,越要靠自己
    2019/11/11
    QT Http
    QT 初步认识
    模板
    RTTI(Runtime Type Infomation)
    位域
    C++ 多字节string转UTF-8 string
    C++ 读写csv文件
  • 原文地址:https://www.cnblogs.com/yeujuan/p/11170171.html
Copyright © 2011-2022 走看看