澳门威利斯人_威利斯人娱乐「手机版」

来自 威利斯人娱乐 2019-08-10 09:55 的文章
当前位置: 澳门威利斯人 > 威利斯人娱乐 > 正文

js实例方法之生命周期详解,js源码学习二

本文首要给我们介绍的是有关Vue.js实例方法之生命周期的相干内容,分享出来供大家参照他事他说加以考察学习,学习的心上大家下边来一同拜见详细的介绍:

一、$mount()挂载方法

$mount是用来挂载扩大的。假如 Vue 实例在实例化时从没接到 el 选项,则它地处“未挂载”状态,未有关系的 DOM 成分。能够选取 vm.$mount() 手动地挂载一个未挂载的实例。

举个例子大家增添了一个大局组件,通过$mount手动的挂载到DOM上,也就生成了三个Vue实例。

<div id="#app"></div>

增加一个大局组件,何况挂载到DOM上。

//扩张全局的组件
var navBar = Vue.extend({
    template: `<div>{{ title }}</div>`,
    data(){
        return {
            title: 'Vue 扩展的全局组件'
        }
    },
    mounted(){
        console.log('挂载上了')
    }
})

//使用全局扩张的组件,挂载到id为#app的DOM上(会替换#app)
var vm = new navBar().$mount('#app');

//或者
var vm = new navBar({el: "#app"})

譬如未有提供 elementOrSelector 参数,模板将被渲染为文书档案之外的的因素,并且必须利用原生DOM API把它插入文档中。

//在文档之外渲染,并且挂载
var navbar = new navBar().$mount()
document.getElementById('app').appendChild(navbar.$el)

新年一而再写博客~加油!

一、$mount()挂载方法

二、$destroy()销毁方法

功能: 完全灭绝多少个实例。

Vue 实例销毁后调用。调用后,Vue 实例相关的兼具东西都会解绑定,全体的事件监听器会被移除,全体的种子例也会被销毁。

<div id="app">

</div>
<button onclick="destroy()">销毁</button>

在组件中挂载destroyed生命周期钩子

var navBar = Vue.extend({
    template: `<div>
                    <div>{{ title }}</div>
                    <h2>{{ num }}</h2>
                    <button @click = 'add'>add</button>
                </div>`,
    data(){
        return {
            title: 'Vue 全局扩展组件',
            num: 10
        }
    }
    destroyed(){
        console.log('销毁了')
    },
    methods: {
        add(){
            this.num  
        }
    }
})

//使用全局扩张的组件,挂载到id为#app的元素上
var vm = new navBar().$mount('#app');

//销毁
function destroy(){
    //点击按钮,销毁vm实例,控制台会输出‘销毁了’,当再次点击的时候不会输出,而且点击add按钮,数量也不会改变,说明已经销毁了
    vm.$destroy()
}

澳门威尼斯人网站 1

此番来上学一下Vue的生命周期,看看生命周期是怎么回事。

$mount是用来挂载扩充的。要是 Vue 实例在实例化时从没接过 el 选项,则它地处“未挂载”状态,未有涉嫌的 DOM 成分。能够应用vm.$mount()手动地挂载叁个未挂载的实例。

三、$forceUpdate()更新方法

该方法是强迫Vue实例重新渲染。注意:它独自影响实例自己和插入插槽内容的子组件,并非全体子组件。

看代码:

<button onclick="reload()">刷新</button>

//同样的,为了看到是否重新更新了数据,即是否执行了reload方法,我们在实例中添加updated选项
updated(){
    console.log('数据重新渲染了')
}

//三、更新数据方法
function reload(){
    vm.$forceUpdate()
}

点击更新按键,调控台打印出updated钩子中的输出,表明Vue实例重新渲染了。

澳门威尼斯人网站 2

callHook

生命周期主要就是在源码有个别时间点推行这些 callHook 方法来调用 vm.$options 的生命周期钩子方法(假使定义了生命周期钩子方法的话)。
我们来走访 callHook 代码:

