vue面試題總結(jié)

runtime-only 和 runtime-compiler

  1. runtime-only:是運(yùn)行的時候代碼不能包含任意一個template標(biāo)簽

    • render(h)- 》 virtual Dom - 》UI真實dom

    • 我們在使用 Runtime Only 版本的 Vue.js 的時候,通常需要借助如 webpack 的 vue-loader 工具把 .vue 文件編譯成 JavaScript,因為是在編譯階段做的,所以它只包含運(yùn)行時的 Vue.js 代碼,因此代碼體積也會更輕量。 在將 .vue 文件編譯成 JavaScript的編譯過程中會將組件中的template模板編譯為render函數(shù),所以我們得到的是render函數(shù)的版本。所以運(yùn)行的時候是不帶編譯的,編譯是在離線的時候做的。

  1. runtime-compiler:代碼中可以有template標(biāo)簽

    • template加載過程:

      template - 》parse - 》ast 抽象語法樹 - 》compiler - 》render(h)- 》 virtual Dom - 》UI真實dom

總結(jié)對比

最終渲染都是通過 render 函數(shù),如果寫 template 屬性,則需要編譯成 render 函數(shù),那么這個編譯過程會發(fā)生運(yùn)行時,所以需要帶有編譯器的版本。

很顯然,這個編譯過程對性能會有一定損耗,所以通常我們更推薦使用 Runtime-Only 的 Vue.js。

runtime-only比runtime-compiler性能更高,代碼更少(少6kb)

計算屬性和監(jiān)聽屬性和方法的區(qū)別

計算屬性

計算屬性是依賴的值改變會重新執(zhí)行函數(shù),當(dāng)數(shù)據(jù)沒有變化的時候,他會讀取緩存。計算屬性是取返回值作為最新結(jié)果,所以里面不能異步的返回結(jié)果。不能寫異步邏輯。

頁面初次加載的時候,會運(yùn)行計算

計算屬性是對多個屬性進(jìn)行監(jiān)聽,進(jìn)一步整合,執(zhí)行判斷邏輯等,返回結(jié)果作為一個新的屬性,可以綁定在頁面中

監(jiān)聽屬性

偵聽屬性是偵聽的值改變會重新執(zhí)行函數(shù),將一個值重新賦值作為最新結(jié)果,所以賦值的時候可以進(jìn)行一些異步操作。

頁面初次加載的時候,不會執(zhí)行操作

監(jiān)聽屬性 是對單個已存在的data屬性進(jìn)行監(jiān)聽,獲取 oldValue newValue,然后執(zhí)行一些判斷邏輯,比如修改其他值

總結(jié)對比

computed是屬性調(diào)用,而method是函數(shù)調(diào)用

數(shù)據(jù)變化時執(zhí)行異步或者開銷比較大的操作的時候,這時候使用watch是合適的

computed一般是一個依賴值衍生新的值,值結(jié)果會被緩存,除非依賴值發(fā)生變化才會重新計算( eg:購物車結(jié)算 )

watch一般監(jiān)聽一個對象鍵值是需要觀察的變量或者表達(dá)式,鍵值對應(yīng)是回調(diào)函數(shù),主要是負(fù)責(zé)監(jiān)聽某些特定數(shù)據(jù)的變化,從而進(jìn)行某些具體的業(yè)務(wù)邏輯

methods方法表示一個具體的操作,負(fù)責(zé)書寫主要業(yè)務(wù)邏輯

keep-alive

名詞解釋和作用

keep-alive是vue內(nèi)置的組件,自身不會渲染一個DOM元素,Vue在初始化生命周期的時候,為組件實例建立父子關(guān)系會根據(jù)abstract屬性決定是否忽略某個組件。在keep-alive中,設(shè)置了abstract:true,那Vue就會跳過該組件實例。最后構(gòu)建的組件樹中就不會包含keep-alive組件,那么由組件樹渲染成的DOM樹自然也不會有keep-alive相關(guān)的節(jié)點了。

可以是被包含的組件保留狀態(tài),緩存組件實例,不會銷毀,避免重新渲染。

避免組件反復(fù)創(chuàng)建和渲染,有效提升系統(tǒng)性能??偟膩碚f,keep-alive用于保存組件的渲染狀態(tài)。

對應(yīng)的vue組件生命周期 activited和deactivited

屬性說明

include:可以是字符串(組件名稱)或者正則表達(dá)式,只有匹配的組件會被緩存

exclude:可以是字符串(組件名稱)或者正則表達(dá)式,任何匹配的組件都不會被緩存

max:定義緩存組件上限,超出上限使用LRU的策略置換緩存數(shù)據(jù)。

