局部钩子能防全局钩子吗_Vue你真的熟吗?来回答这几个问题试试
前言
這個面向中高級Web前端的面經系列文章,到此便接近尾聲了。是不是還有繼續出,這個要看接下來的時間安排了。
小團體有個朋友說,他準備更新一些android-kotlin從入門到上手寫業務的文章。所以關注我的Web前端的朋友們,不著急,先休息休息,消化消化之前的文章,提前預祝跳槽的朋友,有個好東家~!
本系列文章鏈接如下:
“金三銀四”,讓我們愉快的開始準備Web面經吧:CSS篇
“金三銀四”,讓我們愉快的開始準備Web面經吧:JavaScript-上
中高端Web前端面試題,直擊BAT:JavaScript篇
元宵節,猿宵節,寫代碼之余面經走一波:JavaScript篇
通往中高端Web前端:瀏覽器篇
正文
1. nextTick
在下次dom更新循環結束之后執行延遲回調,可用于獲取更新后的dom狀態
- 新版本中默認是mincrotasks, v-on中會使用macrotasks
- macrotasks任務的實現:
- setImmediate / MessageChannel / setTimeout
2. 生命周期
- _init_
- initLifecycle/Event,往vm上掛載各種屬性
- callHook: beforeCreated: 實例剛創建
- initInjection/initState: 初始化注入和 data 響應性
- created: 創建完成,屬性已經綁定, 但還未生成真實dom
- 進行元素的掛載: $el / vm.$mount()
- 是否有template: 解析成render function*.vue文件: vue-loader會將編譯成render function
- beforeMount: 模板編譯/掛載之前
- 執行render function,生成真實的dom,并替換到dom tree中
- mounted: 組件已掛載
- update:
- 執行diff算法,比對改變是否需要觸發UI更新
- flushScheduleQueuewatcher.before: 觸發beforeUpdate鉤子 - watcher.run(): 執行watcher中的 notify,通知所有依賴項更新UI
- 觸發updated鉤子: 組件已更新
- actived / deactivated(keep-alive): 不銷毀,緩存,組件激活與失活
- destroy:
- beforeDestroy: 銷毀開始
- 銷毀自身且遞歸銷毀子組件以及事件監聽
- remove(): 刪除節點
- watcher.teardown(): 清空依賴
- vm.$off(): 解綁監聽
- destroyed: 完成后觸發鉤子
上面是vue的聲明周期的簡單梳理,接下來我們直接以代碼的形式來完成vue的初始化
new Vue({})// 初始化Vue實例function _init() { // 掛載屬性 initLifeCycle(vm) // 初始化事件系統,鉤子函數等 initEvent(vm) // 編譯slot、vnode initRender(vm) // 觸發鉤子 callHook(vm, 'beforeCreate') // 添加inject功能 initInjection(vm) // 完成數據響應性 props/data/watch/computed/methods initState(vm) // 添加 provide 功能 initProvide(vm) // 觸發鉤子 callHook(vm, 'created') // 掛載節點 if (vm.$options.el) { vm.$mount(vm.$options.el) }}// 掛載節點實現function mountComponent(vm) { // 獲取 render function if (!this.options.render) { // template to render // Vue.compile = compileToFunctions let { render } = compileToFunctions() this.options.render = render } // 觸發鉤子 callHook('beforeMounte') // 初始化觀察者 // render 渲染 vdom, vdom = vm.render() // update: 根據 diff 出的 patchs 掛載成真實的 dom vm._update(vdom) // 觸發鉤子 callHook(vm, 'mounted')}// 更新節點實現funtion queueWatcher(watcher) {nextTick(flushScheduleQueue)}// 清空隊列function flushScheduleQueue() { // 遍歷隊列中所有修改 for(){ // beforeUpdate watcher.before() // 依賴局部更新節點 watcher.update() callHook('updated') }}// 銷毀實例實現Vue.prototype.$destory = function() { // 觸發鉤子 callHook(vm, 'beforeDestory') // 自身及子節點 remove() // 刪除依賴 watcher.teardown() // 刪除監聽 vm.$off() // 觸發鉤子 callHook(vm, 'destoryed')}3. 數據響應(數據劫持)
看完生命周期后,里面的watcher等內容其實是數據響應中的一部分。數據響應的實現由兩部分構成: 觀察者( watcher ) 和 依賴收集器( Dep ),其核心是 defineProperty這個方法,它可以 重寫屬性的 get 與 set 方法,從而完成監聽數據的改變。
- Observe (觀察者)觀察 props 與 state
- 遍歷 props 與 state,對每個屬性創建獨立的監聽器( watcher )
- 使用 defineProperty 重寫每個屬性的 get/set(defineReactive)
- get: 收集依賴
- Dep.depend()watcher.addDep()
- set: 派發更新
- Dep.notify()
- watcher.update()
- queenWatcher()
- nextTick
- flushScheduleQueue
- watcher.run()
- updateComponent()
大家可以先看下面的數據相應的代碼實現后,理解后就比較容易看懂上面的簡單脈絡了。
let data = {a: 1}// 數據響應性observe(data)// 初始化觀察者new Watcher(data, 'name', updateComponent)data.a = 2// 簡單表示用于數據更新后的操作function updateComponent() { vm._update() // patchs}// 監視對象function observe(obj) { // 遍歷對象,使用 get/set 重新定義對象的每個屬性值 Object.keys(obj).map(key => { defineReactive(obj, key, obj[key]) })}function defineReactive(obj, k, v) { // 遞歸子屬性 if (type(v) == 'object') observe(v) // 新建依賴收集器 let dep = new Dep() // 定義get/set Object.defineProperty(obj, k, { enumerable: true, configurable: true, get: function reactiveGetter() { // 當有獲取該屬性時,證明依賴于該對象,因此被添加進收集器中 if (Dep.target) { dep.addSub(Dep.target) } return v }, // 重新設置值時,觸發收集器的通知機制 set: function reactiveSetter(nV) { v = nV dep.nofify() }, })}// 依賴收集器class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } notify() { this.subs.map(sub => { sub.update() }) }}Dep.target = null// 觀察者class Watcher { constructor(obj, key, cb) { Dep.target = this this.cb = cb this.obj = obj this.key = key this.value = obj[key] Dep.target = null } addDep(Dep) { Dep.addSub(this) } update() { this.value = this.obj[this.key] this.cb(this.value) } before() { callHook('beforeUpdate') }}尾聲
汗--!沒想到才寫一半就這么多內容了,為了閱讀體驗,決定分上下倆部分發。后續文章可以關注我,翻看歷史文章~
總結
以上是生活随笔為你收集整理的局部钩子能防全局钩子吗_Vue你真的熟吗?来回答这几个问题试试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 查看redis版本_redis详细介绍
- 下一篇: 用ram实现寄存器堆_Verilog如何