vue源码学习笔记(持续更新)

201 阅读4分钟
注意:很多地方没有表达清晰,如有更好说明解答者欢迎留言更正。

1. 规范

1.1 props规范(传参)

  • 写法:
props: ["someData"] 
props: {
  someData1: Number,
  someData2: {
    type: String,
    default: ''
  }
}
  • 规范之后(最后在代码里运行的样子): 全部都会自动添加一个type (数组形式的写法type默认null)。
props: {
  someData1: {
    type: Number
  },
  someData2: {
    type: String,
    default: ''
  }
}

1.2 inject规范(依赖)

  • 写法
inject: ['data1', 'data2']

inject: {
  data1,
  d2: 'data2',
  data3: { someProperty: 'someValue' }
}
  • 规范之后(最后在代码里运行的样子): 全部都会自动添加一个from (数组形式的写法from默认自己)。
inject: {
  'data1': { from: 'data1' },
  'd2': { from: 'data2' },
  'data3': { from: 'data3', someProperty: 'someValue' }
}

1.3 directives规范(自定义指令)

  • 写法
directives: {
    test1: {
      bind: function () {
        console.log('v-test1')
      }
    },
    test2: function () {
      console.log('v-test2')
    }
  }
  • 规范之后(最后在代码里运行的样子): 全部都会自动添加一个bind、update事件;
directives: {
    test1: {
      bind: function () {
        console.log('v-test1')
      },
      update: function () {
        console.log('v-test1')
      }
    },
    test2: {
      bind: function () {
        console.log('v-test2')
      },
      update: function () {
        console.log('v-test2')
      }
    }
  }

2. 合并 (重点,可以知道组件的合并规则方便处理数据)

2.1 data 的合并

data合并之后最终返回的是一个函数对象,合并规则是按照key值将子组件的data与父组件的data进行合并,父组件存在,则子组件覆盖父组件,没有则插入没有的key(这里的key是对象的键,按照递归把深层的数据按照此规则进行合并)。

2.2 data 合并的问题?

2.2.1 为什么最终 strats.data(合并data返回的是一个函数) 会被处理成一个函数?

  • 这是因为通过返回函数对象可以保证每个组件实例都有唯一的数据副本。

2.2.2 为什么不在合并阶段就把数据合并好,而是要等到初始化的时候再合并数据(也就是问题一的进一步解释)?

  • 初始化顺序:即在vue初始化到时候props与inject都是先于data初始化的。这样在执行到data合并函数的时候可以使用props与inject传入的数据。

  • data动态化:初始化之后他也可以是自己当前处理参数之后的数据,也可以是父组件在处理数据之后的data。

2.3 data和props的结构赋值

传统写法:

data () {
  return {
    childData: this.parentData
  }
},
props: ['parentData'],

解构写法:

data (vm) {
  return {
    childData: vm.parentData
  }
}
// 或者使用更简单的解构赋值
data ({ parentData }) {
  return {
    childData: parentData
  }
}

2.3 生命周期合并(mergeHook)

生命周期在合并之后返回的是一个数组(生命周期也可以直接携程一个数组)。实现原理就是通过concat方法合并成一个数组,子组件的在父组件之后执行(包括同名的生命周期)。

//合并之后的代码
[
  created: function () {
    console.log('parentVal') //父组件
  },
  created: function () {
    console.log('childVal') // 子组件
  }
]

2.4 资源(assets)合并策略(原型链的方式传播)

资源包括:directives、filters 以及 components; 父子选项将以原型链的形式被处理,合并之后返回一个对象,如果存在相同的key值将不会像父级原型链查询,入子组件没有则通过原型链像父组件查找( __proto__ )。

2.5 watch 合并策略

被合并处理后的 watch 选项下的每个键值,有可能是一个数组,也有可能是一个函数。如果是一个数组,则按照concat方法合并之后的顺序执行(即同名字监听,先执行父组件的watch内同名的方法在执行子组件内的watch与父组件同名的方法)。

//合并之后的代码
watch: {
  test: [
    function () {
      console.log('extend: test change') //父组件
    },
    function () {
      console.log('instance: test change') // 子组件
    }
  ]
}

2.6 选项 props、methods、inject、computed 的合并策略

合并之后返回的都是对象,如存在相同则会覆盖,没有则直接合并成一个大的对象。使用extend方法来实现合并。

2.7 总结

通过查看合并策略源码我们了解了一下几点:

  • 生命周期类型判断是方法所以在写生命周期的时候要是方法。
  • data类型判断是方法返回必须是对象,所以在写data的时候必须是一个方法返回一个对象。
  • 除了生命周期以及data都是返回的对象。
  • 合并相同名字按顺序执行的是hook与watch
  • 比较特殊的合并策略是assets(资源),采用将父级作为子级的原型的形式来合并资源的。
  • 其他剩下的基本都是合并如存在相同的名字就采用子覆盖父的形式。