內(nèi)存管理的一種頁面置換算法,對于在內(nèi)存中但又不用的數(shù)據(jù)塊(內(nèi)存塊)叫做LRU,操作系統(tǒng)會根據(jù)哪些數(shù)據(jù)屬于LRU而將其移出內(nèi)存而騰出空間來加載另外的數(shù)據(jù)。

兩個同時使用,若某組件同時被兩個屬性都匹配, exclude 優(yōu)先級較高,最終匹配的組件不會被緩存

keep-alive 源碼解析

路由傳參

路由傳參有4種方式

路由配置表中,路徑后面串聯(lián)傳入的參數(shù)

強(qiáng)制刷新頁面,參數(shù)不會丟失 {path: '/a/:num', name: A, component: A}

 方式1:通過router-link,to屬性 路由地址+傳遞參數(shù)
 <router-link to = "/a/12"> 
  
 方式2:通過path 串聯(lián)路由地址和傳遞的參數(shù)
 this.$router.push({
        path: `/d/${id}`
      })
  方式3:通過命名路由+params 匹配路由配置好的屬性名
  this.$router.push({
        name: 'A',
        params: {
          num: '12'
        }
      })

命名路由+params傳遞參數(shù)

路徑后面不需要加傳入的參數(shù),再次刷新頁面后,參數(shù)會丟失 {path: '/b', name: 'B', component: B}

 this.$router.push({
        name: 'B',
        params: {
          sometext: '一只羊出沒'
        }
      })
      
   獲取參數(shù): {{this.$route.params.sometext}}
   

通過query來傳遞參數(shù)