export function callHook (vm: Component, hook: string) {
  const handlers = vm.$options[hook] // 获取Vue选项中的生命周期钩子函数
  if (handlers) {
    for (let i = 0, j = handlers.length; i < j; i  ) {
      try {
        handlers[i].call(vm) // 执行生命周期函数
      } catch (e) {
        handleError(e, vm, `${hook} hook`)
      }
    }
  }
  if (vm._hasHookEvent) {
    vm.$emit('hook:'   hook)
  }
}

诸如触发 mounted 钩子的必经之路:

callHook(vm, 'mounted')

比如大家扩大了一个大局组件,通过$mount手动的挂载到DOM上,也就生成了二个Vue实例。

四、$nextTick()数据修改章程

参数:{Function} [callback]

该方法是结构器data中的数据被涂改后触发,也就是updated钩子函数,但仍旧有分别的:它是在updated钩子函数实践完之后试行其里面包车型地铁回调函数。也正是将回调延迟到下一次DOM 更新循环之后实施。在改换数据之后马上选择它,然后等待 DOM 更新。

methods: {
    add(){
        //更改数据
        this.num  
        this.$nextTick(function(){
            console.log('DOM现在更新了')
        })
    }
},
updated(){
    console.log('数据更新成:' this.num)
}

澳门威尼斯人网站 3

经过调整台的打字与印刷结果,能够观察,当数码变动时,updated钩子早于$nextTick中的回调。

生命周期钩子

先上一张图看下Vue的生命周期,大家能够在相应的生命周期中定义一些事变。

澳门威尼斯人网站 4

Vue生命周期

<div id="#app"></div>

beforeCreate & created

先看看那多个艺术调用的岁月。

beforeCreate
在实例初叶化之后,数据观测 (data observer) 和 event/watcher 事件配置在此之前被调用。
created
在实例创立达成后被当下调用。在这一步,实例已产生以下的布署:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。但是,挂载阶段还没初始,$el 属性近些日子不可知。

切切实实代码如下

  // src/core/instance/init.js
  Vue.prototype._init = function (options?: Object) {
    ……
    initLifecycle(vm) // 初始化生命周期
    initEvents(vm) // 初始化事件
    initRender(vm) // 初始化渲染
    callHook(vm, 'beforeCreate')
    initInjections(vm) // 初始化Inject
    initState(vm) // 初始化数据
    initProvide(vm) // 初始化Provide
    callHook(vm, 'created')
    ……
    if (vm.$options.el) {
      vm.$mount(vm.$options.el) // 如果有el属性,将内容挂载到el中去。
    }
  }

扩张叁个大局组件,况且挂载到DOM上。

beforeMount & mounted

beforeMount
在挂载伊始在此以前被调用:相关的 render 函数第二遍被调用。该钩子在劳务器端渲染期间不被调用。
mounted
el 被新创造的 vm.$el 替换,并挂载到实例上去之后调用该钩子。借使 root 实例挂载了四个文书档案内成分,当 mounted 被调用时 vm.$el 也在文书档案内。

贴出代码逻辑

// src/core/instance/lifecycle.js
// 挂载组件的方法
export function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
  vm.$el = el
  if (!vm.$options.render) {
    vm.$options.render = createEmptyVNode
  }
  callHook(vm, 'beforeMount')

  let updateComponent
  updateComponent = () => {
    vm._update(vm._render(), hydrating)
  }

  vm._watcher = new Watcher(vm, updateComponent, noop)
  hydrating = false

  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }
  return vm
}

那么这一个 mountComponent 在哪儿用了呢?正是在Vue的 $mount 方法中应用。

// src/platforms/web/runtime/index.js
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating)
}

最终会在Vue开首化的时候,判定是还是不是有 el,假设有则施行 $mount 方法。

// src/core/instance/init.js
if (vm.$options.el) {
  vm.$mount(vm.$options.el) // 如果有el属性,将内容挂载到el中去。
}

