new Vue 发生了什么

左手的ㄟ右手 2021-06-26 16:06 564阅读 0赞

new Vue 发生了什么

1. mergeOptions

合并options

2. initLifecycle(vm)

初始化生命周期

3. initEvents(vm)

初始化事件

4. initRender(vm):初始化render

初始化渲染

5. callHook(vm, 'beforeCreate'):触发 beforeCreate 钩子

触发 beforeCreate 钩子

6. initInjections(vm) // resolve injections before data/props

7. initState(vm):初始化 props、data、computed、methodswatch

  1. export function initState (vm: Component) {
  2. vm._watchers = []
  3. const opts = vm.$options
  4. if (opts.props) initProps(vm, opts.props)
  5. if (opts.methods) initMethods(vm, opts.methods)
  6. if (opts.data) {
  7. initData(vm)
  8. } else {
  9. observe(vm._data = { }, true /* asRootData */)
  10. }
  11. if (opts.computed) initComputed(vm, opts.computed)
  12. if (opts.watch && opts.watch !== nativeWatch) {
  13. initWatch(vm, opts.watch)
  14. }
  15. }

9. initProvide(vm) // resolve provide after data/props

10. callHook(vm, 'created'):触发 created 钩子

触发 created 钩子


init

  1. function Vue(options) {
  2. this._init(options)
  3. }
  4. initMixin(Vue)
  5. function initMixin(Vue) {
  6. Vue.prototype._init = function(options) {
  7. const vm = this
  8. // 一个防止观察自身的标志
  9. vm._isVue = true
  10. vm.$options = options
  11. }
  12. initState(vm)
  13. if (vm.$options.el) {
  14. vm.$mount(vm.$options.el)
  15. }
  16. }
  17. const inBrowser = typeof window !== 'undefined'
  18. Vue.prototype.$mount = function (el, hydrating) {
  19. el = el && inBrowser ? query(el) : undefined
  20. return mountComponent(this, el, hydrating)
  21. }
  22. function mountComponent(vm, el, hydrating) {
  23. vm.$el = el
  24. let updateComponent = () => {
  25. vm._update(vm._render(), hydrating)
  26. }
  27. }
  28. // 缓存之前的$mount
  29. const mount = Vue.prototype.$mount
  30. Vue.prototype.$mount = function(el, hydrating) {
  31. el = el && query(el)
  32. const options = this.$options
  33. if (!options.render) {
  34. let template = options.template
  35. if (template) {
  36. // .
  37. } else {
  38. template = getOuterHTML(el)
  39. }
  40. }
  41. return mount.call(this, el, hydrating)
  42. }
  43. function query (el) {
  44. if (typeof el === 'string') {
  45. const selected = document.querySelector(el)
  46. if (!selected) {
  47. // process.env.NODE_ENV !== 'production' && warn(
  48. // 'Cannot find element: ' + el
  49. // )
  50. return document.createElement('div')
  51. }
  52. return selected
  53. } else {
  54. return el
  55. }
  56. }
  57. function getOuterHTML (el) {
  58. if (el.outerHTML) {
  59. return el.outerHTML
  60. } else {
  61. const container = document.createElement('div')
  62. container.appendChild(el.cloneNode(true))
  63. return container.innerHTML
  64. }
  65. }
  66. function initState(vm) {
  67. const opts = vm.$options
  68. if (opts.data) {
  69. initData(vm)
  70. } else {
  71. observe(vm._data = { }, true)
  72. }
  73. }
  74. function initData(vm) {
  75. let data = vm.$options.data
  76. data = vm._data = typeof data === 'function'
  77. ? getData(data, vm)
  78. : data || { }
  79. const keys = Object.keys(data)
  80. let i = keys.length
  81. while (i--) {
  82. proxy(vm, `_data`, key)
  83. }
  84. observe(data, true /* asRootData */)
  85. }
  86. function getData(data, vm) {
  87. return data.call(vm, vm)
  88. }
  89. const sharedPropertyDefinition = {
  90. enumerable: true,
  91. configurable: true,
  92. get: noop,
  93. set: noop
  94. }
  95. // 等待,无操作
  96. function noop() { }
  97. function proxy(target, sourceKey, key) {
  98. sharedPropertyDefinition.get = function proxyGetter () {
  99. return this[sourceKey][key]
  100. }
  101. sharedPropertyDefinition.set = function proxySetter (val) {
  102. this[sourceKey][key] = val
  103. }
  104. Object.defineProperty(target, key, sharedPropertyDefinition)
  105. }
  106. function observe(value, asRootData) {
  107. }

vdom

js对象描述真实dom

为什么使用vdom

手动操作dom比较麻烦,还要考虑兼容性问题,虽然有jquery等库简化操作,但随着项目增大,复杂度不断提升

为了简化操作dom,可以使用模板引擎,但是模板引擎没有解决跟踪状态变化的问题,于是vdom出现了

  • 开销更小
  • 可以合并更改
  • 可以跟踪上一次的状态,并且用作diff

技巧

将事件的创建和销毁写在一起

Vue 中,可以用$on$once去监听所有的生命周期钩子函数,如监听组件的updated钩子函数可以写成this.$on('hook:updated', () => {})

  1. mounted(){
  2. window.addEventListener('resize', xxx)
  3. // 通过hook监听组件销毁钩子函数,并取消监听事件
  4. this.$once('hook:beforeDestroy', () => {
  5. window.removeEventListener('resize', xxx)
  6. })
  7. }

监听子组件的生命周期

需要监听第三方组件数据的变化,但是组件又没有提供change事件

  1. <child @hook:updated="childUpdated" />

发表评论

表情:
评论列表 (有 0 条评论,564人围观)

还没有评论,来说两句吧...

相关阅读