Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 一区免费视频,久久精品免费观看,最近中文字幕完整在线看一

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          如何使用Web Storage對(duì)頁(yè)面中數(shù)據(jù)進(jìn)行監(jiān)聽?

          使用Web Storage存儲(chǔ)的數(shù)據(jù)發(fā)生變化時(shí),會(huì)觸發(fā)Window對(duì)象的storage事件,我們可以監(jiān)聽該事件并指定事件處理函數(shù),當(dāng)其他頁(yè)面中的localStorage或 sessionStorage中保存的數(shù)據(jù)發(fā)生改變時(shí),就會(huì)執(zhí)行事件處理函數(shù)。

          監(jiān)聽storage事件的示例代碼如下:

          // window.addEventListener(事件名, 事件處理畫數(shù));
          window.addEventListener('storage', function (event) {
            console.log(event.key);
          }):

          上述代碼中,事件處理函數(shù)接收一個(gè)event對(duì)象作為參數(shù),event對(duì)象的key屬性保存發(fā)生變化的數(shù)據(jù)的鍵名。event對(duì)象具有的一些屬性,如表所示。

          需要注意的是,storage事件并不在導(dǎo)致數(shù)據(jù)變化的當(dāng)前頁(yè)面觸發(fā)。如果瀏覽器同時(shí)打開一個(gè)域名下面的多個(gè)頁(yè)面,當(dāng)其中的一個(gè)頁(yè)面改變sessionStorage或localStorage的數(shù)據(jù)時(shí),其他所有頁(yè)面的storage事件會(huì)被觸發(fā),而原始頁(yè)面并不觸發(fā)storage事件。通過這種機(jī)制,可以實(shí)現(xiàn)多個(gè)頁(yè)面之間的通信。

          由于sessionStorage無(wú)法在不同標(biāo)簽頁(yè)的網(wǎng)頁(yè)中互相訪問數(shù)據(jù),當(dāng)使用storage事件時(shí),可以將頁(yè)面放在<iframe>標(biāo)簽創(chuàng)建的框架中,此時(shí)在框架內(nèi)通過storage事件可以監(jiān)聽外層頁(yè)面的sessionStorage的數(shù)據(jù)變化。

          對(duì)storage事件有了基本了解之后,下面演示如何使用storage事件對(duì)頁(yè)面中的數(shù)據(jù)進(jìn)行監(jiān)聽。我們通過兩個(gè)頁(yè)面進(jìn)行演示,第1個(gè)頁(yè)面demo03-l.html 用來(lái)修改localstorage數(shù)據(jù),第2個(gè)頁(yè)面demo03-2.html 用來(lái)監(jiān)聽數(shù)據(jù)的變化并實(shí)現(xiàn)數(shù)據(jù)的同步。

          (1)創(chuàng)建C:\codechapter02demo03-1.html,定義一個(gè)文本框用來(lái)輸入用戶名,定義一個(gè)“保存”按鈕用來(lái)將文本框中的用戶名保存在localstorage中,具體代碼如下:

          <!DOCTYPE html>
          <html>
          <head>
            <meta charset="UTF-8">
            <title>Document</title>
          </head>
          <body>
            <label>用戶名:</label><input type="text" id="username">
            <button id="save">保存</button>
            <script>
              var lsername = document.querySelector ('#username');
              //單擊”保存“按鈕,設(shè)置數(shù)據(jù)
              document.querySelector('#save').onclick=function() {
                var val=username.value; // 獲取username里面的值
                localStorage.setItem('username', val);
              };
             </script>
          </body>
          </html>

          在上述代碼中,第8行代碼的文本框用于輸入用戶信息;第l3~16行代碼用于設(shè)置localstorage的數(shù)據(jù)。

          (2)保存代碼,在瀏覽器中進(jìn)行測(cè)試,效果如圖所示。

          初始頁(yè)面效果

          (3)在圖2-8所示的文本框中輸入“userl”,單擊“保存”按鈕,然后進(jìn)入開發(fā)者工具的Application選項(xiàng)卡,找到Local Storage選項(xiàng)并單擊該選項(xiàng)下的http://127.0.0.1:5500地址,可以看到設(shè)置的localStorage中Key的值為“usermame”,Value的值為“userl”的數(shù)據(jù),如圖所示。

          設(shè)置數(shù)據(jù)

          (4)創(chuàng)建C:kcodelchapter02\demo03-2.html,通過storage事件監(jiān)聽數(shù)據(jù)的變化,并定義兩個(gè)<span>標(biāo)簽用來(lái)顯示數(shù)據(jù)修改前和修改后的值,具體代碼如下:

          <!DOCTYPE html>
          <html>
          <head>
            <meta charset="UTF-8">
            <title>document</title>
          </head>
          <body>
            <span>新的用戶名:</span>
            <span id="newval"></span>
            <br>
            <span>舊的用戶名:</span>
            <span id="oldval"></span>
            <script>
              var newdata=document.getElementById('newval');
              var olddata=document.getElementById('oldval');
              window.addEventListener('storage', function(e){     
                newdata.innerHTMLme.newValue:       //設(shè)置元素的內(nèi)容為修改后的值
                olddata.innerHTML=e.oldValue;       //設(shè)置元素的內(nèi)容為修改前的值
              });
          </script>
          </body>
          </html>

          上述代碼中,第9行代碼和第12行代碼定義了兩個(gè)<span>標(biāo)簽,用來(lái)顯示數(shù)據(jù)被修改后和數(shù)據(jù)修改前的值;第16~19行代碼通過storage事件獲取e.newValue和e.oldValue的值并顯示到<span>標(biāo)簽中。

          (5)保存代碼,在瀏覽器中進(jìn)行測(cè)試,效果如圖2-10所示。

          頁(yè)面初始效果

          (6)切換到demo03-1.html頁(yè)面,在文本框中輸入“user2”,然后單擊“保存”按鈕。再切換到demo03-2.html網(wǎng)頁(yè),效果如圖2-11所示。

          修改后與修改前的用戶名

          從圖2-11可以看出,頁(yè)面顯示新的用戶名為“user2”,舊的用戶名為“userl”。由此可知,通過storage事件可以監(jiān)聽 localStorage數(shù)據(jù)發(fā)生的變化。

          ue實(shí)時(shí)監(jiān)聽 localStorage 變化

          應(yīng)用場(chǎng)景:

          1、頁(yè)面B需要實(shí)時(shí)獲取頁(yè)面A數(shù)據(jù)更改

          2、父子頁(yè)面之間的傳參

          代碼實(shí)例

          B頁(yè)面實(shí)時(shí)獲取A頁(yè)面的數(shù)據(jù)變化

          在【頁(yè)面A】進(jìn)行緩存修改or插入緩存

          localStorage.setItem('product_process_uid', parentinputname + '#' + data.uid + '#' + data.nickname);

          在【頁(yè)面B】需要監(jiān)聽緩存值更改

          mounted: function () {
              var that = this;
          
              //監(jiān)聽 localStorage 緩存中指定key的值變化,本例key為 product_process_uid
              window.addEventListener('storage', function (e) {
                if (e.key && e.key == 'product_process_uid' && e.newValue) {
                  that.product_process_uid = e.newValue;
          
                  // 監(jiān)聽到值后的處理邏輯
                  that.product_process_uid = that.product_process_uid.split('#');
                  that.formData.product_process[that.product_process_uid[0]].user_id = that.product_process_uid[1];
                  that.formData.product_process[that.product_process_uid[0]].user_name = that.product_process_uid[2];
          
                  // 根據(jù)實(shí)際情況,判斷處理完后是否要?jiǎng)h除這個(gè)key
                  localStorage.removeItem('product_process_uid');
                }
              })
          
          }

          如上即可在【頁(yè)面B】實(shí)時(shí)獲取到【頁(yè)面A】中的數(shù)據(jù)。

          注意

          頁(yè)面必須是同源(即同一個(gè)域名,例如:都在https://www.baidu.com/域名下)

          參考文檔:

          https://blog.csdn.net/qq_38902230/article/details/110233216

          https://www.muouseo.com/article/rpnv35ewm5.html

          . Vue 的基本原理

          當(dāng) 一 個(gè) Vue 實(shí) 例 創(chuàng) 建 時(shí) , Vue 會(huì) 遍 歷 data 中 的 屬 性 , 用 Object.defineProperty ( vue3.0 使 用 proxy) 將 它 們 轉(zhuǎn) 為 getter/setter,并且在內(nèi)部追蹤相關(guān)依賴,在屬性被訪問和修改時(shí) 通知變化。 每個(gè)組件實(shí)例都有相應(yīng)的 watcher 程序?qū)嵗鼤?huì)在組 件渲染的過程中把屬性記錄為依賴,之后當(dāng)依賴項(xiàng)的 setter 被調(diào)用 時(shí),會(huì)通知 watcher 重新計(jì)算,從而使它關(guān)聯(lián)的組件得以更新。

          2. 雙向數(shù)據(jù)綁定的原理

          Vue.js 是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過 Object.defineProperty()來(lái)劫持各個(gè)屬性的 setter,getter,在數(shù) 據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。主要分為以下幾 個(gè)步驟:

          1.需要 observe 的數(shù)據(jù)對(duì)象進(jìn)行遞歸遍歷,包括子屬性對(duì)象的屬性,都加上 setter 和 getter 這樣的話,給這個(gè)對(duì)象的某個(gè)值賦值,就會(huì) 觸發(fā) setter,那么就能監(jiān)聽到了數(shù)據(jù)變化

          2.compile 解析模板指令,將模板中的變量替換成數(shù)據(jù),然后初始化 渲染頁(yè)面視圖,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽數(shù) 據(jù)的訂閱者,一旦數(shù)據(jù)有變動(dòng),收到通知,更新視圖

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

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

          3. MVVM、MVC、MVP 的區(qū)別

          MVC、MVP 和 MVVM 是三種常見的軟件架構(gòu)設(shè)計(jì)模式,主要通過分離 關(guān)注點(diǎn)的方式來(lái)組織代碼結(jié)構(gòu),優(yōu)化開發(fā)效率。

          在開發(fā)單頁(yè)面應(yīng)用時(shí),往往一個(gè)路由頁(yè)面對(duì)應(yīng)了一個(gè)腳本文件,所有 的頁(yè)面邏輯都在一個(gè)腳本文件里。頁(yè)面的渲染、數(shù)據(jù)的獲取,對(duì)用戶來(lái)說(shuō) 事件的響應(yīng)所有的應(yīng)用邏輯都混合在一起,這樣在開發(fā)簡(jiǎn)單項(xiàng)目時(shí),可能看不出什么問題,如果項(xiàng)目變得復(fù)雜,那么整個(gè)文件就會(huì)變得冗 長(zhǎng)、混亂,這樣對(duì)項(xiàng)目開發(fā)和后期的項(xiàng)目維護(hù)是非常不利的。

          (1)MVC

          MVC 通過分離 Model、View 和 Controller 的方式來(lái)組織代碼結(jié)構(gòu)。其中 View 負(fù)責(zé)頁(yè)面的顯示邏輯,Model 負(fù)責(zé)存儲(chǔ)頁(yè)面的業(yè)務(wù)數(shù)據(jù),以及對(duì)相應(yīng)數(shù)據(jù)的操作。并且 View 和 Model 應(yīng)用了觀察者模式,當(dāng) Model 層發(fā)生改變的時(shí)候它會(huì)通知有關(guān) View 層更新頁(yè)面。Controller 層是 View 層和 Model 層的紐帶,它主要負(fù)責(zé)用戶與應(yīng) 用的響應(yīng)操作,當(dāng)用戶與頁(yè)面產(chǎn)生交互的時(shí)候,Controller 中的事 觸發(fā)器就開始工作了,通過調(diào)用 Model 層,來(lái)完成對(duì) Model 的修 改,然后 Model 層再去通知 View 層更新。

          (2)MVVM

          MVVM 分為 Model、View、ViewModel:

          Model 代表數(shù)據(jù)模型,數(shù)據(jù)和業(yè)務(wù)邏輯都在 Model 層中定義;

          View 代表 UI 視圖,負(fù)責(zé)數(shù)據(jù)的展示;

          ViewModel 負(fù)責(zé)監(jiān)聽 Model 中數(shù)據(jù)的改變并且控制視圖的更新,處理 用戶交互操作;

          Model 和 View 并無(wú)直接關(guān)聯(lián),而是通過 ViewModel 來(lái)進(jìn)行聯(lián)系的,Model 和 ViewModel 之間有著雙向數(shù)據(jù)綁定的聯(lián)系。因此當(dāng) Model 中 的數(shù)據(jù)改變時(shí)會(huì)觸發(fā) View 層的刷新,View 中由于用戶交互操作而改 變的數(shù)據(jù)也會(huì)在 Model 中同步。

          這種模式實(shí)現(xiàn)了 Model 和 View 的數(shù)據(jù)自動(dòng)同步,因此開發(fā)者只需要 專注于數(shù)據(jù)的維護(hù)操作即可,而不需要自己操作 DOM。

          (3)MVP

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

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

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

          默認(rèn)插槽:又名匿名插槽,當(dāng) slot 沒有指定 name 屬性值的時(shí)候一個(gè) 默認(rèn)顯示插槽,一個(gè)組件內(nèi)只有有一個(gè)匿名插槽。具名插槽:帶有具體名字的插槽,也就是帶有 name 屬性的 slot,一 個(gè)組件可以出現(xiàn)多個(gè)具名插槽。

          作用域插槽:默認(rèn)插槽、具名插槽的一個(gè)變體,可以是匿名插槽,也 可以是具名插槽,該插槽的不同點(diǎn)是在子組件渲染作用域插槽時(shí),可 以將子組件內(nèi)部的數(shù)據(jù)傳遞給父組件,讓父組件根據(jù)子組件的傳遞過 來(lái)的數(shù)據(jù)決定如何渲染該插槽。

          實(shí)現(xiàn)原理:當(dāng)子組件 vm 實(shí)例化時(shí),獲取到父組件傳入的 slot 標(biāo)簽的 內(nèi)容,存放在 vm.$slot 中,默認(rèn)插槽為 vm.$slot.default,具名插 槽為 vm.$slot.xxx,xxx 為插槽名,當(dāng)組件執(zhí)行渲染函數(shù)時(shí)候,遇 到 slot 標(biāo)簽,使用$slot 中的內(nèi)容進(jìn)行替換,此時(shí)可以為插槽傳遞 數(shù)據(jù),若存在數(shù)據(jù),則可稱該插槽為作用域插槽。

          5. $nextTick 原理及作用

          Vue 的 nextTick 其本質(zhì)是對(duì) JavaScript 執(zhí)行原理 EventLoop 的 一種應(yīng)用。

          nextTick 的 核 心 是 利 用 了 如 Promise 、 MutationObserver 、setImmediate、setTimeout 的原生 JavaScript 方法來(lái)模擬對(duì)應(yīng)的 微/宏任務(wù)的實(shí)現(xiàn),本質(zhì)是為了利用 JavaScript 的這些異步回調(diào)任 務(wù)隊(duì)列來(lái)實(shí)現(xiàn) Vue 框架中自己的異步回調(diào)隊(duì)列。

          nextTick 不僅是 Vue 內(nèi)部的異步隊(duì)列的調(diào)用方法,同時(shí)也允許開發(fā) 者在實(shí)際項(xiàng)目中使用這個(gè)方法來(lái)滿足實(shí)際應(yīng)用中對(duì) DOM 更新數(shù)據(jù)時(shí) 機(jī)的后續(xù)邏輯處理

          nextTick 是典型的將底層 JavaScript 執(zhí)行原理應(yīng)用到具體案例中 的示例,引入異步更新隊(duì)列機(jī)制的原因∶如果是同步更新,則多次對(duì)一個(gè)或多個(gè)屬性賦值,會(huì)頻繁觸發(fā) UI/DOM 的渲染,可以減少一些無(wú)用渲染

          同時(shí)由于 VirtualDOM 的引入,每一次狀態(tài)發(fā)生變化后,狀態(tài)變化的 信號(hào)會(huì)發(fā)送給組件,組件內(nèi)部使用 VirtualDOM 進(jìn)行計(jì)算得出需要更 新的具體的 DOM 節(jié)點(diǎn),然后對(duì) DOM 進(jìn)行更新操作,每次更新狀態(tài)后 的渲染過程需要更多的計(jì)算,而這種無(wú)用功也將浪費(fèi)更多的性能,所 以異步渲染變得更加至關(guān)重要

          Vue 采用了數(shù)據(jù)驅(qū)動(dòng)視圖的思想,但是在一些情況下,仍然需要操作 DOM。有時(shí)候,可能遇到這樣的情況,DOM1 的數(shù)據(jù)發(fā)生了變化,而 DOM2 需要從 DOM1 中獲取數(shù)據(jù),那這時(shí)就會(huì)發(fā)現(xiàn) DOM2 的視圖并沒有更新,這時(shí)就需要用到了 nextTick 了。

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

          所以,在以下情況下,會(huì)用到 nextTick:

          在數(shù)據(jù)變化后執(zhí)行的某個(gè)操作,而這個(gè)操作需要使用隨數(shù)據(jù)變化而變 化的 DOM 結(jié)構(gòu)的時(shí)候,這個(gè)操作就需要方法在 nextTick()的回調(diào)函 數(shù)中。

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

          因?yàn)樵?created()鉤子函數(shù)中,頁(yè)面的 DOM 還未渲染,這時(shí)候也沒辦 法操作 DOM,所以,此時(shí)如果想要操作 DOM,必須將操作的代碼放在 nextTick()的回調(diào)函數(shù)中。

          6. Vue 單頁(yè)應(yīng)用與多頁(yè)應(yīng)用的區(qū)別

          概念:

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

          MPA 多頁(yè)面應(yīng)用 (MultiPage Application),指有多個(gè)獨(dú)立頁(yè)面的 應(yīng)用,每個(gè)頁(yè)面必須重復(fù)加載 js、css 等相關(guān)資源。多頁(yè)應(yīng)用跳轉(zhuǎn),需要整頁(yè)資源刷新。

          區(qū)別:

          7. Vue 中封裝的數(shù)組方法有哪些,其如何實(shí)現(xiàn)頁(yè)面更新

          在 Vue 中,對(duì)響應(yīng)式處理利用的是 Object.defineProperty 對(duì)數(shù)據(jù)進(jìn) 行攔截,而這個(gè)方法并不能監(jiān)聽到數(shù)組內(nèi)部變化,數(shù)組長(zhǎng)度變化,數(shù) 組的截取變化等,所以需要對(duì)這些操作進(jìn)行 hack,讓 Vue 能監(jiān)聽到 其中的變化。

          那 Vue 是如何實(shí)現(xiàn)讓這些數(shù)組方法實(shí)現(xiàn)元素的實(shí)時(shí)更新的呢,下面是 Vue 中對(duì)這些方法的封裝:

          簡(jiǎn)單來(lái)說(shuō)就是,重寫了數(shù)組中的那些原生方法,首先獲取到這個(gè)數(shù)組 的__ob__,也就是它的 Observer 對(duì)象,如果有新的值,就調(diào)用 observeArray 繼續(xù)對(duì)新的值觀察變化(也就是通過 target__proto__ == arrayMethods 來(lái)改變了數(shù)組實(shí)例的型),然后手動(dòng)調(diào)用 notify,通知渲染 watcher,執(zhí)行 update。

          8. Vue data 中某一個(gè)屬性的值發(fā)生改變后,視圖會(huì)立即同步執(zhí) 行重新渲染嗎?

          不會(huì)立即同步執(zhí)行重新渲染。Vue 實(shí)現(xiàn)響應(yīng)式并不是數(shù)據(jù)發(fā)生變化之 后 DOM 立即變化,而是按一定的策略進(jìn)行 DOM 的更新。Vue 在更新 DOM 時(shí)是異步執(zhí)行的。只要偵聽到數(shù)據(jù)變化, Vue 將開啟一個(gè)隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。

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

          9. 簡(jiǎn)述 mixin、extends 的覆蓋邏輯

          (1)mixin 和 extends

          mixin 和 extends 均 是 用 于 合 并 、 拓 展 組 件 的 , 兩 者 均 通 過 mergeOptions 方法實(shí)現(xiàn)合并。

          mixins 接收一個(gè)混入對(duì)象的數(shù)組,其中混入對(duì)象可以像正常的實(shí)例 對(duì)象一樣包含實(shí)例選項(xiàng),這些選項(xiàng)會(huì)被合并到最終的選項(xiàng)中。Mixin 鉤子按照傳入順序依次調(diào)用,并在調(diào)用組件自身的鉤子之前被調(diào)用。

          extends 主要是為了便于擴(kuò)展單文件組件,接收一個(gè)對(duì)象或構(gòu)造函數(shù)。

          (2)mergeOptions 的執(zhí)行過程

          規(guī) 范 化 選 項(xiàng) ( normalizeProps 、 normalizelnject 、normalizeDirectives)

          對(duì)未合并的選項(xiàng),進(jìn)行判斷

          10. 子組件可以直接改變父組件的數(shù)據(jù)嗎?

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

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

          11. 對(duì) React 和 Vue 的理解,它們的異同

          相似之處:

          都將注意力集中保持在核心庫(kù),而將其他功能如路由和全局狀態(tài)管理 交給相關(guān)的庫(kù);

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

          都有 props 的概念,允許組件間的數(shù)據(jù)傳遞;

          都鼓勵(lì)組件化應(yīng)用,將應(yīng)用分拆成一個(gè)個(gè)功能明確的模塊,提高復(fù)用 性。

          不同之處 :

          1)數(shù)據(jù)流

          Vue 默認(rèn)支持?jǐn)?shù)據(jù)雙向綁定,而 React 一直提倡單向數(shù)據(jù)流

          2)虛擬 DOM

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

          對(duì)于 React 而言,每當(dāng)應(yīng)用的狀態(tài)被改變時(shí),全部子組件都會(huì)重新渲 染。當(dāng)然,這可以通過 PureComponent/shouldComponentUpdate 這 個(gè)生命周期方法來(lái)進(jìn)行控制,但 Vue 將此視為默認(rèn)的優(yōu)化。

          3)組件化

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

          Vue 鼓勵(lì)寫近似常規(guī) HTML 的模板。寫起來(lái)很接近標(biāo)準(zhǔn) HTML 元素,只 是多了一些屬性。

          React 推薦你所有的模板通用 JavaScript 的語(yǔ)法擴(kuò)展——JSX 書寫。

          具體來(lái)講:React 中 render 函數(shù)是支持閉包特性的,所以 import 的 組件在 render 中可以直接調(diào)用。但是在 Vue 中,由于模板中使用的 數(shù)據(jù)都必須掛在 this 上進(jìn)行一次中轉(zhuǎn),所以 import 一個(gè)組件完了 之后,還需要在 components 中再聲明下。

          4)監(jiān)聽數(shù)據(jù)變化的實(shí)現(xiàn)原理不同

          Vue 通過 getter/setter 以及一些函數(shù)的劫持,能精確知道數(shù)據(jù)變 化,不需要特別的優(yōu)化就能達(dá)到很好的性能

          React 默 認(rèn) 是 通 過 比 較 引 用 的 方 式 進(jìn) 行 的 , 如 果 不 優(yōu) 化(PureComponent/shouldComponentUpdate)可能導(dǎo)致大量不必要的 vDOM 的重新渲染。這是因?yàn)?Vue 使用的是可變數(shù)據(jù),而 React 更強(qiáng) 調(diào)數(shù)據(jù)的不可變。

          5)高階組件

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

          高階組件就是高階函數(shù),而 React 的組件本身就是純粹的函數(shù),所以 高階函數(shù)對(duì) React 來(lái)說(shuō)易如反掌。相反 Vue.js 使用 HTML 模板創(chuàng)建視 圖組件,這時(shí)模板無(wú)法有效的編譯,因此 Vue 不能采用 HOC 來(lái)實(shí)現(xiàn)。

          6)構(gòu)建工具

          兩者都有自己的構(gòu)建工具:

          React ==> Create React APP

          Vue ==> vue-cli

          7)跨平臺(tái)

          React ==> React Native

          Vue ==> Weex

          12. Vue 的優(yōu)點(diǎn)

          輕量級(jí)框架:只關(guān)注視圖層,是一個(gè)構(gòu)建數(shù)據(jù)的視圖集合,大小只有 幾十 kb ;

          簡(jiǎn)單易學(xué):國(guó)人開發(fā),中文文檔,不存在語(yǔ)言障礙 ,易于理解和學(xué) 習(xí);

          雙向數(shù)據(jù)綁定:保留了 angular 的特點(diǎn),在數(shù)據(jù)操作方面更為簡(jiǎn)單;組件化:保留了 react 的優(yōu)點(diǎn),實(shí)現(xiàn)了 html 的封裝和重用,在構(gòu) 建單頁(yè)面應(yīng)用方面有著獨(dú)特的優(yōu)勢(shì);

          視圖,數(shù)據(jù),結(jié)構(gòu)分離:使數(shù)據(jù)的更改更為簡(jiǎn)單,不需要進(jìn)行邏輯代 碼的修改,只需要操作數(shù)據(jù)就能完成相關(guān)操作;

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

          運(yùn)行速度更快:相比較于 react 而言,同樣是操作虛擬 dom,就性 能而言, vue 存在很大的優(yōu)勢(shì)。

          13. assets 和 static 的區(qū)別

          相同點(diǎn): assets 和 static 兩個(gè)都是存放靜態(tài)資源文件。項(xiàng)目中所 需要的資源文件圖片,字體圖標(biāo),樣式文件等都可以放在這兩個(gè)文件 下,這是相同點(diǎn)

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

          因?yàn)楸苊饬藟嚎s直接進(jìn)行上傳,在打包時(shí)會(huì)提高一定的效率,但是 static 中的資源文件由于沒有進(jìn)行壓縮等操作,所以文件的體積也 就相對(duì)于 assets 中打包后的文件提交較大點(diǎn)。在服務(wù)器中就會(huì)占據(jù) 更大的空間。

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

          14. delete 和 Vue.delete 刪除數(shù)組的區(qū)別

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

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

          15. Vue 模版編譯原理

          vue 中的模板 template 無(wú)法被瀏覽器解析并渲染,因?yàn)檫@不屬于瀏 覽器的標(biāo)準(zhǔn),不是正確的 HTML 語(yǔ)法,所有需要將 template 轉(zhuǎn)化成一 個(gè) JavaScript 函數(shù),這樣瀏覽器就可以執(zhí)行這一個(gè)函數(shù)并渲染出對(duì) 應(yīng)的 HTML 元素,就可以讓視圖跑起來(lái)了,這一個(gè)轉(zhuǎn)化的過程,就成 為模板編譯。模板編譯又分三個(gè)階段,解析 parse,優(yōu)化 optimize,生成 generate,最終生成可執(zhí)行函數(shù) render。

          解析階段:使用大量的正則表達(dá)式對(duì) template 字符串進(jìn)行解析,將 標(biāo)簽、指令、屬性等轉(zhuǎn)化為抽象語(yǔ)法樹 AST。

          優(yōu)化階段:遍歷 AST,找到其中的一些靜態(tài)節(jié)點(diǎn)并進(jìn)行標(biāo)記,方便在 頁(yè)面重渲染的時(shí)候進(jìn)行 diff 比較時(shí),直接跳過這一些靜態(tài)節(jié)點(diǎn),優(yōu) 化 runtime 的性能。

          生成階段:將最終的 AST 轉(zhuǎn)化為 render 函數(shù)字符串。

          16. vue 初始化頁(yè)面閃動(dòng)問題

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

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

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

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

          17. MVVM 的優(yōu)缺點(diǎn)?

          優(yōu)點(diǎn):

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

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

          ?動(dòng)更新 dom: 利?雙向綁定,數(shù)據(jù)更新后視圖?動(dòng)更新,讓開發(fā)者從 繁瑣的?動(dòng) dom 中解放

          缺點(diǎn):

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

          ?個(gè)?的模塊中 model 也會(huì)很?,雖然使??便了也很容易保證了數(shù) 據(jù)的?致性,當(dāng)時(shí)?期持有,不釋放內(nèi)存就造成了花費(fèi)更多的內(nèi)存

          對(duì)于?型的圖形應(yīng)?程序,視圖狀態(tài)較多,ViewModel 的構(gòu)建和維護(hù) 的成本都會(huì)?較?。

          18. v-if 和 v-for 哪個(gè)優(yōu)先級(jí)更高?如果同時(shí)出現(xiàn),應(yīng)如何優(yōu) 化?

          v-for 優(yōu)先于 v-if 被解析,如果同時(shí)出現(xiàn),每次渲染都會(huì)先執(zhí)行循 環(huán)再判斷條件,無(wú)論如何循環(huán)都不可避免,浪費(fèi)了性能。

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

          19. 對(duì) Vue 組件化的理解

          1.組件是獨(dú)立和可復(fù)用的代碼組織單元。組件系統(tǒng)是 Vue 核心特性之 一,它使開發(fā)者使用小型、獨(dú)立和通常可復(fù)用的組件構(gòu)建大型應(yīng)用;

          2.組件化開發(fā)能大幅提高應(yīng)用開發(fā)效率、測(cè)試性、復(fù)用性等;

          3.組件使用按分類有:頁(yè)面組件、業(yè)務(wù)組件、通用組件;

          4.vue 的組件是基于配置的,我們通常編寫的組件是組件配置而非組 件,框架后續(xù)會(huì)生成其構(gòu)造函數(shù),它們基于 VueComponent,擴(kuò)展于 Vue;

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

          6.組件應(yīng)該是高內(nèi)聚、低耦合的;

          7.遵循單向數(shù)據(jù)流的原則。

          20. 對(duì) vue 設(shè)計(jì)原則的理解

          1.漸進(jìn)式 JavaScript 框架:與其它大型框架不同的是,Vue 被設(shè)計(jì) 為可以自底向上逐層應(yīng)用。Vue 的核心庫(kù)只關(guān)注視圖層,不僅易于上 手,還便于與第三方庫(kù)或既有項(xiàng)目整合。另一方面,當(dāng)與現(xiàn)代化的工 具鏈以及各種支持類庫(kù)結(jié)合使用時(shí),Vue 也完全能夠?yàn)閺?fù)雜的單頁(yè)應(yīng) 用提供驅(qū)動(dòng)。

          2.易用性:vue 提供數(shù)據(jù)響應(yīng)式、聲明式模板語(yǔ)法和基于配置的組件 系統(tǒng)等核心特性。這些使我們只需要關(guān)注應(yīng)用的核心業(yè)務(wù)即可,只要 會(huì)寫 js、html 和 css 就能輕松編寫 vue 應(yīng)用。

          3.靈活性:漸進(jìn)式框架的最大優(yōu)點(diǎn)就是靈活性,如果應(yīng)用足夠小,我 們可能僅需要 vue 核心特性即可完成功能;隨著應(yīng)用規(guī)模不斷擴(kuò)大,我們才可能逐漸引入路由、狀態(tài)管理、vue-cli 等庫(kù)和工具,不管是 應(yīng)用體積還是學(xué)習(xí)難度都是一個(gè)逐漸增加的平和曲線。

          4.高效性:超快的虛擬 DOM 和 diff算法使我們的應(yīng)用擁有最佳的性能 表現(xiàn)。追求高效的過程還在繼續(xù),vue3 中引入 Proxy 對(duì)數(shù)據(jù)響應(yīng)式 改進(jìn)以及編譯器中對(duì)于靜態(tài)內(nèi)容編譯的改進(jìn)都會(huì)讓 vue 更加高效。

          21. 說(shuō)一下 Vue 的生命周期

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

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

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

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

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

          5.beforeUpdate(更新前):響應(yīng)式數(shù)據(jù)更新時(shí)調(diào)用,此時(shí)雖然響應(yīng) 式數(shù)據(jù)更新了,但是對(duì)應(yīng)的真實(shí) DOM 還沒有被渲染。

          6.updated(更新后) :在由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和 打補(bǔ)丁之后調(diào)用。此時(shí) DOM 已經(jīng)根據(jù)響應(yīng)式數(shù)據(jù)的變化更新了。調(diào) 用時(shí),組件 DOM 已經(jīng)更新,所以可以執(zhí)行依賴于 DOM 的操作。然而 在大多數(shù)情況下,應(yīng)該避免在此期間更改狀態(tài),因?yàn)檫@可能會(huì)導(dǎo)致更 新無(wú)限循環(huán)。該鉤子在服務(wù)器端渲染期間不被調(diào)用。

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

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

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

          deactivated。用 keep-alive 包裹的組件在切換時(shí)不會(huì)進(jìn)行銷毀,而 是緩存到內(nèi)存中并執(zhí)行 deactivated 鉤子函數(shù),命中緩存渲染后會(huì)執(zhí) 行 activated 鉤子函數(shù)。

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

          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 的區(qū)別

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

          mounted:在模板渲染成 html 后調(diào)用,通常是初始化頁(yè)面完成后,再 對(duì) html 的 dom 節(jié)點(diǎn)進(jìn)行一些需要的操作。

          4. 一般在哪個(gè)生命周期請(qǐng)求異步數(shù)據(jù)

          我們可以在鉤子函數(shù) created、beforeMount、mounted 中進(jìn)行調(diào)用,因?yàn)樵谶@三個(gè)鉤子函數(shù)中,data 已經(jīng)創(chuàng)建,可以將服務(wù)端端返回的 數(shù)據(jù)進(jìn)行賦值。

          推薦在 created 鉤子函數(shù)中調(diào)用異步請(qǐng)求,因?yàn)樵?created 鉤子函 數(shù)中調(diào)用異步請(qǐng)求有以下優(yōu)點(diǎn):

          能更快獲取到服務(wù)端數(shù)據(jù),減少頁(yè)面加載時(shí)間,用戶體驗(yàn)更好;

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

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

          keep-alive 是 Vue 提供的一個(gè)內(nèi)置組件,用來(lái)對(duì)組件進(jìn)行緩存——在組件切換過程中將狀態(tài)保留在內(nèi)存中,防止重復(fù)渲染 DOM。

          如果為一個(gè)組件包裹了 keep-alive,那么它會(huì)多出兩個(gè)生命周期:deactivated、activated。同時(shí),beforeDestroy 和 destroyed 就 不會(huì)再被觸發(fā)了,因?yàn)榻M件不會(huì)被真正銷毀。

          當(dāng)組件被換掉時(shí),會(huì)被緩存到內(nèi)存中、觸發(fā) deactivated 生命周期;當(dāng)組件被切回來(lái)時(shí),再去緩存里找這個(gè)組件、觸發(fā) activated 鉤子 函數(shù)。

          25. 路由的 hash 和 history 模式的區(qū)別

          Vue-Router 有兩種模式:hash 模式和 history 模式。默認(rèn)的路由模 式是 hash 模式。

          1. hash 模式

          簡(jiǎn)介: hash 模式是開發(fā)中默認(rèn)的模式,它的 URL 帶著一個(gè)#,例如:,它的 hash 值就是#/vue。

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

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

          使用 onhashchange()事件的好處就是,在頁(yè)面的 hash 值發(fā)生變化時(shí),無(wú)需向后端發(fā)起請(qǐng)求,window 就可以監(jiān)聽事件的改變,并按規(guī)則加 載相應(yīng)的代碼。除此之外,hash 值變化對(duì)應(yīng)的 URL 都會(huì)被瀏覽器記

          錄下來(lái),這樣瀏覽器就能實(shí)現(xiàn)頁(yè)面的前進(jìn)和后退。雖然是沒有請(qǐng)求后 端服務(wù)器,但是頁(yè)面的 hash 值和對(duì)應(yīng)的 URL 關(guān)聯(lián)起來(lái)了。

          2. history 模式

          簡(jiǎn)介: history 模式的 URL 中沒有#,它使用的是傳統(tǒng)的路由分發(fā)模 式,即用戶在輸入一個(gè) URL 時(shí),服務(wù)器會(huì)接收這個(gè)請(qǐng)求,并解析這個(gè) URL,然后做出相應(yīng)的邏輯處理。

          特 點(diǎn) :當(dāng) 使 用 history 模 式 時(shí) , URL 就 像 這 樣 :。相比 hash 模式更加好看。但是,history 模式需要后臺(tái)配置支持。如果后臺(tái)沒有正確配置,訪問時(shí)會(huì)返回 404。

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

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

          切換歷史狀態(tài): 包括 forward()、back()、go()三個(gè)方法,對(duì)應(yīng)瀏 覽器的前進(jìn),后退,跳轉(zhuǎn)操作。

          雖然 history 模式丟棄了丑陋的#。但是,它也有自己的缺點(diǎn),就是 在刷新頁(yè)面的時(shí)候,如果沒有相應(yīng)的路由或資源,就會(huì)刷出 404 來(lái)。

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

          3. 兩種模式對(duì)比

          調(diào)用 history.pushState() 相比于直接修改 hash,存在以下優(yōu)勢(shì):

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

          pushState() 設(shè)置的新 URL 可以與當(dāng)前 URL 一模一樣,這樣也會(huì)把 記錄添加到棧中;而 hash 設(shè)置的新值必須與原來(lái)不一樣才會(huì)觸發(fā)動(dòng) 作將記錄添加到棧中;

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

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

          hash 模式下,僅 hash 符號(hào)之前的 url 會(huì)被包含在請(qǐng)求中,后端如果 沒有做到對(duì)路由的全覆蓋,也不會(huì)返回 404 錯(cuò)誤;history 模式下,前端的 url 必須和實(shí)際向后端發(fā)起請(qǐng)求的 url 一致,如果沒有對(duì)用的 路由處理,將返回 404 錯(cuò)誤。

          hash 模式和 history 模式都有各自的優(yōu)勢(shì)和缺陷,還是要根據(jù)實(shí)際 情況選擇性的使用。

          26. Vue-router 跳轉(zhuǎn)和 location.href 有什么區(qū)別

          使用 location.href= /url 來(lái)跳轉(zhuǎn),簡(jiǎn)單方便,但是刷新了頁(yè)面;

          使用 history.pushState( /url ) ,無(wú)刷新頁(yè)面,靜態(tài)跳轉(zhuǎn);

          引進(jìn) router ,然后使用 router.push( /url ) 來(lái)跳轉(zhuǎn),使用了 diff 算法,實(shí)現(xiàn)了按需加載,減少了 dom 的消耗。其實(shí)使用 router 跳 轉(zhuǎn)和使用 history.pushState() 沒什么差別的,因?yàn)?vue-router 就 是用了 history.pushState() ,尤其是在 history 模式下。

          27. Vuex 的原理

          Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。每一個(gè) Vuex 應(yīng)用的核心就是 store(倉(cāng)庫(kù))。“store” 基本上就是一個(gè) 容器,它包含著你的應(yīng)用中大部分的狀態(tài) ( state )。

          Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的 時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得 到高效更新。

          改 變

          store 中 的 狀 態(tài) 的 唯 一 途 徑 就 是 顯 式 地 提 交

          (commit)

          mutation。這樣可以方便地跟蹤每一個(gè)狀態(tài)的變化。

          Vuex 為 Vue Components 建立起了一個(gè)完整的生態(tài)圈,包括開發(fā)中的 API 調(diào)用一環(huán)。

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

          Vue Components 是 vue 組件,組件會(huì)觸發(fā)(dispatch)一些事件或 動(dòng)作,也就是圖中的 Actions;

          在組件中發(fā)出的動(dòng)作,肯定是想獲取或者改變數(shù)據(jù)的,但是在 vuex 中,數(shù)據(jù)是集中管理的,不能直接去更改數(shù)據(jù),所以會(huì)把這個(gè)動(dòng)作提 交(Commit)到 Mutations 中;

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

          當(dāng) State 中的數(shù)據(jù)被改變之后,就會(huì)重新渲染(Render)到 Vue Components 中去,組件展示更新后的數(shù)據(jù),完成一個(gè)流程。

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

          Vue Components∶ Vue 組件。HTML 頁(yè)面上,負(fù)責(zé)接收用戶操作等交 互行為,執(zhí)行 dispatch 方法觸發(fā)對(duì)應(yīng) action 進(jìn)行回應(yīng)。

          dispatch∶操作行為觸發(fā)方法,是唯一能執(zhí)行 action 的方法。

          actions∶ 操作行為處理模塊。負(fù)責(zé)處理 Vue Components 接收到的 所有交互行為。包含同步/異步操作,支持多個(gè)同名方法,按照注冊(cè) 的順序依次觸發(fā)。向后臺(tái) API 請(qǐng)求的操作就在這個(gè)模塊中進(jìn)行,包括 觸發(fā)其他 action 以及提交 mutation 的操作。該模塊提供了 Promise 的封裝,以支持 action 的鏈?zhǔn)接|發(fā)。

          commit∶狀態(tài)改變提交操作方法。對(duì) mutation 進(jìn)行提交,是唯一能 執(zhí)行 mutation 的方法。

          mutations∶狀態(tài)改變操作方法。是 Vuex 修改 state 的唯一推薦方法,其他修改方式在嚴(yán)格模式下將會(huì)報(bào)錯(cuò)。該方法只能進(jìn)行同步操作,且 方法名只能全局唯一。操作之中會(huì)有一些 hook 暴露出來(lái),以進(jìn)行 state 的監(jiān)控等。

          state∶ 頁(yè)面狀態(tài)管理容器對(duì)象。集中存儲(chǔ) Vuecomponents 中 data 對(duì)象的零散數(shù)據(jù),全局唯一,以進(jìn)行統(tǒng)一的狀態(tài)管理。頁(yè)面顯示所需 的數(shù)據(jù)從該對(duì)象中進(jìn)行讀取,利用 Vue 的細(xì)粒度數(shù)據(jù)響應(yīng)機(jī)制來(lái)進(jìn)行 高效的狀態(tài)更新。

          getters∶ state 對(duì)象讀取方法。圖中沒有單獨(dú)列出該模塊,應(yīng)該被 包含在了 render 中,Vue Components 通過該方法讀取全局 state 對(duì) 象。

          總結(jié):

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

          28. Vuex 和 localStorage 的區(qū)別

          (1)最重要的區(qū)別

          vuex 存儲(chǔ)在內(nèi)存中

          localstorage 則以文件的方式存儲(chǔ)在本地,只能存儲(chǔ)字符串類型的 數(shù)據(jù),存儲(chǔ)對(duì)象需要 JSON 的 stringify 和 parse 方法進(jìn)行處理。 讀 取內(nèi)存比讀取硬盤速度要快

          (2)應(yīng)用場(chǎng)景

          Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集 中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一 種可預(yù)測(cè)的方式發(fā)生變化。vuex 用于組件之間的傳值。

          localstorage 是本地存儲(chǔ),是將數(shù)據(jù)存儲(chǔ)到瀏覽器的方法,一般是 在跨頁(yè)面?zhèn)鬟f數(shù)據(jù)時(shí)使用 。

          Vuex 能做到數(shù)據(jù)的響應(yīng)式,localstorage 不能

          (3)永久性

          刷新頁(yè)面時(shí) vuex 存儲(chǔ)的值會(huì)丟失,localstorage 不會(huì)。

          注意:對(duì)于不變的數(shù)據(jù)確實(shí)可以用 localstorage 可以代替 vuex,但 是當(dāng)兩個(gè)組件共用一個(gè)數(shù)據(jù)源(對(duì)象或數(shù)組)時(shí),如果其中一個(gè)組件 改變了該數(shù)據(jù)源,希望另一個(gè)組件響應(yīng)該變化時(shí),localstorage 無(wú) 法做到,原因就是區(qū)別 1。

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

          (1)Redux 和 Vuex 區(qū)別

          Vuex 改進(jìn)了 Redux 中的 Action 和 Reducer 函數(shù),以 mutations 變化 函數(shù)取代 Reducer,無(wú)需 switch,只需在對(duì)應(yīng)的 mutation 函數(shù)里改 變 state 值即可

          Vuex 由于 Vue 自動(dòng)重新渲染的特性,無(wú)需訂閱重新渲染函數(shù),只要 生成新的 State 即可

          Vuex 數(shù)據(jù)流的順序是∶View 調(diào)用 store.commit 提交對(duì)應(yīng)的請(qǐng)求到 Store 中對(duì)應(yīng)的 mutation 函數(shù)->store 改變(vue 檢測(cè)到數(shù)據(jù)變化自 動(dòng)渲染)

          通俗點(diǎn)理解就是,vuex 弱化 dispatch,通過 commit 進(jìn)行 store 狀 態(tài)的一次更變;取消了 action 概念,不必傳入特定的 action 形式進(jìn) 行指定變更;弱化 reducer,基于 commit 參數(shù)直接對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)變,使得框架更加簡(jiǎn)易;

          (2)共同思想

          單—的數(shù)據(jù)源

          變化可以預(yù)測(cè)

          本質(zhì)上:redux 與 vuex 都是對(duì) mvvm 思想的服務(wù),將數(shù)據(jù)從視圖中抽 離的一種方案;

          形式上:vuex 借鑒了 redux,將 store 作為全局的數(shù)據(jù)中心,進(jìn)行 mode 管理;

          30. 為什么要用 Vuex 或者 Redux

          由于傳參的方法對(duì)于多層嵌套的組件將會(huì)非常繁瑣,并且對(duì)于兄弟組 件間的狀態(tài)傳遞無(wú)能為力。我們經(jīng)常會(huì)采用父子組件直接引用或者通 過事件來(lái)變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱,通 常會(huì)導(dǎo)致代碼無(wú)法維護(hù)。

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

          另外,通過定義和隔離狀態(tài)管理中的各種概念并強(qiáng)制遵守一定的規(guī)則,代碼將會(huì)變得更結(jié)構(gòu)化且易維護(hù)。

          31. Vuex 有哪幾種屬性?

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

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

          getters => 從基本數(shù)據(jù)派生出來(lái)的數(shù)據(jù)

          mutations => 提交更改數(shù)據(jù)的方法,同步

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

          modules => 模塊化 Vuex

          32. Vuex 和單純的全局對(duì)象有什么區(qū)別?

          Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的 時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得 到高效更新。

          不能直接改變 store 中的狀態(tài)。改變 store 中的狀態(tài)的唯一途徑就 是顯式地提交 (commit) mutation。這樣可以方便地跟蹤每一個(gè)狀態(tài) 的變化,從而能夠?qū)崿F(xiàn)一些工具幫助更好地了解我們的應(yīng)用。

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

          Vuex 中所有的狀態(tài)更新的唯一途徑都是 mutation,異步操作通過 Action 來(lái)提交 mutation 實(shí)現(xiàn),這樣可以方便地跟蹤每一個(gè)狀態(tài)的 變化,從而能夠?qū)崿F(xiàn)一些工具幫助更好地了解我們的應(yīng)用。

          每個(gè) mutation 執(zhí)行完成后都會(huì)對(duì)應(yīng)到一個(gè)新的狀態(tài)變更,這樣 devtools 就可以打個(gè)快照存下來(lái),然后就可以實(shí)現(xiàn) time-travel 了。

          如果 mutation 支持異步操作,就沒有辦法知道狀態(tài)是何時(shí)更新的,無(wú)法很好的進(jìn)行狀態(tài)的追蹤,給調(diào)試帶來(lái)困難。

          34. Vue3.0 有什么更新

          (1)監(jiān)測(cè)機(jī)制的改變

          3.0 將帶來(lái)基于代理 Proxy 的 observer 實(shí)現(xiàn),提供全語(yǔ)言覆蓋的 反應(yīng)性跟蹤。

          消除了 Vue 2 當(dāng)中基于 Object.defineProperty 的實(shí)現(xiàn)所存在的 很多限制:

          (2)只能監(jiān)測(cè)屬性,不能監(jiān)測(cè)對(duì)象

          檢測(cè)屬性的添加和刪除;

          檢測(cè)數(shù)組索引和長(zhǎng)度的變更;

          支持 Map、Set、WeakMap 和 WeakSet。

          (3)模板

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

          同時(shí),對(duì)于 render 函數(shù)的方面,vue3.0 也會(huì)進(jìn)行一系列更改來(lái)方 便習(xí)慣直接使用 api 來(lái)生成 vdom 。

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

          vue2.x 中 的 組 件 是 通 過 聲 明 的 方 式 傳 入 一 系 列 option , 和 TypeScript 的結(jié)合需要通過一些裝飾器的方式來(lái)做,雖然能實(shí)現(xiàn)功 能,但是比較麻煩。

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

          (5)其它方面的更改

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

          支持 Fragment(多個(gè)根節(jié)點(diǎn))和 Protal(在 dom 其他部分渲染組 建內(nèi)容)組件,針對(duì)一些特殊的場(chǎng)景做了處理。

          基于 tree shaking 優(yōu)化,提供了更多的內(nèi)置功能。

          35. defineProperty 和 proxy 的區(qū)別

          Vue 在 實(shí) 例 初 始 化 時(shí) 遍 歷 data 中 的 所 有 屬 性 , 并 使 用 Object.defineProperty 把這些屬性全部轉(zhuǎn)為 getter/setter。這樣 當(dāng)追蹤數(shù)據(jù)發(fā)生變化時(shí),setter 會(huì)被自動(dòng)調(diào)用。

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

          但是這樣做有以下問題:

          1.添加或刪除對(duì)象的屬性時(shí),Vue 檢測(cè)不到。因?yàn)樘砑踊騽h除的對(duì)象 沒 有 在 初 始 化 進(jìn) 行 響 應(yīng) 式 處 理 , 只 能 通 過 $set 來(lái) 調(diào) 用 Object.defineProperty()處理。

          2.無(wú)法監(jiān)控到數(shù)組下標(biāo)和長(zhǎng)度的變化。

          Vue3 使用 Proxy 來(lái)監(jiān)控?cái)?shù)據(jù)的變化。Proxy 是 ES6 中提供的功能,其作用為:用于定義基本操作的自定義行為(如屬性查找,賦值,枚 舉,函數(shù)調(diào)用等)。相對(duì)于 Object.defineProperty(),其有以下特 點(diǎn):

          1.Proxy 直接代理整個(gè)對(duì)象而非對(duì)象屬性,這樣只需做一層代理就可 以監(jiān)聽同級(jí)結(jié)構(gòu)下的所有屬性變化,包括新增屬性和刪除屬性。2.Proxy 可以監(jiān)聽數(shù)組的變化。

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

          在 Vue2 中, 0bject.defineProperty 會(huì)改變?cè)紨?shù)據(jù),而 Proxy 是創(chuàng)建對(duì)象的虛擬表示,并提供 set 、get 和 deleteProperty 等 處理器,這些處理器可在訪問或修改原始對(duì)象上的屬性時(shí)進(jìn)行攔截,有以下特點(diǎn)∶

          不需用使用 Vue.$set 或 Vue.$delete 觸發(fā)響應(yīng)式。

          全方位的數(shù)組變化檢測(cè),消除了 Vue2 無(wú)效的邊界情況。

          支持 Map,Set,WeakMap 和 WeakSet。

          Proxy 實(shí)現(xiàn)的響應(yīng)式原理與 Vue2 的實(shí)現(xiàn)原理相同,實(shí)現(xiàn)方式大同小 異∶

          get 收集依賴

          Set、delete 等觸發(fā)依賴

          對(duì)于集合類型,就是對(duì)集合對(duì)象的方法做一層包裝:原方法執(zhí)行后執(zhí) 行依賴相關(guān)的收集或觸發(fā)邏輯。

          37. 虛擬 DOM 的解析過程

          虛擬 DOM 的解析過程:

          首先對(duì)將要插入到文檔中的 DOM 樹結(jié)構(gòu)進(jìn)行分析,使用 js 對(duì)象將 其表示出來(lái),比如一個(gè)元素對(duì)象,包含 TagName、props 和 Children

          這些屬性。然后將這個(gè) js 對(duì)象樹給保存下來(lái),最后再將 DOM 片段 插入到文檔中。

          當(dāng)頁(yè)面的狀態(tài)發(fā)生改變,需要對(duì)頁(yè)面的 DOM 的結(jié)構(gòu)進(jìn)行調(diào)整的時(shí)候,首先根據(jù)變更的狀態(tài),重新構(gòu)建起一棵對(duì)象樹,然后將這棵新的對(duì)象 樹和舊的對(duì)象樹進(jìn)行比較,記錄下兩棵樹的的差異。

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

          38. DIFF 算法的原理

          在新老虛擬 DOM 對(duì)比時(shí):

          首先,對(duì)比節(jié)點(diǎn)本身,判斷是否為同一節(jié)點(diǎn),如果不為相同節(jié)點(diǎn),則 刪除該節(jié)點(diǎn)重新創(chuàng)建節(jié)點(diǎn)進(jìn)行替換

          如果為相同節(jié)點(diǎn),進(jìn)行 patchVnode,判斷如何對(duì)該節(jié)點(diǎn)的子節(jié)點(diǎn)進(jìn) 行處理,先判斷一方有子節(jié)點(diǎn)一方?jīng)]有子節(jié)點(diǎn)的情況(如果新的 children 沒有子節(jié)點(diǎn),將舊的子節(jié)點(diǎn)移除)

          比較如果都有子節(jié)點(diǎn),則進(jìn)行 updateChildren,判斷如何對(duì)這些新 老節(jié)點(diǎn)的子節(jié)點(diǎn)進(jìn)行操作(diff 核心)。

          匹配時(shí),找到相同的子節(jié)點(diǎn),遞歸比較子節(jié)點(diǎn)

          在 diff 中,只對(duì)同層的子節(jié)點(diǎn)進(jìn)行比較,放棄跨級(jí)的節(jié)點(diǎn)比較,使 得時(shí)間復(fù)雜從 O(n 3)降低值 O(n),也就是說(shuō),只有當(dāng)新舊 children 都為多個(gè)子節(jié)點(diǎn)時(shí)才需要用核心的 Diff 算法進(jìn)行同層級(jí)比較。

          39. Vue 中 key 的作用

          vue 中 key 值的作用可以分為兩種情況來(lái)考慮:

          第一種情況是 v-if 中使用 key。由于 Vue 會(huì)盡可能高效地渲染元 素,通常會(huì)復(fù)用已有元素而不是從頭開始渲染。因此當(dāng)使用 v-if 來(lái) 實(shí)現(xiàn)元素切換的時(shí)候,如果切換前后含有相同類型的元素,那么這個(gè) 元素就會(huì)被復(fù)用。如果是相同的 input 元素,那么切換前后用戶的 輸入不會(huì)被清除掉,這樣是不符合需求的。因此可以通過使用 key 來(lái) 唯一的標(biāo)識(shí)一個(gè)元素,這個(gè)情況下,使用 key 的元素不會(huì)被復(fù)用。這個(gè)時(shí)候 key 的作用是用來(lái)標(biāo)識(shí)一個(gè)獨(dú)立的元素。

          第二種情況是 v-for 中使用 key。用 v-for 更新已渲染過的元素列 表時(shí),它默認(rèn)使用“就地復(fù)用”的策略。如果數(shù)據(jù)項(xiàng)的順序發(fā)生了改 變,Vue 不會(huì)移動(dòng) DOM 元素來(lái)匹配數(shù)據(jù)項(xiàng)的順序,而是簡(jiǎn)單復(fù)用此 處的每個(gè)元素。因此通過為每個(gè)列表項(xiàng)提供一個(gè) key 值,來(lái)以便 Vue 跟蹤元素的身份,從而高效的實(shí)現(xiàn)復(fù)用。這個(gè)時(shí)候 key 的作用是為 了高效的更新渲染虛擬 DOM。

          key 是為 Vue 中 vnode 的唯一標(biāo)記,通過這個(gè) key,diff 操作可 以更準(zhǔn)確、更快速

          更準(zhǔn)確:因?yàn)閹?key 就不是就地復(fù)用了,在 sameNode 函數(shù) a.key === b.key 對(duì)比中可以避免就地復(fù)用的情況。所以會(huì)更加準(zhǔn)確。

          更快速:利用 key 的唯一性生成 map 對(duì)象來(lái)獲取對(duì)應(yīng)節(jié)點(diǎn),比遍歷 方式更快


          主站蜘蛛池模板: 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 精品一区二区三区四区| 韩国美女vip福利一区| 丰满岳妇乱一区二区三区| 亚洲av永久无码一区二区三区| 成人精品视频一区二区三区不卡| 日韩精品午夜视频一区二区三区| 亚洲AV无码片一区二区三区| 亚洲一区二区三区在线观看蜜桃| 99精品国产高清一区二区三区| 国产精品亚洲产品一区二区三区 | 成人精品一区二区电影| 一区二区三区国产精品| 午夜影视日本亚洲欧洲精品一区| 国产精华液一区二区区别大吗| 日本美女一区二区三区| 日韩毛片一区视频免费| 福利一区二区视频| 日韩免费视频一区| 变态调教一区二区三区| 日本一区二区三区精品国产 | 伊人久久精品一区二区三区| 无码日韩精品一区二区三区免费| 日本不卡一区二区三区视频| 久久综合精品不卡一区二区| 久久久精品人妻一区亚美研究所| 亚洲AV无码一区二区三区DV | 亚洲欧洲精品一区二区三区| 亚洲国产一区在线| 亚洲va乱码一区二区三区| 精品福利视频一区二区三区| 国产精品一区二区毛卡片| 午夜天堂一区人妻| 亚洲熟妇无码一区二区三区导航| 亚洲AV香蕉一区区二区三区| 国产精品一区二区AV麻豆| 国产伦精品一区二区三区视频猫咪| 亚洲视频一区二区| 久久久老熟女一区二区三区| 国产精品日韩欧美一区二区三区| 精品免费AV一区二区三区|