會顯示在地址,以?開頭串聯(lián)在地址末尾,傳遞多個參數(shù),用“&”隔開,每個參數(shù)的名和值用“=”隔開,強(qiáng)制刷新頁面,參數(shù)不會丟失

 this.$router.push({
        path: '/c',
        query: {
          sometext: '這是小羊同學(xué)'
        }
  獲取參數(shù):{{this.$route.query.sometext}}

傳參注意事項

1.當(dāng)使用path路徑匹配路由時,不能和params不能同時使用,params傳遞的參數(shù)會丟失

2.當(dāng)使用命名路由時name,params和query可以同時使用傳遞參數(shù)

路由懶加載

為什么要懶加載

當(dāng)打包構(gòu)建應(yīng)用時,JavaScript 包會變得非常大,影響頁面加載。

路由中會定義很多不同的頁面,默認(rèn)情況下這些頁面會被打包放在一個js文件中,造成這個js文件非常大,請求耗時會比較久,有可能用戶的電腦還會出現(xiàn)短暫的空白,影響用戶的體驗。

怎么實現(xiàn)懶加載

結(jié)合 Vue 的異步組件 (opens new window)和 Webpack 的代碼分割功能 (opens new window),輕松實現(xiàn)路由組件的懶加載

路由懶加載功能

主要作用就是將路由對應(yīng)的組件打包成一個個的js代碼塊,只有在這個路由被訪問的時候,才加載對應(yīng)的組件

路由懶加載的三種方式

方式1 結(jié)合vue的異步組件和webpack的代碼分析,寫法太復(fù)雜,基本已經(jīng)棄用

const home = resolve => {require.ensure(['../views/Home.vue'],()=>{
resolve(require('../views/Home.vue'))
})}

方式2:AMD寫法,也基本被棄用了

const home = resolve =>require(['../vuews/Home.vue'],resolve);

方式3:在ES6中 有更加簡單的寫法來組織vue異步組件和webpack的代碼分割,強(qiáng)烈推薦

const home = ()=> import('../views/Home.vue')

路由守衛(wèi)

路由守衛(wèi)分為2兩種: 全局守衛(wèi)和局部守衛(wèi)

全局守衛(wèi) :前置守衛(wèi) beforeEatch 和后置鉤子 afterEatch

局部守衛(wèi)包括:路由守衛(wèi)和組件守衛(wèi)

路由守衛(wèi)是配置在路由映射表中,beforeEnter,參數(shù)和beforeEatch一直,優(yōu)先級高于全局守衛(wèi)

組件守衛(wèi)是定義在組件中的鉤子函數(shù) beforeRouterEnter , beforeRouterUpdate, beforeRouterLevel

beforeRouterEnter 中不能使用this,因為還沒有創(chuàng)建好組件。

beforeRouterUpdate 是當(dāng)路由地址沒有改變,但是參數(shù)改變的時候,才會被調(diào)用,比如 /a/1 => /a/2

beforeEatch((to,from,next)={ 

})
beforeEatch是一個函數(shù),里面的參數(shù)是一個箭頭函數(shù),to和from 都是route對象實例,next和函數(shù),必須要調(diào)用,所以不會執(zhí)行路由不會跳轉(zhuǎn)
通常用全局的守衛(wèi)來監(jiān)聽路由跳轉(zhuǎn),執(zhí)行一些全局的操作,比如標(biāo)題。

路由導(dǎo)航

所有的組件都繼承自vue的原型,在vue原型vue.prototype 上定義的函數(shù)和屬性,子組件可以通過this. 直接調(diào)用,

比如**this.$router 和this.$route**
this.$router 指向的路由映射表,VueRouter實例,可以導(dǎo)航到不同的url,
this.$router.push(),this.$router.replace,對應(yīng)的history中的pushState和replaceState

this.$route 指向的是路由映射表中的一個路由選項,代表當(dāng)前跳轉(zhuǎn)的路由,可以獲取當(dāng)前路由的name,path,query,params等

Es6新特性

1.不一樣的變量聲明:const和let,ES6推薦使用let聲明局部變量

let表示聲明變量,而const表示聲明常量,兩者都為塊級作用域;const 聲明的變量都會被認(rèn)為是常量,意思就是它的值被設(shè)置完成后就不能再修改了

如果const的是一個對象,對象所包含的值是可以被修改的。抽象一點兒說,就是對象所指向的地址沒有變就行

let 關(guān)鍵詞聲明的變量不具備變量提升(hoisting)特性,不能先使用,再聲明。var具備變量提升

let 和 const 聲明只在最靠近的一個塊中(花括號內(nèi))有效

當(dāng)使用常量 const 聲明時,請使用大寫變量,如:CAPITAL_CASING

const 在聲明時必須被賦值

2.模板字符串

在ES6之前,我們往往通過“\”和“+”來構(gòu)建模板

es6可以將表達(dá)式嵌入字符串中進(jìn)行拼接。用${}來界定;

ES6反引號(``)直接搞定;

  1. $("body").html(`This demonstrates the output of HTML content to the page, 
    including student's ${name}, ${seatNumber}, ${sex} and so on.`);
    

3.箭頭函數(shù)(Arrow Functions)

ES6 中,箭頭函數(shù)就是函數(shù)的一種簡寫形式,使用括號包裹參數(shù),跟隨一個 =>,緊接著是函數(shù)體;

箭頭函數(shù)最直觀的三個特點。

  • 不需要 function 關(guān)鍵字來創(chuàng)建函數(shù)
  • 省略 return 關(guān)鍵字
  • 繼承當(dāng)前上下文的 this 關(guān)鍵字
  • 當(dāng)你的函數(shù)有且僅有一個參數(shù)的時候,是可以省略掉括號的。當(dāng)你函數(shù)返回有且僅有一個表達(dá)式的時候可以省略{} 和 return;

4.函數(shù)參數(shù)默認(rèn)值

// ES6之前,當(dāng)未傳入?yún)?shù)時,
text = 'default'; 
function printText(text) {
    text = text || 'default';   
   console.log(text);
}
// ES6;
function printText(text = 'default') {    
 console.log(text);
}
printText('hello'); // helloprintText();// default

5.二進(jìn)制和八進(jìn)制字面量

ES6 支持二進(jìn)制和八進(jìn)制的字面量,通過在數(shù)字前面添加 0o 或者0O 即可將其轉(zhuǎn)換為八進(jìn)制值:

let oValue = 0o10;console.log(oValue); // 8 let bValue = 0b10; // 二進(jìn)制使用 `0b` 或者 `0B`console.log(bValue); // 2

6.模塊化 export 和 import

import 導(dǎo)入模塊、export 導(dǎo)出模塊

可以直接在任何變量或者函數(shù)前面加上一個 export 關(guān)鍵字,就可以將它導(dǎo)出。

let var 和const區(qū)別

在javascript中有三種聲明變量的方式:var、let、const。

JS中作用域有:全局作用域、函數(shù)作用域。沒有塊作用域的概念。ECMAScript 6(簡稱ES6)中新增了塊級作用域。****塊作用域由 { } 包括,if語句和for語句里面的{ }也屬于塊作用域。

var

var定義的變量可以修改,如果不初始化會輸出undefined,不會報錯。

var 聲明全局變量,換句話理解就是,聲明在for循環(huán)中的變量,跳出for循環(huán)同樣可以使用。

let

同一個變量,不可在聲明之前調(diào)用,必須先定義再使用,否則會報錯,循環(huán)體中可以用let

let是塊級作用域,函數(shù)內(nèi)部使用let定義后,對函數(shù)外部無影響。并且let不能定義同名變量,否則會報錯。

cosnt

const:用于聲明常量,也具有塊級作用域 ,也可聲明塊級。const定義的變量不可以修改,而且必須初始化。

如果const的是一個對象,對象所包含的值是可以被修改的。抽象一點兒說,就是對象所指向的地址沒有變就行

它和let一樣,也不能重復(fù)定義同一個變量,const一旦定義,無法修改.

let和const屬于局部變量,不會出現(xiàn)變量提升的情況,

全局定義的let和const變量,不屬于頂層變量,不屬于window的屬性,

瀏覽器環(huán)境中頂層對象是window,Node中是global對象

es5中頂層變量的屬性等價于全局變量,定義的var變量是window屬性

到了es6中有所改變,es5的var ,function 聲明的全局變量 依舊是頂級對象的屬性 而es6聲明的全局變量不屬于頂級對象的屬性了

var age = 29;
let ages = 29;
alert(window.age)  ==>29
alert(window.ages ) ==>undefined

axios配置

 //安裝axios
 npm install axios 

Axios 是一個基于 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中??梢詧?zhí)行g(shù)et請求,執(zhí)行post請求,執(zhí)行多個并發(fā)請求,支持promise ,攔截請求和響應(yīng),轉(zhuǎn)換請求數(shù)據(jù)和響應(yīng)數(shù)據(jù),取消請求 ,自動轉(zhuǎn)換json數(shù)據(jù)。

1.支持node端和瀏覽器端

同樣的API,node和瀏覽器全支持,平臺切換無壓力

2.支持 Promise

使用Promise管理異步,告別傳統(tǒng)callback方式

3.豐富的配置項

支持?jǐn)r截器等高級配置