澳门威尼斯人网站,时至明天生命周期逻辑应该是 beforeCreate - created - beforeMount -mounted

//扩张全局的组件
var navBar = Vue.extend({
 template: `<div>{{ title }}</div>`,
 data(){
 return {
  title: 'Vue 扩展的全局组件'
 }
 },
 mounted(){
 console.log('挂载上了')
 }
})

//使用全局扩张的组件,挂载到id为#app的DOM上(会替换#app)
var vm = new navBar().$mount('#app');

//或者
var vm = new navBar({el: "#app"})

beforeUpdate & updated

beforeUpdate
数据更新时调用,发生在设想 DOM 打补丁以前。这里适合在更新从前访谈现存的 DOM,比如手动移除已增添的风浪监听器。
updated
由于数量变动导致的杜撰 DOM 重新渲染和打补丁,在这以往会调用该钩子。

找代码逻辑~ beforeUpdate 和 updated 在多少个地点调用。

Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
    const vm: Component = this
    // 如果是已经挂载的,就触发beforeUpdate方法。
    if (vm._isMounted) {
      callHook(vm, 'beforeUpdate')
    }
    ……
    // updated hook is called by the scheduler to ensure that children are
    // updated in a parent's updated hook.
  }

在执行 _update 方法的时候,固然 DOM 已经挂载了,则调用 beforeUpdate 方法。
在 _update 方法的尾声笔者也注视了调用 updated hook 的职位:updated 钩子由 scheduler 调用来确定保证子组件在一个父组件的 update 钩子中
我们找到 scheduler,发掘有个 callUpdateHooks 方法,该办法遍历了 watcher 数组。

// src/core/observer/scheduler.js
function callUpdatedHooks (queue) {
  let i = queue.length
  while (i--) {
    const watcher = queue[i]
    const vm = watcher.vm
    if (vm._watcher === watcher && vm._isMounted) {
      callHook(vm, 'updated')
    }
  }
}

这个 callUpdatedHooksflushSchedulerQueue 方法中调用。

/**
 * 刷新队列并运行watcher
 */
function flushSchedulerQueue () {
  flushing = true
  let watcher, id
  queue.sort((a, b) => a.id - b.id)

  for (index = 0; index < queue.length; index  ) {
    watcher = queue[index]
    id = watcher.id
    has[id] = null
    watcher.run()
  }

  const activatedQueue = activatedChildren.slice()
  const updatedQueue = queue.slice()

  resetSchedulerState()

  // 调用组件的updated和activated生命周期
  callActivatedHooks(activatedQueue)
  callUpdatedHooks(updatedQueue)
}

继续找下去

export function queueWatcher (watcher: Watcher) {
  const id = watcher.id
  if (has[id] == null) {
    has[id] = true // 此参数用于判断watcher的ID是否存在
    ……
    if (!waiting) {
      waiting = true
      nextTick(flushSchedulerQueue)
    }
  }
}

最终在 watcher.js 找到 update 方法:

  // src/core/observer/watcher.js
  update () {
    // lazy 懒加载
    // sync 组件数据双向改变
    if (this.lazy) {
      this.dirty = true
    } else if (this.sync) {
      this.run()
    } else {
      queueWatcher(this) // 排队watcher
    }
  }

等于是队列试行完 Watcher 数组的 update 方法后调用了 updated 钩子函数。

一旦未有提供 elementOrSelector参数,模板将被渲染为文书档案之外的的因素,并且必须利用原生DOM API把它插入文书档案中。

beforeDestroy & destroyed

beforeDestroy
实例销毁以前调用。在这一步,实例照旧完全可用。该钩子在劳动器端渲染时期不被调用。
destroyed
Vue 实例销毁后调用。调用后,Vue 实例提醒的全数东西都会解绑定,全体的事件监听器会被移除,全数的种子例也会被灭绝。该钩子在服务器端渲染时期不被调用。

