整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Vue3 中動態監聽HTML元素大小變化的實踐與探索

          在Web開發中,尤其是在響應式布局設計時,我們常常需要根據HTML元素的尺寸變化來調整頁面布局或內容展示。Vue3 提供了強大的響應式機制和Composition API,使得我們可以更靈活地監聽并處理DOM元素尺寸的變化。本文將詳細介紹如何在Vue3項目中實現這一功能。

          一、傳統方法:ResizeObserver

          ResizeObserver 是瀏覽器提供的一個API,用于觀察目標元素尺寸變化事件,并在其尺寸發生變化時觸發回調函數。首先引入 ResizeObserver 并創建一個觀察者實例:

          import { onMounted, onUnmounted } from 'vue';
          
          export default {
            setup() {
              const targetElement = ref(null); // 存儲需要監聽的DOM元素引用
          
              let resizeObserver;
              
              // 當組件掛載時創建ResizeObserver實例并開始監聽
              onMounted(() => {
                resizeObserver = new ResizeObserver((entries) => {
                  entries.forEach((entry) => {
                    console.log('Element size changed:', entry.contentRect.width, entry.contentRect.height);
                    // 在這里執行相應的邏輯處理
                  });
                });
          
                if (targetElement.value) {
                  resizeObserver.observe(targetElement.value);
                }
              });
          
              // 組件卸載時停止監聽
              onUnmounted(() => {
                if (resizeObserver && targetElement.value) {
                  resizeObserver.unobserve(targetElement.value);
                }
              });
          
              return {
                targetElement,
              };
            },
          };
          

          在模板中,綁定目標元素到 targetElement ref:

          <div ref="targetElement">需要監聽大小變化的元素</div>

          二、結合Vue3的響應式優勢

          為了更好地與Vue3的數據響應性相結合,我們可以利用Ref或者Computed屬性來存儲和更新元素尺寸信息:

          import { ref, computed, onMounted, onUnmounted } from 'vue';
          
          export default {
            setup() {
              const targetElement = ref(null);
              const elementSize = ref({ width: 0, height: 0 });
          
              let resizeObserver;
          
              onMounted(() => {
                resizeObserver = new ResizeObserver((entries) => {
                  const entry = entries[0];
                  elementSize.value = {
                    width: entry.contentRect.width,
                    height: entry.contentRect.height,
                  };
                });
          
                if (targetElement.value) {
                  resizeObserver.observe(targetElement.value);
                }
              });
          
              onUnmounted(() => {
                if (resizeObserver && targetElement.value) {
                  resizeObserver.unobserve(targetElement.value);
                }
              });
          
              // 創建一個計算屬性以返回最新尺寸信息
              const reactiveElementSize = computed(() => elementSize.value);
          
              return {
                targetElement,
                reactiveElementSize,
              };
            },
          };
          

          現在你可以在其他組件內部使用 reactiveElementSize 計算屬性來獲取實時的元素尺寸數據,并據此做出相應布局調整。

          在上述代碼示例中,elementSize 用于存儲元素的尺寸信息(寬度和高度),我們使用了 ref 來定義它。然而,如果你希望 elementSize 對象本身具有響應性,即當對象內部的屬性發生變化時也能觸發視圖更新,那么使用 reactive 可能會更合適。

          import { ref, reactive, onMounted, onUnmounted } from 'vue';
          
          export default {
            setup() {
              const targetElement = ref(null);
              // 使用reactive創建響應式對象
              const elementSize = reactive({ width: 0, height: 0 });
          
              let resizeObserver;
          
              onMounted(() => {
                resizeObserver = new ResizeObserver((entries) => {
                  const entry = entries[0];
                  // 直接修改響應式對象內部屬性
                  elementSize.width = entry.contentRect.width;
                  elementSize.height = entry.contentRect.height;
                });
          
                if (targetElement.value) {
                  resizeObserver.observe(targetElement.value);
                }
              });
          
              onUnmounted(() => {
                if (resizeObserver && targetElement.value) {
                  resizeObserver.unobserve(targetElement.value);
                }
              });
          
              return {
                targetElement,
                elementSize,
              };
            },
          };

          在這種情況下,因為 elementSize 是一個由 reactive 創建的響應式對象,所以在其內部屬性 width 和 height 發生變化時,依賴這些值的組件也會自動重新渲染,無需額外的操作。

          需要注意的是,在實際應用中,如果只是簡單的尺寸數值,使用 ref 足以滿足需求,因為 ref 的 .value 屬性本身就是響應式的。而 reactive 更適用于需要整個對象結構都具有響應性的場景。

          三、總結

          Vue3 的 Composition API 結合瀏覽器原生的 ResizeObserver 可以為我們在監聽HTML元素尺寸變化上提供強大而靈活的支持。通過這樣的方式,開發者可以輕松應對各種復雜的響應式布局需求,為用戶帶來更好的交互體驗。同時,借助Vue3的數據響應性和自動更新機制,能夠在元素尺寸變化時及時刷新視圖,保持UI狀態與實際DOM的一致性。

          Vue 3應用開發過程中,實時監測Cookie變化對于實現用戶會話管理、個性化體驗等功能至關重要。本文將深入探討如何在Vue 3框架下監聽Cookie變化,并提出優化方案,以提升應用性能和用戶體驗。我們將使用Vue 3的Composition API和第三方庫js-cookie來實現這一目標。

          技術棧簡介

          • Vue 3: 最新一代的Vue框架,帶來更強大的Composition API和更好的性能。
          • js-cookie: 一個輕量級的JavaScript庫,用于操作Cookie,簡化了讀取、寫入和刪除Cookie的過程。

          實現基礎監聽

          安裝依賴

          首先,確保你的Vue 3項目已準備好,并通過npm或yarn安裝js-cookie:

          npm install js-cookie
          # 或
          yarn add js-cookie

          引入依賴

          在Vue組件中引入必要的工具:

          import { ref, onMounted, onUnmounted } from 'vue';
          import Cookies from 'js-cookie';

          創建響應式變量與監聽邏輯

          使用Vue 3的Composition API來創建響應式變量,并通過輪詢檢查Cookie變化:

          export default {
            setup() {
              const cookieValue = ref(Cookies.get('your_cookie_key'));
          
              const checkCookie = () => {
                const newValue = Cookies.get('your_cookie_key');
                if (newValue !== cookieValue.value) {
                  cookieValue.value = newValue;
                  console.log('Cookie value changed:', newValue);
                  // 這里可以添加更多響應變化的邏輯
                }
              };
          
              onMounted(() => {
                const intervalId = setInterval(checkCookie, 1000);
                // 記錄定時器ID以便在組件卸載時清除
                onUnmounted(() => clearInterval(intervalId));
              });
          
              return { cookieValue };
            },
          };

          優化方案

          1. 使用MutationObserver優化DOM監聽

          對于由JavaScript動態修改的Cookie(例如通過document.cookie),可以考慮使用MutationObserver監聽<html>標簽的__vue__屬性變化,但請注意,此方法并非所有情況下都能捕捉到Cookie變化,且有一定的兼容性問題。

          2. WebSocket或Server-Sent Events (SSE)

          對于實時性要求高的場景,可以考慮使用WebSocket或Server-Sent Events (SSE)技術,由服務器主動推送Cookie變化給客戶端,從而避免頻繁的輪詢請求,顯著降低資源消耗。

          3. Debounce或Throttle策略

          如果輪詢不可避免,可以引入防抖(debounce)或節流(throttle)策略減少不必要的檢查次數。例如,僅當上一次檢查過去一段時間或用戶停止操作后才再次檢查Cookie,這有助于減少不必要的CPU和網絡負載。

          4. 使用Proxy實現響應式Cookie

          雖然直接將Cookie包裝成響應式對象較為復雜,但理論上可以通過Proxy對象監控Cookie的讀寫操作,實現近乎實時的響應。不過,這種方法實現復雜,且需謹慎處理以避免性能瓶頸。

          示例:結合Debounce的優化方案

          引入lodash的debounce函數來優化輪詢邏輯:

          import { debounce } from 'lodash';
          
          // ...
          
          const debouncedCheckCookie = debounce(checkCookie, 1000);
          
          onMounted(() => {
            const intervalId = setInterval(debouncedCheckCookie, 1000);
            onUnmounted(() => {
              clearInterval(intervalId);
              // 取消debounce的掛起調用
              debouncedCheckCookie.cancel();
            });
          });
          
          // ...

          結論

          監聽Cookie變化是實現動態UI和增強用戶體驗的關鍵環節。雖然輪詢是最直接的解決方案,但通過引入優化策略,如使用WebSocket、MutationObserver、防抖或節流,我們可以更高效、更優雅地處理Cookie變化,從而在Vue 3應用中實現高性能和低延遲的交互體驗。希望本文的探討和示例能為你的項目開發提供有益的參考。

          . Vue 的基本原理

          當 一 個 Vue 實 例 創 建 時 , Vue 會 遍 歷 data 中 的 屬 性 , 用 Object.defineProperty ( vue3.0 使 用 proxy) 將 它 們 轉 為 getter/setter,并且在內部追蹤相關依賴,在屬性被訪問和修改時 通知變化。 每個組件實例都有相應的 watcher 程序實例,它會在組 件渲染的過程中把屬性記錄為依賴,之后當依賴項的 setter 被調用 時,會通知 watcher 重新計算,從而使它關聯的組件得以更新。

          2. 雙向數據綁定的原理

          Vue.js 是采用數據劫持結合發布者-訂閱者模式的方式,通過 Object.defineProperty()來劫持各個屬性的 setter,getter,在數 據變動時發布消息給訂閱者,觸發相應的監聽回調。主要分為以下幾 個步驟:

          1.需要 observe 的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter 和 getter 這樣的話,給這個對象的某個值賦值,就會 觸發 setter,那么就能監聽到了數據變化

          2.compile 解析模板指令,將模板中的變量替換成數據,然后初始化 渲染頁面視圖,并將每個指令對應的節點綁定更新函數,添加監聽數 據的訂閱者,一旦數據有變動,收到通知,更新視圖

          3.Watcher 訂閱者是 Observer 和 Compile 之間通信的橋梁,主要做 的事情是: ①在自身實例化時往屬性訂閱器(dep)里面添加自己 ② 自身必須有一個 update()方法 ③待屬性變動 dep.notice()通知時,能調用自身的 update()方法,并觸發 Compile 中綁定的回調,則成功 成身退。

          4.MVVM 作為數據綁定的入口,整合 Observer、Compile 和 Watcher 三者,通過 Observer 來監聽自己的 model 數據變化,通過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的通信橋梁,達到數據變化 -> 視圖更新;視圖交互變化(input)-> 數據 model 變更的雙向綁定效果。

          3. MVVM、MVC、MVP 的區別

          MVC、MVP 和 MVVM 是三種常見的軟件架構設計模式,主要通過分離 關注點的方式來組織代碼結構,優化開發效率。

          在開發單頁面應用時,往往一個路由頁面對應了一個腳本文件,所有 的頁面邏輯都在一個腳本文件里。頁面的渲染、數據的獲取,對用戶來說 事件的響應所有的應用邏輯都混合在一起,這樣在開發簡單項目時,可能看不出什么問題,如果項目變得復雜,那么整個文件就會變得冗 長、混亂,這樣對項目開發和后期的項目維護是非常不利的。

          (1)MVC

          MVC 通過分離 Model、View 和 Controller 的方式來組織代碼結構。其中 View 負責頁面的顯示邏輯,Model 負責存儲頁面的業務數據,以及對相應數據的操作。并且 View 和 Model 應用了觀察者模式,當 Model 層發生改變的時候它會通知有關 View 層更新頁面。Controller 層是 View 層和 Model 層的紐帶,它主要負責用戶與應 用的響應操作,當用戶與頁面產生交互的時候,Controller 中的事 觸發器就開始工作了,通過調用 Model 層,來完成對 Model 的修 改,然后 Model 層再去通知 View 層更新。

          (2)MVVM

          MVVM 分為 Model、View、ViewModel:

          Model 代表數據模型,數據和業務邏輯都在 Model 層中定義;

          View 代表 UI 視圖,負責數據的展示;

          ViewModel 負責監聽 Model 中數據的改變并且控制視圖的更新,處理 用戶交互操作;

          Model 和 View 并無直接關聯,而是通過 ViewModel 來進行聯系的,Model 和 ViewModel 之間有著雙向數據綁定的聯系。因此當 Model 中 的數據改變時會觸發 View 層的刷新,View 中由于用戶交互操作而改 變的數據也會在 Model 中同步。

          這種模式實現了 Model 和 View 的數據自動同步,因此開發者只需要 專注于數據的維護操作即可,而不需要自己操作 DOM。

          (3)MVP

          MVP 模式與 MVC 唯一不同的在于 Presenter 和 Controller。在 MVC 模式中使用觀察者模式,來實現當 Model 層數據發生變化的時 候,通知 View 層的更新。這樣 View 層和 Model 層耦合在一起,當項目邏輯變得復雜的時候,可能會造成代碼的混亂,并且可能會對 代碼的復用性造成一些問題。MVP 的模式通過使用 Presenter 來實 現對 View 層和 Model 層的解耦。MVC 中的 Controller 只知道 Model 的接口,因此它沒有辦法控制 View 層的更新,MVP 模式中,View 層的接口暴露給了 Presenter 因此可以在 Presenter 中將 Model 的變化和 View 的變化綁定在一起,以此來實現 View 和 Model 的同步更新。這樣就實現了對 View 和 Model 的解耦,Presenter 還包含了其他的響應邏輯。

          4. slot 是什么?有什么作用?原理是什么?

          slot 又名插槽,是 Vue 的內容分發機制,組件內部的模板引擎使用 slot 元素作為承載分發內容的出口。插槽 slot 是子組件的一個模板 標簽元素,而這一個標簽元素是否顯示,以及怎么顯示是由父組件決 定的。slot 又分三類,默認插槽,具名插槽和作用域插槽。

          默認插槽:又名匿名插槽,當 slot 沒有指定 name 屬性值的時候一個 默認顯示插槽,一個組件內只有有一個匿名插槽。具名插槽:帶有具體名字的插槽,也就是帶有 name 屬性的 slot,一 個組件可以出現多個具名插槽。

          作用域插槽:默認插槽、具名插槽的一個變體,可以是匿名插槽,也 可以是具名插槽,該插槽的不同點是在子組件渲染作用域插槽時,可 以將子組件內部的數據傳遞給父組件,讓父組件根據子組件的傳遞過 來的數據決定如何渲染該插槽。

          實現原理:當子組件 vm 實例化時,獲取到父組件傳入的 slot 標簽的 內容,存放在 vm.$slot 中,默認插槽為 vm.$slot.default,具名插 槽為 vm.$slot.xxx,xxx 為插槽名,當組件執行渲染函數時候,遇 到 slot 標簽,使用$slot 中的內容進行替換,此時可以為插槽傳遞 數據,若存在數據,則可稱該插槽為作用域插槽。

          5. $nextTick 原理及作用

          Vue 的 nextTick 其本質是對 JavaScript 執行原理 EventLoop 的 一種應用。

          nextTick 的 核 心 是 利 用 了 如 Promise 、 MutationObserver 、setImmediate、setTimeout 的原生 JavaScript 方法來模擬對應的 微/宏任務的實現,本質是為了利用 JavaScript 的這些異步回調任 務隊列來實現 Vue 框架中自己的異步回調隊列。

          nextTick 不僅是 Vue 內部的異步隊列的調用方法,同時也允許開發 者在實際項目中使用這個方法來滿足實際應用中對 DOM 更新數據時 機的后續邏輯處理

          nextTick 是典型的將底層 JavaScript 執行原理應用到具體案例中 的示例,引入異步更新隊列機制的原因∶如果是同步更新,則多次對一個或多個屬性賦值,會頻繁觸發 UI/DOM 的渲染,可以減少一些無用渲染

          同時由于 VirtualDOM 的引入,每一次狀態發生變化后,狀態變化的 信號會發送給組件,組件內部使用 VirtualDOM 進行計算得出需要更 新的具體的 DOM 節點,然后對 DOM 進行更新操作,每次更新狀態后 的渲染過程需要更多的計算,而這種無用功也將浪費更多的性能,所 以異步渲染變得更加至關重要

          Vue 采用了數據驅動視圖的思想,但是在一些情況下,仍然需要操作 DOM。有時候,可能遇到這樣的情況,DOM1 的數據發生了變化,而 DOM2 需要從 DOM1 中獲取數據,那這時就會發現 DOM2 的視圖并沒有更新,這時就需要用到了 nextTick 了。

          由于 Vue 的 DOM 操作是異步的,所以,在上面的情況中,就要將 DOM2 獲取數據的操作寫在$nextTick 中。

          所以,在以下情況下,會用到 nextTick:

          在數據變化后執行的某個操作,而這個操作需要使用隨數據變化而變 化的 DOM 結構的時候,這個操作就需要方法在 nextTick()的回調函 數中。

          在 vue 生命周期中,如果在 created()鉤子進行 DOM 操作,也一定要 放在 nextTick()的回調函數中。

          因為在 created()鉤子函數中,頁面的 DOM 還未渲染,這時候也沒辦 法操作 DOM,所以,此時如果想要操作 DOM,必須將操作的代碼放在 nextTick()的回調函數中。

          6. Vue 單頁應用與多頁應用的區別

          概念:

          SPA 單頁面應用(SinglePage Web Application),指只有一個主頁 面的應用,一開始只需要加載一次 js、css 等相關資源。所有內容都 包含在主頁面,對每一個功能模塊組件化。單頁應用跳轉,就是切換 相關組件,僅僅刷新局部資源。

          MPA 多頁面應用 (MultiPage Application),指有多個獨立頁面的 應用,每個頁面必須重復加載 js、css 等相關資源。多頁應用跳轉,需要整頁資源刷新。

          區別:

          7. Vue 中封裝的數組方法有哪些,其如何實現頁面更新

          在 Vue 中,對響應式處理利用的是 Object.defineProperty 對數據進 行攔截,而這個方法并不能監聽到數組內部變化,數組長度變化,數 組的截取變化等,所以需要對這些操作進行 hack,讓 Vue 能監聽到 其中的變化。

          那 Vue 是如何實現讓這些數組方法實現元素的實時更新的呢,下面是 Vue 中對這些方法的封裝:

          簡單來說就是,重寫了數組中的那些原生方法,首先獲取到這個數組 的__ob__,也就是它的 Observer 對象,如果有新的值,就調用 observeArray 繼續對新的值觀察變化(也就是通過 target__proto__ == arrayMethods 來改變了數組實例的型),然后手動調用 notify,通知渲染 watcher,執行 update。

          8. Vue data 中某一個屬性的值發生改變后,視圖會立即同步執 行重新渲染嗎?

          不會立即同步執行重新渲染。Vue 實現響應式并不是數據發生變化之 后 DOM 立即變化,而是按一定的策略進行 DOM 的更新。Vue 在更新 DOM 時是異步執行的。只要偵聽到數據變化, Vue 將開啟一個隊列,并緩沖在同一事件循環中發生的所有數據變更。

          如果同一個 watcher 被多次觸發,只會被推入到隊列中一次。這種在 緩沖時去除重復數據對于避免不必要的計算和 DOM 操作是非常重要 的。然后,在下一個的事件循環 tick 中,Vue 刷新隊列并執行實際(已去重的)工作。

          9. 簡述 mixin、extends 的覆蓋邏輯

          (1)mixin 和 extends

          mixin 和 extends 均 是 用 于 合 并 、 拓 展 組 件 的 , 兩 者 均 通 過 mergeOptions 方法實現合并。

          mixins 接收一個混入對象的數組,其中混入對象可以像正常的實例 對象一樣包含實例選項,這些選項會被合并到最終的選項中。Mixin 鉤子按照傳入順序依次調用,并在調用組件自身的鉤子之前被調用。

          extends 主要是為了便于擴展單文件組件,接收一個對象或構造函數。

          (2)mergeOptions 的執行過程

          規 范 化 選 項 ( normalizeProps 、 normalizelnject 、normalizeDirectives)

          對未合并的選項,進行判斷

          10. 子組件可以直接改變父組件的數據嗎?

          子組件不可以直接改變父組件的數據。這樣做主要是為了維護父子組 件的單向數據流。每次父級組件發生更新時,子組件中所有的 prop 都將會刷新為最新的值。如果這樣做了,Vue 會在瀏覽器的控制臺中 發出警告。Vue 提倡單向數據流,即父級 props 的更新會流向子組件,但是反 過來則不行。這是為了防止意外的改變父組件狀態,使得應用的數據 流變得難以理解,導致數據流混亂。如果破壞了單向數據流,當應用 復雜時,debug 的成本會非常高。

          只能通過 $emit 派發一個自定義事件,父組件接收到后,由父組件 修改。

          11. 對 React 和 Vue 的理解,它們的異同

          相似之處:

          都將注意力集中保持在核心庫,而將其他功能如路由和全局狀態管理 交給相關的庫;

          都有自己的構建工具,能讓你得到一個根據最佳實踐設置的項目模板;都使用了 Virtual DOM(虛擬 DOM)提高重繪性能;

          都有 props 的概念,允許組件間的數據傳遞;

          都鼓勵組件化應用,將應用分拆成一個個功能明確的模塊,提高復用 性。

          不同之處 :

          1)數據流

          Vue 默認支持數據雙向綁定,而 React 一直提倡單向數據流

          2)虛擬 DOM

          Vue2.x 開始引入"Virtual DOM",消除了和 React 在這方面的差異,但是在具體的細節還是有各自的特點。Vue 宣稱可以更快地計算出 Virtual DOM 的差異,這是由于它在渲染 過程中,會跟蹤每一個組件的依賴關系,不需要重新渲染整個組件樹。

          對于 React 而言,每當應用的狀態被改變時,全部子組件都會重新渲 染。當然,這可以通過 PureComponent/shouldComponentUpdate 這 個生命周期方法來進行控制,但 Vue 將此視為默認的優化。

          3)組件化

          React 與 Vue 最大的不同是模板的編寫。

          Vue 鼓勵寫近似常規 HTML 的模板。寫起來很接近標準 HTML 元素,只 是多了一些屬性。

          React 推薦你所有的模板通用 JavaScript 的語法擴展——JSX 書寫。

          具體來講:React 中 render 函數是支持閉包特性的,所以 import 的 組件在 render 中可以直接調用。但是在 Vue 中,由于模板中使用的 數據都必須掛在 this 上進行一次中轉,所以 import 一個組件完了 之后,還需要在 components 中再聲明下。

          4)監聽數據變化的實現原理不同

          Vue 通過 getter/setter 以及一些函數的劫持,能精確知道數據變 化,不需要特別的優化就能達到很好的性能

          React 默 認 是 通 過 比 較 引 用 的 方 式 進 行 的 , 如 果 不 優 化(PureComponent/shouldComponentUpdate)可能導致大量不必要的 vDOM 的重新渲染。這是因為 Vue 使用的是可變數據,而 React 更強 調數據的不可變。

          5)高階組件

          react 可以通過高階組件(HOC)來擴展,而 Vue 需要通過 mixins 來 擴展。

          高階組件就是高階函數,而 React 的組件本身就是純粹的函數,所以 高階函數對 React 來說易如反掌。相反 Vue.js 使用 HTML 模板創建視 圖組件,這時模板無法有效的編譯,因此 Vue 不能采用 HOC 來實現。

          6)構建工具

          兩者都有自己的構建工具:

          React ==> Create React APP

          Vue ==> vue-cli

          7)跨平臺

          React ==> React Native

          Vue ==> Weex

          12. Vue 的優點

          輕量級框架:只關注視圖層,是一個構建數據的視圖集合,大小只有 幾十 kb ;

          簡單易學:國人開發,中文文檔,不存在語言障礙 ,易于理解和學 習;

          雙向數據綁定:保留了 angular 的特點,在數據操作方面更為簡單;組件化:保留了 react 的優點,實現了 html 的封裝和重用,在構 建單頁面應用方面有著獨特的優勢;

          視圖,數據,結構分離:使數據的更改更為簡單,不需要進行邏輯代 碼的修改,只需要操作數據就能完成相關操作;

          虛擬 DOM:dom 操作是非常耗費性能的,不再使用原生的 dom 操作 節點,極大解放 dom 操作,但具體操作的還是 dom 不過是換了另一 種方式;

          運行速度更快:相比較于 react 而言,同樣是操作虛擬 dom,就性 能而言, vue 存在很大的優勢。

          13. assets 和 static 的區別

          相同點: assets 和 static 兩個都是存放靜態資源文件。項目中所 需要的資源文件圖片,字體圖標,樣式文件等都可以放在這兩個文件 下,這是相同點

          不相同點:assets 中存放的靜態資源文件在項目打包時,也就是運 行 npm run build 時會將 assets 中放置的靜態資源文件進行打包 上傳,所謂打包簡單點可以理解為壓縮體積,代碼格式化。而壓縮后 的靜態資源文件最終也都會放置在 static 文件中跟著 index.html 一同上傳至服務器。static 中放置的靜態資源文件就不會要走打包 壓縮格式化等流程,而是直接進入打包好的目錄,直接上傳至服務器。

          因為避免了壓縮直接進行上傳,在打包時會提高一定的效率,但是 static 中的資源文件由于沒有進行壓縮等操作,所以文件的體積也 就相對于 assets 中打包后的文件提交較大點。在服務器中就會占據 更大的空間。

          建議: 將項目中 template 需要的樣式文件 js 文件等都可以放置在 assets 中,走打包這一流程。減少體積。而項目中引入的第三方的 資源文件如 iconfoont.css 等文件可以放置在 static 中,因為這 些引入的第三方文件已經經過處理,不再需要處理,直接上傳。

          14. delete 和 Vue.delete 刪除數組的區別

          delete 只是被刪除的元素變成了 empty/undefined 其他的元素的 鍵值還是不變。

          Vue.delete 直接刪除了數組 改變了數組的鍵值。

          15. Vue 模版編譯原理

          vue 中的模板 template 無法被瀏覽器解析并渲染,因為這不屬于瀏 覽器的標準,不是正確的 HTML 語法,所有需要將 template 轉化成一 個 JavaScript 函數,這樣瀏覽器就可以執行這一個函數并渲染出對 應的 HTML 元素,就可以讓視圖跑起來了,這一個轉化的過程,就成 為模板編譯。模板編譯又分三個階段,解析 parse,優化 optimize,生成 generate,最終生成可執行函數 render。

          解析階段:使用大量的正則表達式對 template 字符串進行解析,將 標簽、指令、屬性等轉化為抽象語法樹 AST。

          優化階段:遍歷 AST,找到其中的一些靜態節點并進行標記,方便在 頁面重渲染的時候進行 diff 比較時,直接跳過這一些靜態節點,優 化 runtime 的性能。

          生成階段:將最終的 AST 轉化為 render 函數字符串。

          16. vue 初始化頁面閃動問題

          使用 vue 開發時,在 vue 初始化之前,由于 div 是不歸 vue 管的,所 以我們寫的代碼在還沒有解析的情況下會容易出現花屏現象,看到類 似于{{message}}的字樣,雖然一般情況下這個時間很短暫,但是還 是有必要讓解決這個問題的。

          首先:在 css 里加上以下代碼:

          如 果 沒 有 徹 底 解 決 問 題 , 則 在 根 元 素 加 上 style="display:

          none;" :style="{display: 'block'}"

          17. MVVM 的優缺點?

          優點:

          分離視圖(View)和模型(Model),降低代碼耦合,提?視圖或者 邏輯的重?性: ?如視圖(View)可以獨?于 Model 變化和修改,?個 ViewModel 可以綁定不同的"View"上,當 View 變化的時候 Model 不可以不變,當 Model 變化的時候 View 也可以不變。你可以把?些 視圖邏輯放在?個 ViewModel??,讓很多 view 重?這段視圖邏輯

          提?可測試性: ViewModel 的存在可以幫助開發者更好地編寫測試代 碼

          ?動更新 dom: 利?雙向綁定,數據更新后視圖?動更新,讓開發者從 繁瑣的?動 dom 中解放

          缺點:

          Bug 很難被調試: 因為使?雙向綁定的模式,當你看到界?異常了,有可能是你 View 的代碼有 Bug,也可能是 Model 的代碼有問題。數 據綁定使得?個位置的 Bug 被快速傳遞到別的位置,要定位原始出問 題的地?就變得不那么容易了。另外,數據綁定的聲明是指令式地寫 在 View 的模版當中的,這些內容是沒辦法去打斷點 debug 的

          ?個?的模塊中 model 也會很?,雖然使??便了也很容易保證了數 據的?致性,當時?期持有,不釋放內存就造成了花費更多的內存

          對于?型的圖形應?程序,視圖狀態較多,ViewModel 的構建和維護 的成本都會?較?。

          18. v-if 和 v-for 哪個優先級更高?如果同時出現,應如何優 化?

          v-for 優先于 v-if 被解析,如果同時出現,每次渲染都會先執行循 環再判斷條件,無論如何循環都不可避免,浪費了性能。

          要避免出現這種情況,則在外層嵌套 template,在這一層進行 v-if 判斷,然后在內部進行 v-for 循環。如果條件出現在循環內部,可通 過計算屬性提前過濾掉那些不需要顯示的項。

          19. 對 Vue 組件化的理解

          1.組件是獨立和可復用的代碼組織單元。組件系統是 Vue 核心特性之 一,它使開發者使用小型、獨立和通常可復用的組件構建大型應用;

          2.組件化開發能大幅提高應用開發效率、測試性、復用性等;

          3.組件使用按分類有:頁面組件、業務組件、通用組件;

          4.vue 的組件是基于配置的,我們通常編寫的組件是組件配置而非組 件,框架后續會生成其構造函數,它們基于 VueComponent,擴展于 Vue;

          5.vue 中常見組件化技術有:屬性 prop,自定義事件,插槽等,它們 主要用于組件通信、擴展等;6.合理的劃分組件,有助于提升應用性 能;

          6.組件應該是高內聚、低耦合的;

          7.遵循單向數據流的原則。

          20. 對 vue 設計原則的理解

          1.漸進式 JavaScript 框架:與其它大型框架不同的是,Vue 被設計 為可以自底向上逐層應用。Vue 的核心庫只關注視圖層,不僅易于上 手,還便于與第三方庫或既有項目整合。另一方面,當與現代化的工 具鏈以及各種支持類庫結合使用時,Vue 也完全能夠為復雜的單頁應 用提供驅動。

          2.易用性:vue 提供數據響應式、聲明式模板語法和基于配置的組件 系統等核心特性。這些使我們只需要關注應用的核心業務即可,只要 會寫 js、html 和 css 就能輕松編寫 vue 應用。

          3.靈活性:漸進式框架的最大優點就是靈活性,如果應用足夠小,我 們可能僅需要 vue 核心特性即可完成功能;隨著應用規模不斷擴大,我們才可能逐漸引入路由、狀態管理、vue-cli 等庫和工具,不管是 應用體積還是學習難度都是一個逐漸增加的平和曲線。

          4.高效性:超快的虛擬 DOM 和 diff算法使我們的應用擁有最佳的性能 表現。追求高效的過程還在繼續,vue3 中引入 Proxy 對數據響應式 改進以及編譯器中對于靜態內容編譯的改進都會讓 vue 更加高效。

          21. 說一下 Vue 的生命周期

          Vue 實例有?個完整的?命周期,也就是從開始創建、初始化數據、編譯模版、掛載 Dom -> 渲染、更新 -> 渲染、卸載 等?系列過程,稱這是 Vue 的?命周期。

          1.beforeCreate(創建前):數據觀測和初始化事件還未開始,此時 data 的響應式追蹤、event/watcher 都還沒有被設置,也就是說不 能訪問到 data、computed、watch、methods 上的方法和數據。

          2.created(創建后) :實例創建完成,實例上配置的 options 包 括 data、computed、watch、methods 等都配置完成,但是此時渲染 得節點還未掛載到 DOM,所以不能訪問到 $el 屬性。

          3.beforeMount(掛載前):在掛載開始之前被調用,相關的 render 函數首次被調用。實例已完成以下的配置:編譯模板,把 data 里面 的數據和模板生成 html。此時還沒有掛載 html 到頁面上。

          4.mounted(掛載后):在 el 被新創建的 vm.$el 替換,并掛載到實 例上去之后調用。實例已完成以下的配置:用上面編譯好的 html 內 容替換 el 屬性指向的 DOM 對象。完成模板中的 html 渲染到 html 頁 面中。此過程中進行 ajax 交互。

          5.beforeUpdate(更新前):響應式數據更新時調用,此時雖然響應 式數據更新了,但是對應的真實 DOM 還沒有被渲染。

          6.updated(更新后) :在由于數據更改導致的虛擬 DOM 重新渲染和 打補丁之后調用。此時 DOM 已經根據響應式數據的變化更新了。調 用時,組件 DOM 已經更新,所以可以執行依賴于 DOM 的操作。然而 在大多數情況下,應該避免在此期間更改狀態,因為這可能會導致更 新無限循環。該鉤子在服務器端渲染期間不被調用。

          7.beforeDestroy(銷毀前):實例銷毀之前調用。這一步,實例仍 然完全可用,this 仍能獲取到實例。

          8.destroyed(銷毀后):實例銷毀后調用,調用后,Vue 實例指示 的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例 也會被銷毀。該鉤子在服務端渲染期間不被調用。

          另外還有 keep-alive 獨有的生命周期,分別為 activated 和

          deactivated。用 keep-alive 包裹的組件在切換時不會進行銷毀,而 是緩存到內存中并執行 deactivated 鉤子函數,命中緩存渲染后會執 行 activated 鉤子函數。

          22. Vue 子組件和父組件執行順序 加載渲染過程:

          1.父組件 beforeCreate

          2.父組件 created

          3.父組件 beforeMount

          4.子組件 beforeCreate

          5.子組件 created

          6.子組件 beforeMount

          7.子組件 mounted

          8.父組件 mounted

          更新過程:

          1. 父組件 beforeUpdate

          2.子組件 beforeUpdate

          3.子組件 updated

          4.父組件 updated

          銷毀過程:

          1. 父組件 beforeDestroy

          2.子組件 beforeDestroy

          3.子組件 destroyed

          4.父組件 destoryed

          23. created 和 mounted 的區別

          created:在模板渲染成 html 前調用,即通常初始化某些屬性值,然 后再渲染成視圖。

          mounted:在模板渲染成 html 后調用,通常是初始化頁面完成后,再 對 html 的 dom 節點進行一些需要的操作。

          4. 一般在哪個生命周期請求異步數據

          我們可以在鉤子函數 created、beforeMount、mounted 中進行調用,因為在這三個鉤子函數中,data 已經創建,可以將服務端端返回的 數據進行賦值。

          推薦在 created 鉤子函數中調用異步請求,因為在 created 鉤子函 數中調用異步請求有以下優點:

          能更快獲取到服務端數據,減少頁面加載時間,用戶體驗更好;

          SSR 不支持 beforeMount 、mounted 鉤子函數,放在 created 中有 助于一致性。

          24. keep-alive 中的生命周期哪些

          keep-alive 是 Vue 提供的一個內置組件,用來對組件進行緩存——在組件切換過程中將狀態保留在內存中,防止重復渲染 DOM。

          如果為一個組件包裹了 keep-alive,那么它會多出兩個生命周期:deactivated、activated。同時,beforeDestroy 和 destroyed 就 不會再被觸發了,因為組件不會被真正銷毀。

          當組件被換掉時,會被緩存到內存中、觸發 deactivated 生命周期;當組件被切回來時,再去緩存里找這個組件、觸發 activated 鉤子 函數。

          25. 路由的 hash 和 history 模式的區別

          Vue-Router 有兩種模式:hash 模式和 history 模式。默認的路由模 式是 hash 模式。

          1. hash 模式

          簡介: hash 模式是開發中默認的模式,它的 URL 帶著一個#,例如:,它的 hash 值就是#/vue。

          特點:hash 值會出現在 URL 里面,但是不會出現在 HTTP 請求中,對 后端完全沒有影響。所以改變 hash 值,不會重新加載頁面。這種模 式的瀏覽器支持度很好,低版本的 IE 瀏覽器也支持這種模式。hash 路由被稱為是前端路由,已經成為 SPA(單頁面應用)的標配。

          原理: hash 模式的主要原理就是 onhashchange()事件:

          使用 onhashchange()事件的好處就是,在頁面的 hash 值發生變化時,無需向后端發起請求,window 就可以監聽事件的改變,并按規則加 載相應的代碼。除此之外,hash 值變化對應的 URL 都會被瀏覽器記

          錄下來,這樣瀏覽器就能實現頁面的前進和后退。雖然是沒有請求后 端服務器,但是頁面的 hash 值和對應的 URL 關聯起來了。

          2. history 模式

          簡介: history 模式的 URL 中沒有#,它使用的是傳統的路由分發模 式,即用戶在輸入一個 URL 時,服務器會接收這個請求,并解析這個 URL,然后做出相應的邏輯處理。

          特 點 :當 使 用 history 模 式 時 , URL 就 像 這 樣 :。相比 hash 模式更加好看。但是,history 模式需要后臺配置支持。如果后臺沒有正確配置,訪問時會返回 404。

          API: history api 可以分為兩大部分,切換歷史狀態和修改歷史狀 態:

          修 改 歷 史 狀 態 : 包 括 了 HTML5 History Interface 中 新 增 的 pushState() 和 replaceState() 方法,這兩個方法應用于瀏覽器的 歷史記錄棧,提供了對歷史記錄進行修改的功能。只是當他們進行修 改時,雖然修改了 url,但瀏覽器不會立即向后端發送請求。如果要 做到改變 url 但又不刷新頁面的效果,就需要前端用上這兩個 API。

          切換歷史狀態: 包括 forward()、back()、go()三個方法,對應瀏 覽器的前進,后退,跳轉操作。

          雖然 history 模式丟棄了丑陋的#。但是,它也有自己的缺點,就是 在刷新頁面的時候,如果沒有相應的路由或資源,就會刷出 404 來。

          如果想要切換到 history 模式,就要進行以下配置(后端也要進行配 置):

          3. 兩種模式對比

          調用 history.pushState() 相比于直接修改 hash,存在以下優勢:

          pushState() 設置的新 URL 可以是與當前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能設置與當前 URL 同文檔的 URL;

          pushState() 設置的新 URL 可以與當前 URL 一模一樣,這樣也會把 記錄添加到棧中;而 hash 設置的新值必須與原來不一樣才會觸發動 作將記錄添加到棧中;

          pushState() 通過 stateObject 參數可以添加任意類型的數據到記 錄中;而 hash 只可添加短字符串;

          pushState() 可額外設置 title 屬性供后續使用。

          hash 模式下,僅 hash 符號之前的 url 會被包含在請求中,后端如果 沒有做到對路由的全覆蓋,也不會返回 404 錯誤;history 模式下,前端的 url 必須和實際向后端發起請求的 url 一致,如果沒有對用的 路由處理,將返回 404 錯誤。

          hash 模式和 history 模式都有各自的優勢和缺陷,還是要根據實際 情況選擇性的使用。

          26. Vue-router 跳轉和 location.href 有什么區別

          使用 location.href= /url 來跳轉,簡單方便,但是刷新了頁面;

          使用 history.pushState( /url ) ,無刷新頁面,靜態跳轉;

          引進 router ,然后使用 router.push( /url ) 來跳轉,使用了 diff 算法,實現了按需加載,減少了 dom 的消耗。其實使用 router 跳 轉和使用 history.pushState() 沒什么差別的,因為 vue-router 就 是用了 history.pushState() ,尤其是在 history 模式下。

          27. Vuex 的原理

          Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。“store” 基本上就是一個 容器,它包含著你的應用中大部分的狀態 ( state )。

          Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的 時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得 到高效更新。

          改 變

          store 中 的 狀 態 的 唯 一 途 徑 就 是 顯 式 地 提 交

          (commit)

          mutation。這樣可以方便地跟蹤每一個狀態的變化。

          Vuex 為 Vue Components 建立起了一個完整的生態圈,包括開發中的 API 調用一環。

          (1)核心流程中的主要功能:

          Vue Components 是 vue 組件,組件會觸發(dispatch)一些事件或 動作,也就是圖中的 Actions;

          在組件中發出的動作,肯定是想獲取或者改變數據的,但是在 vuex 中,數據是集中管理的,不能直接去更改數據,所以會把這個動作提 交(Commit)到 Mutations 中;

          然后 Mutations 就去改變(Mutate)State 中的數據;

          當 State 中的數據被改變之后,就會重新渲染(Render)到 Vue Components 中去,組件展示更新后的數據,完成一個流程。

          (2)各模塊在核心流程中的主要功能:

          Vue Components∶ Vue 組件。HTML 頁面上,負責接收用戶操作等交 互行為,執行 dispatch 方法觸發對應 action 進行回應。

          dispatch∶操作行為觸發方法,是唯一能執行 action 的方法。

          actions∶ 操作行為處理模塊。負責處理 Vue Components 接收到的 所有交互行為。包含同步/異步操作,支持多個同名方法,按照注冊 的順序依次觸發。向后臺 API 請求的操作就在這個模塊中進行,包括 觸發其他 action 以及提交 mutation 的操作。該模塊提供了 Promise 的封裝,以支持 action 的鏈式觸發。

          commit∶狀態改變提交操作方法。對 mutation 進行提交,是唯一能 執行 mutation 的方法。

          mutations∶狀態改變操作方法。是 Vuex 修改 state 的唯一推薦方法,其他修改方式在嚴格模式下將會報錯。該方法只能進行同步操作,且 方法名只能全局唯一。操作之中會有一些 hook 暴露出來,以進行 state 的監控等。

          state∶ 頁面狀態管理容器對象。集中存儲 Vuecomponents 中 data 對象的零散數據,全局唯一,以進行統一的狀態管理。頁面顯示所需 的數據從該對象中進行讀取,利用 Vue 的細粒度數據響應機制來進行 高效的狀態更新。

          getters∶ state 對象讀取方法。圖中沒有單獨列出該模塊,應該被 包含在了 render 中,Vue Components 通過該方法讀取全局 state 對 象。

          總結:

          Vuex 實現了一個單向數據流,在全局擁有一個 State 存放數據,當 組件要更改 State 中的數據時,必須通過 Mutation 提交修改信息,Mutation 同時提供了訂閱者模式供外部插件調用獲取 State 數據 的更新。而當所有異步操作(常見于調用后端接口異步獲取更新數據) 或批量的同步操作需要走 Action ,但 Action 也是無法直接修改 State 的,還是需要通過 Mutation 來修改 State 的數據。最后,根 據 State 的變化,渲染到視圖上。

          28. Vuex 和 localStorage 的區別

          (1)最重要的區別

          vuex 存儲在內存中

          localstorage 則以文件的方式存儲在本地,只能存儲字符串類型的 數據,存儲對象需要 JSON 的 stringify 和 parse 方法進行處理。 讀 取內存比讀取硬盤速度要快

          (2)應用場景

          Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集 中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一 種可預測的方式發生變化。vuex 用于組件之間的傳值。

          localstorage 是本地存儲,是將數據存儲到瀏覽器的方法,一般是 在跨頁面傳遞數據時使用 。

          Vuex 能做到數據的響應式,localstorage 不能

          (3)永久性

          刷新頁面時 vuex 存儲的值會丟失,localstorage 不會。

          注意:對于不變的數據確實可以用 localstorage 可以代替 vuex,但 是當兩個組件共用一個數據源(對象或數組)時,如果其中一個組件 改變了該數據源,希望另一個組件響應該變化時,localstorage 無 法做到,原因就是區別 1。

          29. Redux 和 Vuex 有什么區別,它們的共同思想

          (1)Redux 和 Vuex 區別

          Vuex 改進了 Redux 中的 Action 和 Reducer 函數,以 mutations 變化 函數取代 Reducer,無需 switch,只需在對應的 mutation 函數里改 變 state 值即可

          Vuex 由于 Vue 自動重新渲染的特性,無需訂閱重新渲染函數,只要 生成新的 State 即可

          Vuex 數據流的順序是∶View 調用 store.commit 提交對應的請求到 Store 中對應的 mutation 函數->store 改變(vue 檢測到數據變化自 動渲染)

          通俗點理解就是,vuex 弱化 dispatch,通過 commit 進行 store 狀 態的一次更變;取消了 action 概念,不必傳入特定的 action 形式進 行指定變更;弱化 reducer,基于 commit 參數直接對數據進行轉變,使得框架更加簡易;

          (2)共同思想

          單—的數據源

          變化可以預測

          本質上:redux 與 vuex 都是對 mvvm 思想的服務,將數據從視圖中抽 離的一種方案;

          形式上:vuex 借鑒了 redux,將 store 作為全局的數據中心,進行 mode 管理;

          30. 為什么要用 Vuex 或者 Redux

          由于傳參的方法對于多層嵌套的組件將會非常繁瑣,并且對于兄弟組 件間的狀態傳遞無能為力。我們經常會采用父子組件直接引用或者通 過事件來變更和同步狀態的多份拷貝。以上的這些模式非常脆弱,通 常會導致代碼無法維護。

          所以需要把組件的共享狀態抽取出來,以一個全局單例模式管理。在 這種模式下,組件樹構成了一個巨大的"視圖",不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為。

          另外,通過定義和隔離狀態管理中的各種概念并強制遵守一定的規則,代碼將會變得更結構化且易維護。

          31. Vuex 有哪幾種屬性?

          有五種,分別是 State、 Getter、Mutation 、Action、 Module

          state => 基本數據(數據源存放地)

          getters => 從基本數據派生出來的數據

          mutations => 提交更改數據的方法,同步

          actions => 像一個裝飾器,包裹 mutations,使之可以異步。

          modules => 模塊化 Vuex

          32. Vuex 和單純的全局對象有什么區別?

          Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的 時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得 到高效更新。

          不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就 是顯式地提交 (commit) mutation。這樣可以方便地跟蹤每一個狀態 的變化,從而能夠實現一些工具幫助更好地了解我們的應用。

          33. 為什么 Vuex 的 mutation 中不能做異步操作?

          Vuex 中所有的狀態更新的唯一途徑都是 mutation,異步操作通過 Action 來提交 mutation 實現,這樣可以方便地跟蹤每一個狀態的 變化,從而能夠實現一些工具幫助更好地了解我們的應用。

          每個 mutation 執行完成后都會對應到一個新的狀態變更,這樣 devtools 就可以打個快照存下來,然后就可以實現 time-travel 了。

          如果 mutation 支持異步操作,就沒有辦法知道狀態是何時更新的,無法很好的進行狀態的追蹤,給調試帶來困難。

          34. Vue3.0 有什么更新

          (1)監測機制的改變

          3.0 將帶來基于代理 Proxy 的 observer 實現,提供全語言覆蓋的 反應性跟蹤。

          消除了 Vue 2 當中基于 Object.defineProperty 的實現所存在的 很多限制:

          (2)只能監測屬性,不能監測對象

          檢測屬性的添加和刪除;

          檢測數組索引和長度的變更;

          支持 Map、Set、WeakMap 和 WeakSet。

          (3)模板

          作用域插槽,2.x 的機制導致作用域插槽變了,父組件會重新渲染,而 3.0 把作用域插槽改成了函數的方式,這樣只會影響子組件的重 新渲染,提升了渲染的性能。

          同時,對于 render 函數的方面,vue3.0 也會進行一系列更改來方 便習慣直接使用 api 來生成 vdom 。

          (4)對象式的組件聲明方式

          vue2.x 中 的 組 件 是 通 過 聲 明 的 方 式 傳 入 一 系 列 option , 和 TypeScript 的結合需要通過一些裝飾器的方式來做,雖然能實現功 能,但是比較麻煩。

          3.0 修改了組件的聲明方式,改成了類式的寫法,這樣使得和 TypeScript 的結合變得很容易

          (5)其它方面的更改

          支持自定義渲染器,從而使得 weex 可以通過自定義渲染器的方式來 擴展,而不是直接 fork 源碼來改的方式。

          支持 Fragment(多個根節點)和 Protal(在 dom 其他部分渲染組 建內容)組件,針對一些特殊的場景做了處理。

          基于 tree shaking 優化,提供了更多的內置功能。

          35. defineProperty 和 proxy 的區別

          Vue 在 實 例 初 始 化 時 遍 歷 data 中 的 所 有 屬 性 , 并 使 用 Object.defineProperty 把這些屬性全部轉為 getter/setter。這樣 當追蹤數據發生變化時,setter 會被自動調用。

          Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就 是 Vue 不支持 IE8 以及更低版本瀏覽器的原因。

          但是這樣做有以下問題:

          1.添加或刪除對象的屬性時,Vue 檢測不到。因為添加或刪除的對象 沒 有 在 初 始 化 進 行 響 應 式 處 理 , 只 能 通 過 $set 來 調 用 Object.defineProperty()處理。

          2.無法監控到數組下標和長度的變化。

          Vue3 使用 Proxy 來監控數據的變化。Proxy 是 ES6 中提供的功能,其作用為:用于定義基本操作的自定義行為(如屬性查找,賦值,枚 舉,函數調用等)。相對于 Object.defineProperty(),其有以下特 點:

          1.Proxy 直接代理整個對象而非對象屬性,這樣只需做一層代理就可 以監聽同級結構下的所有屬性變化,包括新增屬性和刪除屬性。2.Proxy 可以監聽數組的變化。

          36. Vue3.0 為什么要用 proxy?

          在 Vue2 中, 0bject.defineProperty 會改變原始數據,而 Proxy 是創建對象的虛擬表示,并提供 set 、get 和 deleteProperty 等 處理器,這些處理器可在訪問或修改原始對象上的屬性時進行攔截,有以下特點∶

          不需用使用 Vue.$set 或 Vue.$delete 觸發響應式。

          全方位的數組變化檢測,消除了 Vue2 無效的邊界情況。

          支持 Map,Set,WeakMap 和 WeakSet。

          Proxy 實現的響應式原理與 Vue2 的實現原理相同,實現方式大同小 異∶

          get 收集依賴

          Set、delete 等觸發依賴

          對于集合類型,就是對集合對象的方法做一層包裝:原方法執行后執 行依賴相關的收集或觸發邏輯。

          37. 虛擬 DOM 的解析過程

          虛擬 DOM 的解析過程:

          首先對將要插入到文檔中的 DOM 樹結構進行分析,使用 js 對象將 其表示出來,比如一個元素對象,包含 TagName、props 和 Children

          這些屬性。然后將這個 js 對象樹給保存下來,最后再將 DOM 片段 插入到文檔中。

          當頁面的狀態發生改變,需要對頁面的 DOM 的結構進行調整的時候,首先根據變更的狀態,重新構建起一棵對象樹,然后將這棵新的對象 樹和舊的對象樹進行比較,記錄下兩棵樹的的差異。

          最后將記錄的有差異的地方應用到真正的 DOM 樹中去,這樣視圖就 更新了。

          38. DIFF 算法的原理

          在新老虛擬 DOM 對比時:

          首先,對比節點本身,判斷是否為同一節點,如果不為相同節點,則 刪除該節點重新創建節點進行替換

          如果為相同節點,進行 patchVnode,判斷如何對該節點的子節點進 行處理,先判斷一方有子節點一方沒有子節點的情況(如果新的 children 沒有子節點,將舊的子節點移除)

          比較如果都有子節點,則進行 updateChildren,判斷如何對這些新 老節點的子節點進行操作(diff 核心)。

          匹配時,找到相同的子節點,遞歸比較子節點

          在 diff 中,只對同層的子節點進行比較,放棄跨級的節點比較,使 得時間復雜從 O(n 3)降低值 O(n),也就是說,只有當新舊 children 都為多個子節點時才需要用核心的 Diff 算法進行同層級比較。

          39. Vue 中 key 的作用

          vue 中 key 值的作用可以分為兩種情況來考慮:

          第一種情況是 v-if 中使用 key。由于 Vue 會盡可能高效地渲染元 素,通常會復用已有元素而不是從頭開始渲染。因此當使用 v-if 來 實現元素切換的時候,如果切換前后含有相同類型的元素,那么這個 元素就會被復用。如果是相同的 input 元素,那么切換前后用戶的 輸入不會被清除掉,這樣是不符合需求的。因此可以通過使用 key 來 唯一的標識一個元素,這個情況下,使用 key 的元素不會被復用。這個時候 key 的作用是用來標識一個獨立的元素。

          第二種情況是 v-for 中使用 key。用 v-for 更新已渲染過的元素列 表時,它默認使用“就地復用”的策略。如果數據項的順序發生了改 變,Vue 不會移動 DOM 元素來匹配數據項的順序,而是簡單復用此 處的每個元素。因此通過為每個列表項提供一個 key 值,來以便 Vue 跟蹤元素的身份,從而高效的實現復用。這個時候 key 的作用是為 了高效的更新渲染虛擬 DOM。

          key 是為 Vue 中 vnode 的唯一標記,通過這個 key,diff 操作可 以更準確、更快速

          更準確:因為帶 key 就不是就地復用了,在 sameNode 函數 a.key === b.key 對比中可以避免就地復用的情況。所以會更加準確。

          更快速:利用 key 的唯一性生成 map 對象來獲取對應節點,比遍歷 方式更快


          主站蜘蛛池模板: 精品国产亚洲一区二区在线观看| 国产精品99精品一区二区三区 | 午夜视频在线观看一区| 亚洲第一区二区快射影院| 久久精品无码一区二区日韩AV| 亚洲一区二区三区丝袜| 亚洲午夜在线一区| 色综合一区二区三区| 欧美亚洲精品一区二区| 国产一区精品视频| 精品一区二区久久| www一区二区www免费| 狠狠爱无码一区二区三区| 亚洲色偷精品一区二区三区| 日韩在线不卡免费视频一区| 一区二区三区日本视频| 国产中的精品一区的| 日韩精品人妻一区二区三区四区| 国产一区二区三区久久精品| 国产在线精品一区在线观看| 人妻AV中文字幕一区二区三区| 国产不卡视频一区二区三区| 国产亚洲福利精品一区二区| 无码一区18禁3D| 亚洲AV噜噜一区二区三区| 无码人妻精品一区二区蜜桃网站 | 欧美日韩精品一区二区在线观看| 中文字幕精品无码一区二区三区 | 日韩一区二区视频| 国产高清在线精品一区| 日韩人妻精品无码一区二区三区| 免费av一区二区三区| 亚洲AV美女一区二区三区| 久久亚洲综合色一区二区三区| 成人区精品一区二区不卡| 熟女性饥渴一区二区三区| 国产成人无码精品一区二区三区 | 国产一区二区视频在线观看| 国产精品亚洲不卡一区二区三区| 久久精品一区二区影院| 国产suv精品一区二区33|