常用的請求配置

method:請求方法 post get delete put等
baseUrl:請求基本路徑地址,將自動加在 `url` 前面
url:請求地址
headers:自定義請求頭參數(shù),可以包含token,content-type等
timeout:配置請求超時
params: 是即將與請求一起發(fā)送的 URL 參數(shù)

添加攔截器

// 添加請求攔截器
axios.interceptors.request.use(
   function (response) {    // 對請求數(shù)據(jù)做點什么    return response;  },
 function (error) {    // 對請求錯誤做點什么    return Promise.reject(error);  }
);
// 添加響應(yīng)攔截器
axios.interceptors.response.use(
 function (response) {    // 對響應(yīng)數(shù)據(jù)做點什么    return response;  },
 function (error) {    // 對響應(yīng)錯誤做點什么    return Promise.reject(error);  }
);

創(chuàng)建axios實例

function createAxios(type){
    let timeout = 20000; //統(tǒng)一的超時時間
    var token = null;
    if (userInfo.token()) {
        token = userInfo.token();
    }
    let applicationHeaderPayload = {
        'Content-Type': 'application/json; charset=utf-8',
        'token':token,
        'platform': "H5",
        'Accept': '*/*'
    }
    let applicationHeader = {
        'Content-Type': 'application/x-www-form-urlencoded', 
        'token':token,
        'platform': "H5",
        'Accept': '*/*'
    }; 
    let args = {}; //配置參數(shù)
    let axiosInstance; //axios 實例
    switch(type){
        case "payload" :
            args = {
                timeout,
                "headers": applicationHeaderPayload
            };
            break;
        case "formData" :
            args = {
                timeout,
                "headers" : applicationHeader
            };
            break;
        default :
            break;
    }
    axiosInstance = axios.create(args);
    axiosInstance.interceptors.request.use (function (config) { //請求攔截器
        var token = null;
        if (userInfo.token()) {
            token = userInfo.token();
        }
        config.url = baseUrl+config.url;
        config.headers = {
            'Content-Type': 'application/json; charset=utf-8',
            'token':token,
            'platform': "H5",
            'Accept': '*/*'
        }
        if(config && config.data && ['formData'].indexOf(type) != -1){
            config.data = qs.stringify(config.data);
            config.headers = {
                'Content-Type': 'application/x-www-form-urlencoded', 
                'token':token,
                'platform': "H5",
                'Accept': '*/*'
            }
        }
        return config;
    }, function (error) {
        return Promise.reject(error);
    });
    axiosInstance.interceptors.response.use(function (response) { //返回攔截器
        return handleSuccess(response);
    }, function (data) {
        return handleError(data);
    });
    return axiosInstance;
}

vue-router兩種加載模式

1. Hash (對應(yīng)HashHistory)

hash(“#”)符號的本來作用是加在URL中指示網(wǎng)頁中的位置:

http://www.example.com/index.html#print

符號本身以及它后面的字符稱之為hash(也就是我之前為什么地址欄都會有一個‘#’),可通過window.location.hash屬性讀取。它具有如下特點:

  1. hash雖然出現(xiàn)在URL中,但不會被包括在HTTP請求中。它是用來指導(dǎo)瀏覽器動作的,對服務(wù)器端完全無用,因此,改變hash不會重新加載頁面

2.可以為hash的改變添加監(jiān)聽事件:

window.addEventListener("hashchange", funcRef, false)
  1. 每一次改變hash(window.location.hash),都會在瀏覽器的訪問歷史中增加一個記錄

利用hash的以上特點,就可以來實現(xiàn)前端路由“更新視圖但不重新請求頁面”的功能了。

2. History (對應(yīng)HTML5History)

History接口是瀏覽器歷史記錄棧提供的接口,通過back(), forward(), go()等方法,我們可以讀取瀏覽器歷史記錄棧的信息,進(jìn)行各種跳轉(zhuǎn)操作。

從HTML5開始,History interface提供了兩個新的方法:pushState(), replaceState()使得我們可以對瀏覽器歷史記錄棧進(jìn)行修改:

window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)

stateObject: 當(dāng)瀏覽器跳轉(zhuǎn)到新的狀態(tài)時,將觸發(fā)popState事件,該事件將攜帶這個stateObject參數(shù)的副本
title: 所添加記錄的標(biāo)題
URL: 所添加記錄的URL

這兩個方法有個共同的特點:當(dāng)調(diào)用他們修改瀏覽器歷史記錄棧后,雖然當(dāng)前URL改變了,但瀏覽器不會刷新頁面,這就為單頁應(yīng)用前端路由“更新視圖但不重新請求頁面”提供了基礎(chǔ)。
瀏覽器歷史記錄可以看作一個「?!?。棧是一種后進(jìn)先出的結(jié)構(gòu),可以把它想象成一摞盤子,用戶每點開一個新網(wǎng)頁,都會在上面加一個新盤子,叫「入?!埂?br> 用戶每次點擊「后退」按鈕都會取走最上面的那個盤子,叫做「出?!?。而每次瀏覽器顯示的自然是最頂端的盤子的內(nèi)容。

vue-router 的作用

vue-router的作用就是通過改變URL,在不重新請求頁面的情況下,更新頁面視圖。簡單的說就是,雖然地址欄的地址改變了,但是并不是一個全新的頁面,而是之前的頁面某些部分進(jìn)行了修改。

export default new Router({ 
  mode: 'history', //后端支持可開
  routes: constantRouterMap})

這是Vue項目中常見的一段初始化vue-router的代碼,mode屬性用來指定vue-router使用哪一種模式。在沒有指定mode的值,則使用hash模式。

vue-router路由模式有幾種?請談?wù)勀銓λ鼈兊睦斫猓?/h4>

常用的路由模式有hash和history;
最直觀的區(qū)別是hash模式url上會攜帶有一個#,而history不攜帶;

hash:

即地址欄URL中的#符號,它的特點在于hash值雖然出現(xiàn)在URL中,但不會被包括在HTTP請求中,對服務(wù)端完全沒影響,因此改變hash值不會重新加載頁面。

history:

利用了HTML5 History interface 中新增的pushState() 和 replaceState()方法。
這兩個方法應(yīng)用于瀏覽器歷史記錄棧,提供了修改歷史記錄的功能,執(zhí)行修改時雖然改變了URL但是不會立即的向服務(wù)端發(fā)起請求。

hash和history模式都屬于瀏覽器自身的特性,vue-router只是利用了這兩個特性來實現(xiàn)前端路由
但是在history模式下會出現(xiàn)刷新404的問題,對于這個問題,我們只需要在服務(wù)器配置nginx如果URL匹配不到任何靜態(tài)資源,就跳轉(zhuǎn)到默認(rèn)的index.html

history.pushState()相比于直接修改hash主要有以下優(yōu)勢:

  1. pushState設(shè)置的新URL可以是與當(dāng)前URL同源的任意URL;而hash只可修改#后面的部分,故只可設(shè)置與當(dāng)前同文檔的URL
  2. pushState設(shè)置的新URL可以與當(dāng)前URL一模一樣,這樣也會把記錄添加到棧中;而hash設(shè)置的新值必須與原來不一樣才會觸發(fā)記錄添加到棧中
  3. pushState通過stateObject可以添加任意類型的數(shù)據(jù)到記錄中;而hash只可添加短字符串
  4. pushState可額外設(shè)置title屬性供后續(xù)使用

v-if 和 show的區(qū)別

相同點:v-if與v-show都可以動態(tài)控制dom元素顯示隱藏
不同點:v-if顯示隱藏是將dom元素整個添加或刪除,而v-show隱藏則是為該元素添加css--display:none,dom元素還在。

組件通信的方法

父子組件通信

1.props 父組件向子組件傳遞數(shù)據(jù) ,$emit 子組件觸發(fā)父組件事件響應(yīng)

2.$children 和 $refs 獲取子組件實例對象,$parent或者$root 獲取父組件或者根組件實例對象。拿到實例對象可以直接操作data數(shù)據(jù)或者調(diào)用函數(shù),但是一般不推薦,耦合度太高

$children 和 $refs 獲取子組件實例對象 這兩個的區(qū)別:
 ref可以指定任意的dom元素節(jié)點,包括原生HTML元素,children 獲取的是包含自定義子組件實例列表,并且是無序的

3.通過vuex 或者localStorage 保存數(shù)據(jù),進(jìn)行數(shù)據(jù)傳遞

4.多級組件嵌套需要傳遞數(shù)據(jù)時, Vue2.4 版本提供了另一種方法----$attrs/$listeners

5.  provide/inject,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在起上下游關(guān)系成立的時間里始終生效。
祖先組件中通過 provider 來提供變量,然后在子孫組件中通過 inject 來注入變量。

provide / inject API 主要解決了跨級組件間的通信問題,不過它的使用場景,主要是子組件獲取上級組件的狀態(tài),跨級組件間建立了一種主動提供與依賴注入的關(guān)系。

需要注意的是:**provide 和 inject 綁定并不是可響應(yīng)的**。這是刻意為之的。然而,如果你傳入了一個可監(jiān)聽的對象,那么其對象的屬性還是可響應(yīng)的----vue 官方文檔

所以,上面 A.vue 的 name 如果改變了,B.vue 的 this.name 是不會改變的,為了解決這種問題,可以把祖先組件的this實例傳遞provide過去,然后子組件通過this 獲取需要的參數(shù)。耦合度太高

組件通信常見使用場景可以分為三類:

**父子通信:**
  父向子傳遞數(shù)據(jù)是通過 props,子向父是通過 events($emit);
  通過父鏈 / 子鏈也可以通信($parent / $children);ref 也可以訪問組件實例;
  provide / inject API;$attrs/$listeners

 ** 兄弟通信:**
  Bus;Vuex;localStorage

  **跨級通信:**
  Bus;Vuex;localStorage;provide / inject API;$attrs/$listeners

詳細(xì)解析

vue 自定義指令

自定義指令
Vue 內(nèi)置了一些非常有用的指令(比如v-html 和 v-once等),每個指令都有自身的用途
Vue 也允許注冊自定義指令。它的作用價值在于當(dāng)開發(fā)人員在某些場景下需要對普通 DOM 元素進(jìn)行操作。
Vue 自定義指令有全局注冊和局部注冊兩種方式。先來看看注冊全局指令的方式,
通過 Vue.directive( id, [definition] ) 方式注冊全局指令。然后在入口文件中進(jìn)行 Vue.use() 調(diào)用。

當(dāng)頁面加載時,該元素將獲得焦點 (注意:autofocus 在移動版 Safari 上不工作)。事實上,只要你在打開這個頁面后還沒點擊過任何內(nèi)容,這個輸入框就應(yīng)當(dāng)還是處于聚焦?fàn)顟B(tài)?,F(xiàn)在讓我們用指令來實現(xiàn)這個功能:

注冊一個全局自定義指令 v-focus

Vue.directive('focus', {
  // 當(dāng)被綁定的元素插入到 DOM 中時……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

如果想注冊局部指令,組件中也接受一個 directives 的選項:

directives: {
  focus: {
    // 指令的定義
    inserted: function (el) {
      el.focus()
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus property,如下:<input v-focus>

vue常用內(nèi)置指令

v-model
v-for
v-text
v-html
v-on
v-bind
v-if/v-else
v-show

1.vuex是什么?怎么使用?哪種功能場景使用它

Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。簡單來說就是:應(yīng)用遇到多個組件共享狀態(tài)時,使用vuex。
場景:多個組件共享數(shù)據(jù)或者是跨組件傳遞數(shù)據(jù)時

vuex的流程

頁面通過mapAction異步提交事件到action。action通過commit把對應(yīng)參數(shù)同步提交到mutation,mutation會修改state中對應(yīng)的值。最后通過getter把對應(yīng)值跑出去,在頁面的計算屬性中,通過,mapGetter來動態(tài)獲取state中的值
在vue組件中可以直接通過this.$store 來操作

vuex有哪幾種屬性

有五種,分別是State , Getter , Mutation , Action , Module (就是mapAction)

  1. state:vuex的基本數(shù)據(jù),用來存儲變量
  2. geeter:從基本數(shù)據(jù)(state)派生的數(shù)據(jù),相當(dāng)于state的計算屬性,對state數(shù)據(jù)進(jìn)行封裝轉(zhuǎn)換之后再輸出
  3. mutation:提交更新數(shù)據(jù)的方法,必須是同步的(如果需要異步使用action)。每個mutation 都有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)?;卣{(diào)函數(shù)就是我們實際進(jìn)行狀態(tài)更改的地方,并且它會接受 state 作為第一個參數(shù),提交載荷作為第二個參數(shù)。
  4. action:和mutation的功能大致相同,不同之處在于 ==》1. Action 提交的是 mutation,而不是直接變更狀態(tài)。 2. Action 可以包含任意異步操作。
  5. modules:模塊化vuex,可以讓每一個模塊擁有自己的state、mutation、action、getters,使得結(jié)構(gòu)非常清晰,方便管理。
  6. actions與mutations作用類似,都是可以對狀態(tài)進(jìn)行修改。不同的是actions是異步操作的。actions是可以調(diào)用Mutations里的方法的。
    dispatch:異步操作,寫法: this.store.dispatch('actions方法名',值) commit:同步操作,寫法:this.store.commit('mutations方法名',值)

Vuex中actions和mutations的區(qū)別

Mutation 更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation
Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)。這個回調(diào)函數(shù)就是我們實際進(jìn)行狀態(tài)更改的地方,并且它會接受 state 作為第一個參數(shù)
Action Action 類似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接變更狀態(tài)。
  • Action 可以包含任意異步操作。 .

什么是mvvm模式,談?wù)勀愕睦斫猓?/h3>
MVVM - Model View ViewModel,數(shù)據(jù),視圖,視圖模型
view 可以通過 事件綁定 的方式影響 model
model 可以通過 數(shù)據(jù)綁定 的形式影響到view,
viewModel是把 model 和 view 連起來的橋梁,這樣就實現(xiàn)了數(shù)據(jù)的雙向綁定。

請談?wù)勀銓ue.js 生命周期的理解?

1.什么是vue.js的生命周期:Vue 實例有一個完整的生命周期,也就是從開始創(chuàng)建、初始化數(shù)據(jù)、編譯模版、掛載 Dom -> 渲染、更新 -> 渲染、卸載等一系列過程,我們稱這是 Vue 的生命周期。

2.各個生命周期的作用


1111.jpg

為什么vue中組件里面的data是一個函數(shù)而不是一個對象呢?

因為組件可能被用來創(chuàng)建多個實例,如果data仍然是一個純粹的對象,則所有的實例將共享引用一個數(shù)據(jù)對象,通過提供data函數(shù),每次創(chuàng)建一個新的實例之后,我們能夠調(diào)用data函數(shù)從而返回一個全新的副本數(shù)據(jù)對象,這樣每一個實例都有自己私有的數(shù)據(jù)空間不會互相影響

vue事件修飾符以及各個的作用?

.stop:阻止事件冒泡
.native:綁定原生事件
.once:事件只執(zhí)行一次
.self 將事件綁定在自身身上,相當(dāng)于阻止事件冒泡
.prevent:阻止默認(rèn)事件
.passive: 2.3.0 新增,滾動事件的默認(rèn)行為 (即滾動行為) 將會立即觸發(fā),不能和.prevent 一起使用

vue如何優(yōu)化頁面加載?

1.UI組件庫盡量使用cdn的方式引入,或者下載本地通過js文件引入;
2.配置路由懶加載的方式;
3.增加loading圖,提升用戶體驗

父組件和子組件生命周期執(zhí)行的順序?

1.加載渲染過程:

父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate
-> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

2.子組件更新過程:

父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

3.父組件更新過程:

父 beforeUpdate -> 父 updated

4.銷毀過程:

父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

獲取dom節(jié)點的方式

案例解析
DOM 是一個樹形結(jié)構(gòu),操作一個DOM節(jié)點,實際上就是這幾個操作:更新、刪除、添加、遍歷
在操作DOM節(jié)點之前,需要通過各種方式先拿到這個DOM節(jié)點,常用的方法有:

一、通過元素類型的方法來操作:

  1. document.getElementById();//id名,在實際開發(fā)中較少使用,選擇器中多用class id一般只用在頂級層存在 不能太過依賴id
  2. document.getElementsByTagName();//標(biāo)簽名
  3. document.getElementsByClassName();//類名
  4. document.getElementsByName();//name屬性值,一般不用
  5. document.querySelector();//css選擇符模式,返回與該模式匹配的第一個元素,結(jié)果為一個元素;如果沒找到匹配的元素,則返回null
  6. document.querySelectorAll()//css選擇符模式,返回與該模式匹配的所有元素,結(jié)果為一個類數(shù)組

二、根據(jù)關(guān)系樹來選擇(遍歷節(jié)點樹):

【先簡單介紹一下節(jié)點:
DOM(文檔對象模型)可以將任何HTML、XML文檔描繪成一個多層次的節(jié)點樹。所有的頁面都表現(xiàn)為以一個特定節(jié)點為根節(jié)點的樹形結(jié)構(gòu)。html文檔中根節(jié)點為document節(jié)點。

所有節(jié)點都有nodeType屬性,代表節(jié)點的不同類型,通過nodeType屬性可以來判斷節(jié)點的類型。經(jīng)常使用的節(jié)點主要有以下幾種類型:

Element類型(元素節(jié)點):nodeType值為 1
Text類型(文本節(jié)點):nodeType值為 3
Comment類型(注釋節(jié)點):nodeType值為 8
Document類型(document節(jié)點):nodeType值為 9;其規(guī)定的一些常用的屬性有
document.body    document.head  分別為HTML中的 <body><head>
document.documentElement為<html>標(biāo)簽

所有的節(jié)點都有 hasChildNodes()方法 判斷有無子節(jié)點 有一個或多個子節(jié)點時返回true】

通過一些屬性可以來遍歷節(jié)點樹:
parentNode//獲取所選節(jié)點的父節(jié)點,最頂層的節(jié)點為#document
childNodes //獲取所選節(jié)點的子節(jié)點們
firstChild //獲取所選節(jié)點的第一個子節(jié)點
lastChild //獲取所選節(jié)點的最后一個子節(jié)點
nextSibling //獲取所選節(jié)點的后一個兄弟節(jié)點 列表中最后一個節(jié)點的nextSibling屬性值為null
previousSibling //獲取所選節(jié)點的前一兄弟節(jié)點 列表中第一個節(jié)點的previousSibling屬性值為null
由于文檔中的節(jié)點類型較多,遍歷子節(jié)點的結(jié)果很多時候并不能得到我們想要的結(jié)果,使用遍歷元素節(jié)點則很方便

三、基于元素節(jié)點樹的遍歷(遍歷元素節(jié)點樹):

parentElement //返回當(dāng)前元素的父元素節(jié)點(IE9以下不兼容)
children  // 返回當(dāng)前元素的元素子節(jié)點
firstElementChild //返回的是第一個元素子節(jié)點(IE9以下不兼容)
lastElementChild  //返回的是最后一個元素子節(jié)點(IE9以下不兼容)
nextElementSibling  //返回的是后一個兄弟元素節(jié)點(IE9以下不兼容)
previousElementSibling  //返回的是前一個兄弟元素節(jié)點(IE9以下不兼容)

vue獲取dom節(jié)點

在vue項目中,獲取dom節(jié)點可以用ref屬性,這個屬性就是來獲取dom對象的。

<template>
    <div class="contaier" ref="box" style="width: 100px;height: 100px;">
        這里用來測試元素的ref屬性
    </div>
    <button type="button" @click="showData()">點擊</button>
</template>

<script>
    export default {
        methods: {
            showData() {
                console.log(this.$refs.box);
                console.log(this.$refs.box.style);
            }
        }
    }
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • <meta charset="utf-8" 看看面試題,只是為了查漏補(bǔ)缺,看看自己那些方面還不懂。切記不要以為背了...
    hcySam閱讀 1,337評論 0 9
  • 看看面試題,只是為了查漏補(bǔ)缺,看看自己那些方面還不懂。切記不要以為背了面試題,就萬事大吉了,最好是理解背后的原理,...
    lessonSam閱讀 591評論 0 6
  • 前端面試題總結(jié)[http://m.itdecent.cn/p/4e69d9769966]JavaScript...
    程序小小黑閱讀 931評論 0 18
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,900評論 28 54
  • 信任包括信任自己和信任他人 很多時候,很多事情,失敗、遺憾、錯過,源于不自信,不信任他人 覺得自己做不成,別人做不...
    吳氵晃閱讀 6,394評論 4 8

友情鏈接更多精彩內(nèi)容