看代码~

  // src/core/instance/lifecycle.js
  // 销毁方法
  Vue.prototype.$destroy = function () {
    const vm: Component = this
    if (vm._isBeingDestroyed) {
      // 已经被销毁
      return
    }
    callHook(vm, 'beforeDestroy')
    vm._isBeingDestroyed = true
    // 销毁过程
    // remove self from parent
    const parent = vm.$parent
    if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
      remove(parent.$children, vm)
    }
    // teardown watchers
    if (vm._watcher) {
      vm._watcher.teardown()
    }
    let i = vm._watchers.length
    while (i--) {
      vm._watchers[i].teardown()
    }
    // remove reference from data ob
    // frozen object may not have observer.
    if (vm._data.__ob__) {
      vm._data.__ob__.vmCount--
    }
    // call the last hook...
    vm._isDestroyed = true
    // invoke destroy hooks on current rendered tree
    vm.__patch__(vm._vnode, null)
    // 触发 destroyed 钩子
    callHook(vm, 'destroyed')
    // turn off all instance listeners.
    vm.$off()
    // remove __vue__ reference
    if (vm.$el) {
      vm.$el.__vue__ = null
    }
  }

那是三个销毁 Vue 实例的经过,将各个配置清空和移除。

//在文档之外渲染,并且挂载
var navbar = new navBar().$mount()
document.getElementById('app').appendChild(navbar.$el)

activated & deactivated

activated
keep-alive 组件激活时调用。
deactivated
keep-alive 组件停用时调用。

找到达成代码的地点

// src/core/instance/lifecycle.js
export function activateChildComponent (vm: Component, direct?: boolean) {
  if (direct) {
    vm._directInactive = false
    if (isInInactiveTree(vm)) {
      return
    }
  } else if (vm._directInactive) {
    return
  }
  if (vm._inactive || vm._inactive === null) {
    vm._inactive = false
    for (let i = 0; i < vm.$children.length; i  ) {
      activateChildComponent(vm.$children[i])
    }
    callHook(vm, 'activated')
  }
}

export function deactivateChildComponent (vm: Component, direct?: boolean) {
  if (direct) {
    vm._directInactive = true
    if (isInInactiveTree(vm)) {
      return
    }
  }
  if (!vm._inactive) {
    vm._inactive = true
    for (let i = 0; i < vm.$children.length; i  ) {
      deactivateChildComponent(vm.$children[i])
    }
    callHook(vm, 'deactivated')
  }
}

如上四个办法主要正是修改了 vm._inactive 的值,并且乡下遍历子组件,最后触发钩子方法。

二、$destroy()销毁方法

errorCaptured

当捕获一个来源于子孙组件的错误时被调用。此钩子会接到五个参数:错误对象、发生错误的零件实例以及多个分包错误来源新闻的字符串。此钩子能够回去 false 以阻挠该错误继续升高传播。

这是 2.5 以上版本有的三个钩子,用于管理错误。

// src/core/util/error.js
export function handleError (err: Error, vm: any, info: string) {
  if (vm) {
    let cur = vm
    // 向上冒泡遍历
    while ((cur = cur.$parent)) {
      // 获取钩子函数
      const hooks = cur.$options.errorCaptured
      if (hooks) {
        for (let i = 0; i < hooks.length; i  ) {
          try {
            // 执行 errorCaptured 钩子函数
            const capture = hooks[i].call(cur, err, vm, info) === false
            if (capture) return
          } catch (e) {
            globalHandleError(e, cur, 'errorCaptured hook')
          }
        }
      }
    }
  }
  globalHandleError(err, vm, info)
}

代码很简短,看代码就能够~

作用: 完全绝迹一个实例。

生命周期

除开生命周期钩子外,vue还提供了生命周期方法来直接调用。

本文由澳门威利斯人发布于威利斯人娱乐,转载请注明出处:js实例方法之生命周期详解,js源码学习二

关键词: 澳门威利斯人 Vue.js开发技巧 Vue系列 Vue实验室