• VueJs 源码解析 (四) initRender.Js


    vueJs 源码解析 (四) initRender.Js

    在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm、compiler、watcher 这三要素,那么今天我们就从这三要素逐步了解清楚。这部分主要是来解读 render.js。
    

    一、initRender 初始化 render 函数

    核心代码一:

      vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false);
      // normalization is always applied for the public version, used in
      // user-written render functions.
      vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true);
    

    解析:

     这里我们先做个一个大胆的猜测:createElement() 方法的最后一个参数 是来判断是 开发者是否在调用vue的时候 使用了 render 函数,从而给了不同的 参数,去render。
    
    后面,我们再来一一验证,前面的这些猜测.
    

    找到 createElement() 方法

    import { createElement } from '../vdom/create-element';
    

    核心代码:

    export function createElement(context, tag, data, children, normalizationType, alwaysNormalize) {
      if (Array.isArray(data) || isPrimitive(data)) {
        normalizationType = children;
        children = data;
        data = undefined;
      }
      if (isTrue(alwaysNormalize)) {
        normalizationType = ALWAYS_NORMALIZE;
      }
      return _createElement(context, tag, data, children, normalizationType);
    }
    
    其中 createElement(context, tag, data, children, normalizationType, alwaysNormalize)  
    
    context    // 上下文
    tag        // 标签
    data       // 数据对象   (hook, on , pendingInsert)
    children   // 子节点 (位置)
    

    核心代码二:

    
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production') {
        defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
          !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm);
        }, true);
        defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
          !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm);
        }, true);
      } else {
        defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true);
        defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true);
      }
    
    
    其中 常见的 一个 vue 的方法是 defineReactive()
    
    在 observe 文件夹下 找到 index.js 的 defineReactive() 
    

    核心代码:

    
    export function defineReactive(obj, key, val, customSetter, shallow) {
      const dep = new Dep();
    
      const property = Object.getOwnPropertyDescriptor(obj, key);
      if (property && property.configurable === false) {
        return;
      }
    
      // cater for pre-defined getter/setters
      const getter = property && property.get;
      const setter = property && property.set;
      if ((!getter || setter) && arguments.length === 2) {
        val = obj[key];
      }
    
      let childOb = !shallow && observe(val);
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter() {
          const value = getter ? getter.call(obj) : val;
          if (Dep.target) {
            dep.depend();
            if (childOb) {
              childOb.dep.depend();
              if (Array.isArray(value)) {
                dependArray(value);
              }
            }
          }
          return value;
        },
        set: function reactiveSetter(newVal) {
          const value = getter ? getter.call(obj) : val;
          /* eslint-disable no-self-compare */
          if (newVal === value || newVal !== newVal && value !== value) {
            return;
          }
          /* eslint-enable no-self-compare */
          if (process.env.NODE_ENV !== 'production' && customSetter) {
            customSetter();
          }
          if (setter) {
            setter.call(obj, newVal);
          } else {
            val = newVal;
          }
          childOb = !shallow && observe(newVal);
          dep.notify();
        }
      });
    }
    
    
    这个核心的代码,就是 Vue 的 实现数据监听以及 单向数据流的 主要方式。
    

    二、initInjections 初始化

    核心代码 :

    
    export function initInjections(vm) {
      const result = resolveInject(vm.$options.inject, vm);
      if (result) {
        toggleObserving(false);
        Object.keys(result).forEach(key => {
          /* istanbul ignore else */
          if (process.env.NODE_ENV !== 'production') {
            defineReactive(vm, key, result[key], () => {
              warn(`Avoid mutating an injected value directly since the changes will be ` + `overwritten whenever the provided component re-renders. ` + `injection being mutated: "${key}"`, vm);
            });
          } else {
            defineReactive(vm, key, result[key]);
          }
        });
        toggleObserving(true);
      }
    }
    
    

    三、initState 初始化

    核心代码 :

    
    export function initState(vm) {
      vm._watchers = [];
      const opts = vm.$options;
      if (opts.props) initProps(vm, opts.props);
      if (opts.methods) initMethods(vm, opts.methods);
      if (opts.data) {
        initData(vm);
      } else {
        observe(vm._data = {}, true /* asRootData */);
      }
      if (opts.computed) initComputed(vm, opts.computed);
      if (opts.watch && opts.watch !== nativeWatch) {
        initWatch(vm, opts.watch);
      }
    }
    
    判断传入的 options 对象中是否有 props methods data computed watch 等属性
    
    如果有的话, 会分别去 进行实例化操作。
    

    initProps(vm, opts.props)

    
    defineReactive(props, key, value)
    
    

    initMethods(vm, opts.methods)

    
      for (const key in methods) {
        ...
        vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
      }
    
    

    initData(vm)

    
    function initData(vm) {
      ...
      // observe data
      observe(data, true /* asRootData */);
    }
    
    

    initComputed(vm, opts.computed)

    
      const watchers = vm._computedWatchers = Object.create(null);
      // computed properties are just getters during SSR
      const isSSR = isServerRendering();
    
      ...
    
        if (!isSSR) {
          // create internal watcher for the computed property.
          watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions);
        }
    
    

    initWatch(vm, opts.watch)

    
    createWatcher(vm, key, handler)
    
    function createWatcher(vm, expOrFn, handler, options) {
      if (isPlainObject(handler)) {
        options = handler;
        handler = handler.handler;
      }
      if (typeof handler === 'string') {
        handler = vm[handler];
      }
      return vm.$watch(expOrFn, handler, options);
    }
    
    看到了 这里是不是 突然有种 豁然开朗的感觉, 各种属性方法的实例化,让我们比较清楚的知道了在
    
    props methods data computed watch 等属性或者方法中 的内部变化。
    

    好了,今天先写到这里,回家继续~

  • 相关阅读:
    centos 6.5安装erlang和RabbitMQ
    vert.x学习(八),用JDBCClient配合c3p0操作数据库
    vert.x学习(七),使用表单获取用户提交的数据
    vert.x学习(六),动态模板与静态文件的结合
    vert.x学习(五),用StaticHandler来处理静态文件
    函数-生成器、迭代器
    函数装饰器
    函数参数、作用域、高阶函数、递归函数、高阶函数
    深浅拷贝、集合set、函数、日志
    第一部分day5 文件操作
  • 原文地址:https://www.cnblogs.com/erbingbing/p/8876932.html
Copyright © 2020-2023  润新知