国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【直接收藏】前端 VUE 高階面試題(二)

這篇具有很好參考價值的文章主要介紹了【直接收藏】前端 VUE 高階面試題(二)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

44.vuex的數(shù)據(jù)丟失知道嗎 怎么解決

原理:可以利用緩存,將vuex中的state,在緩存中備份一下,當狀態(tài)發(fā)生改變時,同步緩存的的備份。同時當刷新時,去緩存中的備份,給state賦值

實際開發(fā)中我們一般利用vuex一個插件來實現(xiàn) vuex-persistedstate

具體代碼如下

安裝

npm i vuex-persistedstate -S

使用

import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate";


const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()],
});

45.vuex怎么拿數(shù)據(jù)

獲取vuex state中的count數(shù)據(jù)方法有

方法1:this.$store.state.count 直接使用;

方法2:`import { mapState } from vuex `


  然后把`...mapState('count')放入computed中`,然后直接使用count變量。

獲取vuex getters中g(shù)etCount數(shù)據(jù)的方法

方法1:this.$store.getters.getCount直接使用。

  方法2:`import { mapGetters } from vuex `


  然后把`...mapGetters ('getCount')放入computed中`,然后直接使用getCount變量。

46.說說Vuex原理

  vuex 是一個專門為 vue 構(gòu)建的狀態(tài)管理工具,主要是為了解決 多組間之間狀態(tài)共享問題。強調(diào)的是集中式管理,(組件與組件之間的關(guān)系變成了組件與倉庫之間的關(guān)系)

  vuex 的核心包括:state(存放狀態(tài))、mutations(同步的更改狀態(tài))、actions(發(fā)送異步請求,拿到數(shù)據(jù))、getters(根據(jù)之前的狀態(tài)派發(fā)新的狀態(tài))、modules(模塊劃分)  state 發(fā)布一條新的數(shù)據(jù),在 getters 里面根據(jù)狀態(tài)派發(fā)新的狀態(tài),actions 發(fā)送異步請求獲取數(shù)據(jù),然后在 mutations 里面同步的更改數(shù)據(jù)  應用場合:購物車的數(shù)據(jù)共享、登入注冊

47.vuex倉庫數(shù)據(jù)很多,怎么管理

使用moduls模塊劃分和文件拆分來管理數(shù)據(jù)很多的問題。例如:我們可以在modules中進行模塊劃分,比如用戶相關(guān)模塊放入user中,文章信息相關(guān)模塊放入article中。

代碼如下:

modules:{
         user:{ //跟用戶相關(guān)的數(shù)據(jù)放這
            state:{


            },
            geeters:{


            },
            mutations:{


            },
            actions:{


            },
        },
         article:{ //跟文章相關(guān)的保存在這里
            state:{


            },
            geeters:{


            },
            mutations:{


            },
            actions:{


            },
        }   
}        

48.vuex做數(shù)據(jù)集中管理,mutations和actions分別是做什么的,為什么不能用mutations處理異步數(shù)據(jù)

mutations和actions分別是做什么的?

mutations和action都是用來改變Vuex store的狀態(tài)的;mutations提供的回調(diào)函數(shù)是同步的;而actions提供的方法是異步的,此外,actions的方法最終還是通過調(diào)用mutations的方法來實現(xiàn)修改vuex的狀態(tài)的。

為什么不能用mutations處理異步數(shù)據(jù)?

官方文檔說明:“在 mutation 中混合異步調(diào)用會導致你的程序很難調(diào)試。例如,當你能調(diào)用了兩個包含異步回調(diào)的 mutation 來改變狀態(tài),你怎么知道什么時候回調(diào)和哪個先回調(diào)呢?這就是為什么我們要區(qū)分這兩個概念。在 Vuex 中,我們將全部的改變都用同步方式實現(xiàn)。我們將全部的異步操作都放在Actions中?!?/p>

actions 和 mutations 并不是為了解決競態(tài)問題,而是為了能用 devtools 追蹤狀態(tài)變化。事實上在 vuex 里面 actions 只是一個架構(gòu)性的概念,并不是必須的,說到底只是一個函數(shù),你在里面想干嘛都可以,只要最后觸發(fā) mutation 就行。異步競態(tài)怎么處理那是用戶自己的事情。vuex 真正限制你的只有 mutation 必須是同步的這一點(在 redux 里面就好像 reducer 必須同步返回下一個狀態(tài)一樣)。同步的意義在于這樣每一個 mutation 執(zhí)行完成后都可以對應到一個新的狀態(tài)(和 reducer 一樣),這樣 devtools 就可以打個 snapshot 存下來,然后就可以隨便 time-travel 了。如果你開著 devtool 調(diào)用一個異步的 action,你可以清楚地看到它所調(diào)用的 mutation 是何時被記錄下來的,并且可以立刻查看它們對應的狀態(tài)。其實我有個點子一直沒時間做,那就是把記錄下來的 mutations 做成類似 rx-marble 那樣的時間線圖,對于理解應用的異步狀態(tài)變化很有幫助。

49.vuex中actions與mutations的區(qū)別

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

Action Action 類似于 mutation,不同在于:Action 提交的是 mutation,而不是直接變更狀態(tài)。Action 可以包含任意異步操作。總體來說:actions 1、用于通過提交mutation改變數(shù)據(jù) 2、會默認將自身封裝為一個Promise 3、可以包含任意的異步操作mutations 1、通過提交commit改變數(shù)據(jù) 2、只是一個單純的函數(shù) 3、不要使用異步操作,異步操作會導致變量不能追蹤

50.說說vue如何進行路由配置

一、安裝

本地環(huán)境安裝路由插件vue-router: cnpm install vue-router --save-dev

二、配置兩種配置方法:在main.js中 || 在src/router文件夾下的index.js中這里只說在src/router/index.js中的 1.引入 import Vue from 'vue' import Router from 'vue-router' 注意這個Router是自定義的名字,這里叫這個名字后,下邊都要用到的

  1. 使用/注冊:Vue.use(Router)
  2. 配置配置路由:
  3. export default new Router({
    routes: [
    {
    path : ‘/’, //到時候地址欄會顯示的路徑
    name : ‘Home’,
    component : Home // Home是組件的名字,這個路由對應跳轉(zhuǎn)到的組件。。注意component沒有加“s”.
    },
    {
    path : ‘/content’,
    name : ‘Content’,
    component : Content
    }
    ],
    mode: "history"
    })
  4. 引入路由對應的組件地址:import Home from '@/components/Home'import Home from '@/components/Content’
  5. 在main.js中調(diào)用index.js的配置:import router from './router'
  6. App.vue頁面使用(展示)路由:<!-- 展示router -->
  7. 把這個標簽放到對應位置: <router-view></router-view>
  8. 路由切換(原來的<a href="XXX.html">等地方):把切換標簽和鏈接改成:<router-link to="/">切換到Home組件</router-link><router-link to="/content">切換到Content組件</router-link>//這里,to里邊的參數(shù)和配置時,path的路徑一樣即可

51.談談Vue路由守衛(wèi)

1、路由守衛(wèi) 是什么

簡單來說,導航守衛(wèi)就是路由跳轉(zhuǎn)前、中、后過程中的一些鉤子函數(shù),這個函數(shù)能讓你操作一些其他的事兒,這就是導航守衛(wèi)。官方解釋,vue-router提供的導航守衛(wèi)主要用來通過跳轉(zhuǎn)或取消的方式守衛(wèi)導航。

2、路由守衛(wèi)分類導航守衛(wèi)分為:全局的、組件內(nèi)的、單個路由獨享三種

52.路由守衛(wèi)中頁面跳轉(zhuǎn)運用了哪些鉤子函數(shù)

應用場景1:可進行一些頁面跳轉(zhuǎn)前處理,例如判斷需要登錄的頁面進行攔截,做登錄跳轉(zhuǎn)??!

router.beforeEach((to, from, next) => {
    if (to.meta.requireAuth) {
        //判斷該路由是否需要登錄權(quán)限
        if (cookies('token')) {
            //通過封裝好的cookies讀取token,如果存在,name接下一步如果不存在,那跳轉(zhuǎn)回登錄頁
            next()//不要在next里面加"path:/",會陷入死循環(huán)
        }
        else {
            next({
                path: '/login',
                query: {redirect: to.fullPath}//將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由
            })
        }
    }
    else {
        next()
    }
})

應用場景2,進入頁面登錄判斷、管理員權(quán)限判斷、瀏覽器判斷

//使用鉤子函數(shù)對路由進行權(quán)限跳轉(zhuǎn)
router.beforeEach((to, from, next) => {
    const role = localStorage.getItem('ms_username');
    if(!role && to.path !== '/login'){
        next('/login');
    }else if(to.meta.permission){
        // 如果是管理員權(quán)限則可進入,這里只是簡單的模擬管理員權(quán)限而已
        role === 'admin' ? next() : next('/403');
    }else{
        // 簡單的判斷IE10及以下不進入富文本編輯器,該組件不兼容
        if(navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor'){
            Vue.prototype.$alert('vue-quill-editor組件不兼容IE10及以下瀏覽器,請使用更高版本的瀏覽器查看', '瀏覽器不兼容通知', {
                confirmButtonText: '確定'
            });
        }else{
            next();
        }
    }
})

應用場景3:當頁面中有未關(guān)閉的窗口, 或未保存的內(nèi)容時, 阻止頁面跳轉(zhuǎn)

beforeRouteLeave (to, from, next) {
 //判斷是否彈出框的狀態(tài)和保存信息與否
 if (this.dialogVisibility === true) {
    this.dialogVisibility = false //關(guān)閉彈出框
    next(false) //回到當前頁面, 阻止頁面跳轉(zhuǎn)
  }else if(this.saveMessage === false) {
    alert('請保存信息后退出!') //彈出警告
    next(false) //回到當前頁面, 阻止頁面跳轉(zhuǎn)
  }else {
    next() //否則允許跳轉(zhuǎn)
  }

53.談談Vue路由模式,路由有哪些模式

在vue-router路由對象中,路由有兩種模式:hash和history,而默認的是hash模式.前端路由目前主要有兩種方法:

1、利用url的hash,就是常用的錨點(#)操作,類似頁面中點擊某小圖標,返回頁面頂部,JS通過hashChange事件來監(jiān)聽url的改變,IE7及以下需要輪詢進行實現(xiàn)。一般常用框架的路由機制都是用的這種方法,例如Angualrjs自帶的ngRoute和二次開發(fā)模塊ui-router,react的react-route,vue-route…

2、利用HTML5的History模式,使url看起來類似普通網(wǎng)站,以”/”分割,沒有”#”,但頁面并沒有跳轉(zhuǎn),不過使用這種模式需要服務器端的支持,服務器在接收到所有的請求后,都指向同一個html文件,通過historyAPI,監(jiān)聽popState事件,用pushState和replaceState來實現(xiàn)。

54.路由守衛(wèi)的作用,全局和局部使用的差異是什么

全局路由守衛(wèi):就是在整個網(wǎng)頁中,只要發(fā)生了路由的變化,都會觸發(fā)。全局導航守衛(wèi)主要包括兩個函數(shù),分別為:beforeEach、afterEach。局部路由守衛(wèi):(組件內(nèi)的守衛(wèi))只有當前路由使用。

路由加載之前觸發(fā):beforeRouteEnter (to, from, next)

更新路由之前觸發(fā):beforeRouteUpdate (to, from, next)

離開當前路由之前觸發(fā):beforeRouteLeave (to, from, next)

55.vue路由有哪幾種

this.$router.push(obj) 跳轉(zhuǎn)到指定url路徑,并想history棧中添加一個記錄,點擊后退會返回到上一個頁面this.$router.replace(obj) 跳轉(zhuǎn)到指定url路徑,但是history棧中不會有記錄this.$router.go(n) 向前或者向后跳轉(zhuǎn)n個頁面,n可為正整數(shù)或負整數(shù)

56.說一下vue路由跳轉(zhuǎn)方式

1、router-link 【實現(xiàn)跳轉(zhuǎn)最簡單的方法】<router-link to='需要跳轉(zhuǎn)到的頁面的路徑>瀏覽器在解析時,將它解析成一個類似于<a>的標簽。div和css樣式略

 <li >
 <router-link to="keyframes">點擊驗證動畫效果 </router-link>  
 </li>

2、this.$router.push({ path:’/user’})

3、this.$router.replace{path:‘/’ }類似,不再贅述  

57.vue路由的數(shù)據(jù)傳參,params,query的區(qū)別。使用params什么時候會生效,什么時候不會生效,params有時會失效,為什么

query和params區(qū)別query類似 get, 跳轉(zhuǎn)之后頁面 url后面會拼接參數(shù),類似?id=1, 非重要性的可以這樣傳,刷新頁面id還在 params類似 post, 跳轉(zhuǎn)之后頁面 url后面不會拼接參數(shù) , 但是刷新頁面id 會消失 注意:如果提供了path,params會被忽略而導致失效。 通過官網(wǎng)我們知道路由中的name是不能重復的,而path是可以的。所以在函數(shù)式編程中,我們可以用變量來控制路徑。

58.路由守衛(wèi)路由攔截如何配置

通常在項目里,我們需要用戶進行登錄,才能讓用戶查看項目。在后臺管理系統(tǒng)中,會根據(jù)不同的用戶權(quán)限展示不同的內(nèi)容。在用戶訪問頁面之前,我們通過全局前置守衛(wèi)對路由進行攔截,看看你是不是可以通過。通過的標準是否登錄,如果登錄就通過放行,沒有通過就打回。

// 不需要路由驗證頁面 
const whiteList = ['login', 'index']


router.beforeEach((to, from, next) => {
    // 確定用戶是否已登錄  
    const hasToken = false  // 這里就是路由是否通過標準,一般都是通過token來驗證
if (hasToken) {   // 登錄
  if (to.path === '/login') {  
    // 如果已登錄,請重定向到主頁
    next({ path: '/index' })
    return
  } 
  next()
} else {
  if (whiteList.indexOf(to.name) !== -1) {
    // 在免費登錄白名單中,直接進入
    next()
  } else {
    // 沒有訪問權(quán)限的其他頁將重定向到登錄頁。
    next(`/login`)
  }
}
})

需要注意的一點是,用戶沒有登錄,是需要跳轉(zhuǎn)到登錄頁面,如果在白名單里面沒有登錄頁或者沒有next(),頁面一直跳轉(zhuǎn)直到內(nèi)存溢出。

每個項目的驗證是否擁有權(quán)限不一樣,權(quán)限判斷那一塊可以根據(jù)自己的實項目需求來進行操作。

59.寫公用組件的時候,怎么提高可配置性

  1. 帶著開放封閉原則的視角思考
  2. 開放原則,是說我們需要將有可能變動的屬性,通過props接口的方式暴露給組件的調(diào)用者。
  3. 封閉原則,意思是我們需要將該組件的通用能力及邏輯封裝再組件內(nèi)部,讓調(diào)用者使用更加方便
  4. 組件的可配置性需要結(jié)合實際的業(yè)務需求具體分析
  5. 假設我們要封裝一個Tab選項卡組件,實際功能交互可參考組件 | Element
  6. 組件的開放原則實踐

參數(shù)

說明

類型

可選值

默認值

value / v-model

綁定值,選中選項卡的 name

string

第一個選項卡的 name

type

風格類型

string

card/border-card

closable

標簽是否可關(guān)閉

boolean

false

addable

標簽是否可增加

boolean

false

editable

標簽是否同時可增加和關(guān)閉

boolean

false

tab-position

選項卡所在位置

string

top/right/bottom/left

top

stretch

標簽的寬度是否自撐開

boolean

-

false

before-leave

切換標簽之前的鉤子,若返回 false 或者返回 Promise 且被 reject,則阻止切換。

Function(activeName, oldActiveName)

上面的表格為Tab組件提供的props配置接口,它們需要遵循如下特點,可以極大提高可配置性:

  • 配置項要盡可能多的,覆蓋到業(yè)務中可能出現(xiàn)的每一種情況。
  • 保證組件在每一項配置缺省狀態(tài)下都能夠正常表現(xiàn)
  • 每一項配置都應該具備合理的默認值。
  1. 組件的封閉原則實踐

事件名稱

說明

回調(diào)參數(shù)

tab-click

tab 被選中時觸發(fā)

被選中的標簽 tab 實例

tab-remove

點擊 tab 移除按鈕后觸發(fā)

被刪除的標簽的 name

tab-add

點擊 tabs 的新增按鈕后觸發(fā)

edit

點擊 tabs 的新增按鈕或 tab 被關(guān)閉后觸發(fā)

(targetName, action)

上面的表格為Tab組件所提供的自定義事件,但是事件相關(guān)的邏輯實現(xiàn),已經(jīng)完全在組件內(nèi)部封裝好了,組件使用者,只需要按需綁定事件即可對組件的行為做出監(jiān)聽,這些事件也需要遵循如下特點,才能保證該組件的可配置性:

  • 事件函數(shù)相關(guān)邏輯,必須在組件內(nèi)部封裝完善
  • 自定義事件函數(shù)在觸發(fā)時,必須能夠返回相關(guān)的參數(shù)
  • 例如 @tab-click 事件會給函數(shù)返回,被點擊菜單的index下標等信息
  • 事件函數(shù)本身也需要能夠在缺省狀態(tài)下,保持組件的正常運行。

60.vue-router怎么生成動態(tài)地址

  1. 動態(tài)路由配置的應用場景
  2. 一般我們在使用vue-router進行路由管理的時候,是通過如下方式配置路由與組件之間的映射關(guān)系:
// router/index.js配置文件
const router = new VueRouter({
    routes:[
        {
            path:'/login',
            component:()=>import ('../views/Login') //登錄路由
        },
        {
            path:'/reg',
            component:()=>import ('../views/Reg') //注冊路由
        },
        {
            path:'/admin',
            component:()=>import ('../views/Admin') //這是一個管理員才能訪問的路由
        },
        {
            path:'/vip',
            component:()=>import ('../views/Vip') //假設,這是要給vip用戶才能訪問的路由
        },
    ]
})

但是在后臺管理平臺這種類型的項目中,我們需要讓擁有不同角色權(quán)限的用戶,訪問不同的菜單及路由,如上述代碼所示,部分路由只有管理員才能訪問,而另外一部分路由只能vip用戶才能訪問,所以需要用到vue-router提供的addRoute方法來動態(tài)管理這一部分路由配置。

2.本地只配置通用路由

我們?yōu)榱藢崿F(xiàn)路由的動態(tài)配置,需要將上述路由配置進行拆分,本地配置文件中,只保留通用的路由映射。

const router = new VueRouter({
    routes:[
        {
            path:'/login',
            component:()=>import ('../views/Login') //登錄路由
        },
        {
            path:'/reg',
            component:()=>import ('../views/Reg') //注冊路由
        }
    ]
})

3.后端為每個用戶分配一個角色,隨登錄接口下發(fā)給前端

app.get('/login',(req,res)=>{
  //此處需要實現(xiàn)登錄相關(guān)邏輯
  res.send({
    username:'張三豐',
    role:'admin',  //標志當前用戶角色
    routerList:[  //此處的路由配置,也可以通過獨立接口向前端提供
      {
                path:'/admin',
                component:()=>import ('../views/Admin') //這是一個管理員才能訪問的路由
            },
            ...此處可能會有很多其他路由,這些路由數(shù)據(jù)應該由專門的數(shù)據(jù)表來存儲
    ]
  })
})

4.前端登錄并動態(tài)獲取路由配置

前端登錄成功后,會得到后端動態(tài)下發(fā)的,跟自己賬號角色相匹配的路由數(shù)據(jù),此時可以通過addRoute方法,將這些動態(tài)獲取的路由配置數(shù)據(jù)包,設置給router對象

// views/Login.vue 登錄面板


axios.get('/login',(result)=>{
  let {routerList} = result
  routerList.forEach((item) => {
        this.$router.addRoute(item)
    })
})

61.vue-router有哪些方法

  1. router.beforeEach 路由守衛(wèi)
  2. 我們可以使用這個方法,按需攔截用戶訪問某些敏感路由,例如:
router.beforeEach((to,from,next)=>{ //路由的全局前置守衛(wèi)
    if(to.path.indexOf('/account')==-1){ //判斷用戶訪問的是不是個人中心
        next()  //不是個人中心,直接放行
    }else{
        if(store.state.my.userInfo){ //判斷登錄狀態(tài)
            next() //如果已經(jīng)登錄,直接放行
        }else{
            next('/login')  //如果沒有登錄,則跳至登錄頁
        }
    }
})

2.router.push 編程式導航

通過編程式導航,我們可以通過事件的方式觸發(fā)路由跳轉(zhuǎn)

// 字符串
router.push('home')
 
// 對象
router.push({ path: 'home' })
 
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
 
// 帶查詢參數(shù),變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

3.router.go、router.back、router.forward 路由的進入與返回

router.go 作用等同于window.history.go

// 在瀏覽器記錄中前進一步,等同于 history.forward()
router.go(1)
 
// 后退一步記錄,等同于 history.back()
router.go(-1)
 
// 前進 3 步記錄
router.go(3)

4.router.addRoute 動態(tài)設置路由映射

添加一條新路由規(guī)則。如果該路由規(guī)則有 name,并且已經(jīng)存在一個與之相同的名字,則會覆蓋它。

axios.get('/login',(result)=>{  //通過異步接口獲取對應用戶的特有路由配置
  let {routerList} = result
  routerList.forEach((item) => {
        this.$router.addRoute(item)  //通過addRoute方法依次將路由配置設置給router對象           
    })
})

62.談談對MVVM的理解

  1. 什么是MVVM
  2. 不管是MVC,MVP,或者MVVM,都是常見的軟件架構(gòu)設計模式(Architectural Pattern),它通過分離關(guān)注點來改進代碼的組織方式。不同于設計模式(Design Pattern),只是為了解決一類問題而總結(jié)出的抽象方法,一種架構(gòu)模式往往使用了多種設計模式。MVVM,可以拆分為Model-View-ViewModel來理解:
  3. Model - 數(shù)據(jù)模型,可以對應到真實開發(fā)過程中的數(shù)據(jù)包
  4. View - 視圖層,布局和外觀,可以對應到真實開發(fā)中的DOM結(jié)構(gòu)
  5. ViewModel - 扮演“View”和“Model”之間的使者,幫忙處理 View 視圖層的全部業(yè)務邏輯
  6. 為什么使用MVVM框架
  7. 要回答這個問題,我們需要對比一下,在使用MVVM框架之前,我們是如何完成前端交互的。
  8. 為了修改某個視圖節(jié)點中的內(nèi)容信息,我們需要頻繁人為操作DOM,效率低下
  9. 使用前

為了修改某個視圖節(jié)點中的內(nèi)容信息,我們需要頻繁人為操作DOM,效率低下

var dom = document.querySelector('div');
dom.innerHTML = '張三豐';
dom.style.color = 'red';
  • 使用后

當name數(shù)據(jù)發(fā)生變化的時候,視圖區(qū)域的name自定觸發(fā)更新,極大提高開發(fā)效率

<div>{{name}}</div>


data:{
  name:'張三豐'
}

3.通過上述案例進一步理解MVVM

  • name數(shù)據(jù)包可以認為就是那個Model
  • div 節(jié)點可以認為就是那個View
  • 而Vue提供的語法環(huán)境所支持的數(shù)據(jù)驅(qū)動能力,就可以認為是那個ViewModel

63.vue-router有什么組件

  1. router-link 組件
  2. <router-link> 組件支持用戶在具有路由功能的應用中 (點擊) 導航。通過 to 屬性指定目標地址,默認渲染成帶有正確鏈接的 <a> 標簽,可以通過配置 tag 屬性生成別的標簽.。另外,當目標路由成功激活時,鏈接元素自動設置一個表示激活的 CSS 類名。
  3. <router-link> 比起寫死的 <a href="..."> 會好一些,理由如下:
  4. 無論是 HTML5 history 模式還是 hash 模式,它的表現(xiàn)行為一致,所以,當你要切換路由模式,或者在 IE9 降級使用 hash 模式,無須作任何變動。
  5. 在 HTML5 history 模式下,router-link 會守衛(wèi)點擊事件,讓瀏覽器不再重新加載頁面。
  6. 當你在 HTML5 history 模式下使用 base 選項之后,所有的 to 屬性都不需要寫 (基路徑) 了。
  7. router-view組件
  8. <router-view> 組件是一個 functional 組件,渲染路徑匹配到的視圖組件。<router-view> 渲染的組件還可以內(nèi)嵌自己的 <router-view>,根據(jù)嵌套路徑,渲染嵌套組件。
  9. 其他屬性 (非 router-view 使用的屬性) 都直接傳給渲染的組件, 很多時候,每個路由的數(shù)據(jù)都是包含在路由參數(shù)中。
  10. 因為它也是個組件,所以可以配合 <transition> 和 <keep-alive> 使用。如果兩個結(jié)合一起用,要確保在內(nèi)層使用 <keep-alive>:
<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>

64.vue-cli怎么自定義組件

1.組件封裝

// HelloWorld.vue組件
<template>
  <div>
    自定義組件
  </div>
</template>


<script>
export default {
  data() {
    return {
      key: 'value'
    }
  },
  // 組件交互
}
</script>


<style scoped lang="less">
// 組件樣式
</style>

2.局部注冊調(diào)用組件

// Test.vue
<template>
    <div>
        <HelloWorld/>
    </div>
</template>


<script>
    import HelloWorld from './HelloWorld.vue'
    export default {
        components:{
            HelloWorld
        }
    }
</script>


<style lang="less" scoped>
</style>

全局注冊使用

  • 先在main.js中全局注冊該組件
import Vue from 'vue'
import App from './App.vue'


//全局注冊
import HelloWorld from './components/HelloWorld.vue'
Vue.component('hello-world',HelloWorld)


new Vue({
  render: h => h(App),
}).$mount('#app')

  • 然后在需要使用公共組件的業(yè)務組件中,調(diào)用該組件
// Test.vue
<template>
    <div>
        <hello-world></hello-world>
    </div>
</template>


<script>
    export default {
        
    }
</script>


<style lang="less" scoped>
</style>

65.談談對vue-loader的理解,實現(xiàn)原理是什么

一. vue-loader的作用是什么

  1. 首先我們需要達成共識的是,目前瀏覽器,只能識別普通的html、css、javascript。
  2. 但是為了能夠方便使用vue的組件化開發(fā),需要我們將代碼寫在.vue單文件組件中。
  3. .vue文件,以及其內(nèi)部的template、style、script區(qū)域代碼,不能直接交給瀏覽器去解析,因為它解析不了。
  4. 所以我們需要一個vue-loader進行.vue單文件組件代碼的轉(zhuǎn)換,也就是
  5. .vue方便開發(fā) ------> vue-laoder協(xié)助翻譯 -----> 瀏覽器才能展示

二. vue-loader 工作原理

vue-loader 的工作流程, 簡單來說,分為以下幾個步驟:

  1. 將一個 .vue 文件 切割成 template、script、styles 三個部分。
  2. template 部分 通過 compile 生成 renderstaticRenderFns。
  3. 獲取 script 部分 返回的配置項對象 scriptExports
  4. styles 部分,會通過 css-loadervue-style-loader, 添加到 head 中, 或者通過 css-loader、MiniCssExtractPlugin 提取到一個 公共的css文件 中。
  5. 使用 vue-loader 提供的 normalizeComponent 方法, 合并 scriptExports、render、staticRenderFns, 返回 構(gòu)建vue組件需要的配置項對象 - options, 即 {data, props, methods, render, staticRenderFns...}。

66.vue的路由有哪些鉤子函數(shù),可以用來做什么

一、全局守衛(wèi)

顧名思義,是要定義在全局的,也就是我們 index.js 中的 router 對象。

1. beforeEach

全局前置守衛(wèi),在路由跳轉(zhuǎn)前觸發(fā),它在 每次導航 時都會觸發(fā)。

通過 router.beforeEach 注冊一個全局前置守衛(wèi)。

router.beforeEach((to, from, next) => {
  console.log('??~ to:', to);
  console.log('??~ from:', from);
  next();
})

參數(shù)

beforeEach 全局前置守衛(wèi)接收三個參數(shù)

  • to: Route: 即將要進入的目標路由對象
  • from: Route: 當前導航正要離開的路由對象
  • next: Function: 一定要調(diào)用該方法不然會阻塞路由。

注意: next 參數(shù)可以不添加,但是一旦添加,則必須調(diào)用一次,否則路由跳轉(zhuǎn)等會停止。

next()方法的幾種情況

  • next(): 進行管道中的下一個鉤子。
  • next(false): 中斷當前的導航?;氐?from 路由對應的地址。
  • next('/') 或者 next({ path: '/' }): 跳轉(zhuǎn)到一個不同的地址,可傳遞的參數(shù)與 router.push 中選項一致。
  • next(error): 導航終止,且該錯誤會被傳遞給 router.onError() 注冊過的回調(diào)。、

2. beforeResolve

全局解析守衛(wèi),在路由跳轉(zhuǎn)前,所有 組件內(nèi)守衛(wèi)異步路由組件 被解析之后觸發(fā),它同樣在 每次導航 時都會觸發(fā)。

通過 router.beforeResolve 注冊一個全局解析守衛(wèi)。

router.beforeResolve((to, from, next) => {
  next();
})

回調(diào)參數(shù),返回值和 beforeEach 一樣。也可以定義多個全局解析守衛(wèi)。

3. afterEach

全局后置鉤子,它發(fā)生在路由跳轉(zhuǎn)完成后,beforeEach 和 beforeResolve 之后,beforeRouteEnter(組件內(nèi)守衛(wèi))之前。它同樣在 每次導航 時都會觸發(fā)。

通過 router.afterEach 注冊一個全局后置鉤子。

router.afterEach((to, from) => {
  console.log('??~ afterEach:');
})

這個鉤子的兩個參數(shù)和 beforeEach 中的 to 和 from 一樣。然而和其它全局鉤子不同的是,這些鉤子不會接受 next 函數(shù),也不會改變導航本身。

二、路由守衛(wèi)

顧名思義,就是跟路由相關(guān)的鉤子,我們的路由守衛(wèi)只有一個,就是 beforeEnter。

1. beforeEnter

需要在路由配置上定義 beforeEnter 守衛(wèi),此守衛(wèi)只在進入路由時觸發(fā),在 beforeEach 之后緊隨執(zhí)行,不會在 params、query 或 hash 改變時觸發(fā)。

//index.js
{
  path: '/a',
  component: () => import('../components/A.vue'),
  beforeEnter: (to, from) => {
   console.log('??~ beforeEnter ');
  },
},

beforeEnter 路由守衛(wèi)的參數(shù)是 to、from、next ,同 beforeEach 一樣。

三、組件守衛(wèi)

顧名思義,是定義在路由組件內(nèi)部的守衛(wèi)。

1. beforeRouteEnter

  //A.vue
  beforeRouteEnter(to, from,next) {
    console.log('??~ beforeRouteEnter');
  },

路由進入組件之前調(diào)用,該鉤子在全局守衛(wèi) beforeEach 和路由守衛(wèi) beforeEnter 之后,全局 beforeResolve 和全局 afterEach 之前調(diào)用。

參數(shù)包括 to,from,next。

該守衛(wèi)內(nèi)訪問不到組件的實例,也就是 this 為 undefined,也就是他在 beforeCreate 生命周期前觸發(fā)。

2. beforeRouteUpdate

 //A.vue
  beforeRouteUpdate(to, from) {
    console.log('??~ beforeRouteUpdate');
  },

對于 beforeRouteUpdate 來說,this 已經(jīng)可用了,所以給 next 傳遞回調(diào)就沒有必要了。

3. beforeRouteLeave

 //A.vue
  beforeRouteLeave(to, from) {
    console.log('??~ beforeRouteLeave');
  },

對于 beforeRouteLeave 來說,this 已經(jīng)可用了,所以給 next 傳遞回調(diào)就沒有必要了。

四、總結(jié)

完整的導航解析流程

導航被觸發(fā)。

在失活的組件里調(diào)用 beforeRouteLeave 守衛(wèi)。

調(diào)用全局的 beforeEach 守衛(wèi)。

在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi)。

在路由配置里調(diào)用 beforeEnter。

解析異步路由組件。

在被激活的組件里調(diào)用 beforeRouteEnter。

調(diào)用全局的 beforeResolve 守衛(wèi)。

導航被確認。

調(diào)用全局的 afterEach 鉤子。

觸發(fā) DOM 更新。

調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù),創(chuàng)建好的組件實例會作為回調(diào)函數(shù)的參數(shù)傳入。

67.計算屬性通常用來干什么

一、理解計算屬性的概念

計算屬性的英文是computed,其實很多時候,一些概念從英文對照為中文后,會導致其中一些含義發(fā)生錯位與丟失,我們要想更好的理解computed計算屬性,可以將這個概念分為兩部分來看:

  • 計算
  • 這里的計算,是有種宏觀的概念,指的是對于數(shù)據(jù)包的一種操作,比如:篩選、過濾、新增、刪除等。
  • 說明computed本身是具有處理數(shù)據(jù)的能力。
  • 屬性
  • 屬性的意思是,一種可以讀取、渲染的數(shù)據(jù),性質(zhì)跟data的作用相似
  • 說明computed最終會給出一個數(shù)據(jù)供頁面渲染使用。

由此,我們可以得出一個結(jié)論:

computed計算屬性,負責將一些數(shù)據(jù)在其內(nèi)部按照指定邏輯處理后,最終給出處理后的結(jié)果數(shù)據(jù),給到組件、頁面進行渲染使用,可以讓開發(fā)者更加便捷的處理一些動態(tài)變化的數(shù)據(jù)需求。

二、computed計算屬性的特點

  1. computed內(nèi)部對data做出處理,其處理結(jié)果可以像data一樣,可以直接在頁面中渲染。
  2. computed內(nèi)部邏輯會自動識別到data的變化,從而做出新的操作,得出新的數(shù)據(jù),從而自動更新視圖。
  3. computed處理的數(shù)據(jù)具有緩存的能力,如果data不變,則頁面中調(diào)用的都是computed第一次執(zhí)行時的運算結(jié)果,提高渲染性能。

三、computed應用場景

當某個前端已經(jīng)指定的data數(shù)據(jù)包,如果我們渲染前,對其有過濾、篩選等操作需求,就可以使用computed

  1. 字符串翻轉(zhuǎn)的官方案例,就是將一個普通字符串翻轉(zhuǎn)后再渲染到視圖。
new Vue({
        el:'#app',   //占地盤
        data:{
            'msg':'Hello Vue'  //自定義數(shù)據(jù)包
        },
        computed:{
            reMsg(){ //專門用于反轉(zhuǎn)msg的計算屬性
                return this.msg.split('').reverse().join('')
            }
        }
    })
  1. 如果一個班級中有很多學生,每個學生通過一個對象來表達,現(xiàn)在我們需要根據(jù)學員成績來進行動態(tài)切換顯示:全部學員、及格學員、不及格學員,這種在本地進行篩選的需求可以快速通過computed實現(xiàn),代碼邏輯大致如下:
new Vue({
        el:'#app',   //占地盤
        data:{
            stu:[
                {name:'張三豐',score:100},
                {name:'DDK',score:50},
                {name:'張翠山',score:60},
                {name:'張無忌',score:90},
                {name:'PDD',score:45}
            ],
            status:0  //0全部 1及格  2不及格
        },
        computed:{
            filterStu(){
                let {stu,status} = this
                // let stu = this.stu
                // let status = this.status
                switch (status) {
                    case 1:  //及格
                        return stu.filter(item=>{
                            return item.score>=60
                        })
                    case 2: //不及格
                        let arr = stu.filter(item=>{
                            return item.score<60
                        })
                        return arr
                    default:  //全部
                        return stu
                }


            }
        }
    })

68.computed和watch的區(qū)別

上一個問題我們已經(jīng)詳細探討了computed的相關(guān)特征,在這里我們可以逐一對比一下:

  1. 兩者都跟data有關(guān),區(qū)別在于
  2. computed 在處理完data后,會提供一個新的數(shù)據(jù)包以供使用
  3. watch 只會監(jiān)聽某個指定data的變化,執(zhí)行相關(guān)的邏輯,不會提供新的數(shù)據(jù)
  4. 兩者的使用傾向不同
  5. computed 內(nèi)部雖然有邏輯,但是使用時更加多的關(guān)心其提供的新數(shù)據(jù)包
  6. watch 更加關(guān)注data數(shù)據(jù)變化所引發(fā)的行為邏輯

69.狀態(tài)管理器的數(shù)據(jù)走向是什么

一、什么是狀態(tài)管理?

狀態(tài)管理就是,把組件之間需要共享的狀態(tài)抽取出來,遵循特定的約定,統(tǒng)一來管理,讓狀態(tài)的變化可以預測

二、為什么需要狀態(tài)管理?

狀態(tài)共享

組件之間通常會有一些共享的狀態(tài),在 Vue 或者 React 中我們一般會將這部分狀態(tài)提升至公共父組件的 props 中,由父組件來統(tǒng)一管理共享的狀態(tài),狀態(tài)的改變也是由父組件執(zhí)行并向下傳遞。這樣會導致兩個問題:

  • 需要將共享的狀態(tài)提升至公共的父組件,若無公共的父組件,往往需要自行構(gòu)造
  • 狀態(tài)由父組件自上而下逐層傳遞,若組件層級過多,數(shù)據(jù)傳遞會變得很冗雜

變化跟蹤

在應用調(diào)試過程中,可能會有跟蹤狀態(tài)變化過程的需求,方便對某些應用場景的復現(xiàn)和回溯。這時候就需要統(tǒng)一對狀態(tài)進行管理,并遵循特定的約定去變更狀態(tài),從而讓狀態(tài)的變化可預測。

三、單項數(shù)據(jù)流

因為在真實項目開發(fā)過程中,Store狀態(tài)管理器中的數(shù)據(jù)會在很多組件中用到,如果不設定一個統(tǒng)一的規(guī)范去管理數(shù)據(jù),最終將會導致數(shù)據(jù)混亂、使得項目變得難以維護。所以vuex狀態(tài)管理器設計了如下幾個核心api,與視圖之間進行交互配合:

  • state
  • vuex提供的,用以集中存儲共享的數(shù)據(jù)。
  • mutations
  • vuex提供的,專門用以觸發(fā)state數(shù)據(jù)變化的方法集,并且要求mutations的方法執(zhí)行結(jié)果必須時可預測的,在其內(nèi)部不能出現(xiàn)異步請求等不可預測的邏輯。
  • actions
  • vuex提供的,專門用于讓vuex進行異步請求處理的方法集,可選擇使用。
  • view
  • 視圖層,整個項目組件的代稱,我們在此處消費狀態(tài)管理器提供的數(shù)據(jù)、方法。

數(shù)據(jù)走向必須遵循單向數(shù)據(jù)流的規(guī)范:

  1. 當我們初始化使用狀態(tài)機數(shù)據(jù)時的流程是
  2. store---->state----> view
  3. 當組件內(nèi)部想要本地更新狀態(tài)管理器的數(shù)據(jù),其流程是
  4. view觸發(fā)---->mutations---->state---->store---->view更新
  5. 當組件內(nèi)部想要在異步請求后,再更新本地狀態(tài)管理器的數(shù)據(jù),其流程是
  6. view觸發(fā)---->actions---->mutations---->state---->store---->view更新

70.vuex數(shù)據(jù)丟失怎么解決

vuex的 store 中的數(shù)據(jù)是保存在運行內(nèi)存中的,當頁面刷新時,頁面會重新加載 vue 實例,vuex 里面的數(shù)據(jù)就會被重新賦值,這樣就會出現(xiàn)頁面刷新vuex中的數(shù)據(jù)丟失的問題。 如何解決瀏覽器刷新數(shù)據(jù)丟失問題呢?

方法一:手動操作本地存儲

全局監(jiān)聽,頁面刷新的時候?qū)?store 里 state 的值存到 sessionStorage 中,然后從sessionStorage 中獲取,再賦值給 store ,并移除 sessionStorage 中的數(shù)據(jù)。在 app.vue 中添加以下代碼:

 created() {
    window.addEventListener('beforeunload',()=>{  
       sessionStorage.setItem('list', JSON.stringify(this.$store.state))
    })
    
    try{
      sessionStorage.getItem('list') && this.$store.replaceState(Object.assign({},this.$store.state,JSON.parse(sessionStorage.getItem('list'))))
    }catch(err) {
      console.log(err);
    }
  
    sessionStorage.removeItem("list");
  }

方法二:安裝 vuex-persistedstate 插件

1. npm install vuex-persistedstate -S //安裝插件
2. 在 store/index.js 文件中添加以下代碼:
import persistedState from 'vuex-persistedstate'
const store = new Vuex.Store({
 state:{},
 getters:{},
 ...
 plugins: [persistedState()] //添加插件
})

這時候就需要使用 sessionStorage 進行存儲,修改 plugins 中的代碼

plugins: [
    persistedState({ storage: window.sessionStorage })
]

71.怎么理解v-for的key值

key的值一般為string或則number的類型,它用于解決在進行虛擬dom更新時的更新對象快速定位,虛擬dom更新需要逐個對比虛擬dom對象綁定的數(shù)據(jù),這個過程稱為diff算法,所以key也是提升diff算法的一個標識符,因為數(shù)組可能會進行排序以及增刪等動作,所以使用數(shù)組的下標來定義key是沒有任何作用的

72.能不能自己實現(xiàn)v-model的功能

可以的,自定義一個指令,給節(jié)點綁定上添加input的功能,數(shù)據(jù)使用value綁定,在用戶輸入數(shù)據(jù)的時候,采用oninput事件來進行數(shù)據(jù)獲取,并實時更新value數(shù)據(jù),即可實現(xiàn)v-model的功能

73.Vue雙向數(shù)據(jù)綁定,怎么知道數(shù)據(jù)變了

在Vue2.x中采用ES5的對象屬性定義方法(Object.defineProperty)來給每一個數(shù)據(jù)添加額外屬性(getter和setter屬性)進行數(shù)據(jù)攔截,在vue內(nèi)部實現(xiàn)對攔截數(shù)據(jù)的setter方法數(shù)據(jù)更新消息發(fā)布機制來獲取數(shù)據(jù)更新消息,對getter方法實現(xiàn)消息訂閱機制來獲取數(shù)據(jù)更新

74.退出登錄頭像還在是什么原因怎么辦

多方面的原因引起的:
1、頭像信息是否采用了應用緩存機制,如果有需要清除H5應用緩存
2、頭像緩存在webStorage中,退出沒有清除,直接清除
3、緩存在移動設備的數(shù)據(jù),也需要清除
4、緩存在vuex或redux中的數(shù)據(jù),直接清除即可
5、瀏覽器緩存,清除cookie或則強制清除瀏覽器緩存

75.vue數(shù)據(jù)雙向綁定如何實現(xiàn),如果不用vue,用原生js代碼怎么實現(xiàn)

1、獲取傳遞進來的數(shù)據(jù),然后對所有數(shù)據(jù)添加getter和setter方法,并在setter方法中添加消息訂閱回調(diào)方法,在getter方法中實現(xiàn)數(shù)據(jù)更新發(fā)布回調(diào)方法
2、對作用域內(nèi)的所有dom節(jié)點進行數(shù)據(jù)以來處理,根據(jù)不同指令來實現(xiàn)不同訂閱或發(fā)布回調(diào)方法綁定:如v-model綁定的數(shù)據(jù)對象,在oninput事件中添加消息發(fā)布回調(diào)方法綁定,在v-text中添加value數(shù)據(jù)更新消息訂閱回調(diào)方法綁定
當在輸入框輸入值的時候,出發(fā)oninput事件,出發(fā)消息發(fā)布回調(diào)方法更新數(shù)據(jù)
當數(shù)據(jù)發(fā)生變化,觸發(fā)訂閱方法,執(zhí)行dom數(shù)據(jù)更新方法,把最新數(shù)據(jù)更新到視圖上

76.vue如何實現(xiàn)響應式,說一下原理,它有什么缺點?

它使用ES5的Object.defineProperty方法把所有的屬性全部改為setter和getter屬性,在每一個組件中都有一個watcher對象,當數(shù)據(jù)被賦值或變更的時候會通知頁面的render方法對數(shù)據(jù)進行重新渲染,達到數(shù)據(jù)和視圖的響應更新
因為js的固有特性,不能動態(tài)觀察對象動態(tài)添加、刪除屬性和數(shù)組的長度添加,所以vue2.x不能夠動態(tài)進行數(shù)據(jù)雙向綁定,需要調(diào)用$set、$delete這些方法來實現(xiàn)動態(tài)添加雙向綁定屬性

77.include,exclude的區(qū)別

這個是webpack中常常用于指定加載,對哪些文件進行加載的排除或包含的一個屬性,include配置的文件路徑中的所有文件都將采用配置的loader進行文件加載處理,exclude是配置的路徑都不要進行這個加載器的處理

78.你說你使用懶加載優(yōu)化頁面,用的哪個版本的vue,看過源碼嗎, vue2.0不能實現(xiàn)懶加載

這個與vue沒有太大關(guān)系,采用的是ES6的動態(tài)加載機制來實現(xiàn)頁面的懶加載,主要使用的webpack語法庫為:@babel/plugin-syntax-dynamic-import,在對頁面引入的時候,需要把引入方式從:import MyComponent from 'path' 修改為:const MyComponent = () => import('path')

79.運用多個組件庫,提取公共代碼進行壓縮,發(fā)現(xiàn)js代碼過大,怎么處理

對組件不要做全局引入,可以采用動態(tài)引入和頁面局部引入機制,減少文件首次加載的文件大小和文件進行打包時把所有依賴進行一次性打包造成的文件過大問題

80.vue中爺孫通信怎么實現(xiàn)

可以采用:eventBus事件機制來進行數(shù)據(jù)傳遞;也可以采用逐層props和$emit事件傳遞來實現(xiàn)傳值;vuex數(shù)據(jù)傳遞;使用v-model逐層數(shù)據(jù)傳遞等

81.vue怎么配置多個代理

在vue.config.js中使用devServer配置選項的proxy屬性來進行多個代理配置
devServer: {
  proxy: {
    '/apis': {
      target: 'http://www.baidu.com',
      pathRewrite: {'/apis': ''}
    },
    '/info': {
      target: 'http://www.sina.com',
      pathRewrite: {'/info': ''}
    }
  }
}

82.為什么vue3.0雙向數(shù)據(jù)綁定換成了proxy

因為Object.defineProperty方法的歷史原因,如果要實現(xiàn)數(shù)據(jù)的劫持,需要遍歷所有屬性,如果是深層數(shù)據(jù)需要遞歸來進行屬性綁定;而proxy是直接代理此數(shù)據(jù)對象,不需要遍歷綁定屬性
如果對象有數(shù)據(jù)屬性添加或則屬性更新,需要重新給定數(shù)據(jù)劫持方法綁定,而proxy直接代理對象,不需要對屬性做另外的處理
因此可以在進行數(shù)據(jù)監(jiān)聽和劫持上節(jié)省很多數(shù)據(jù)遍歷性能

83.你封裝一個組件會有哪些考慮,用戶用你的組件要怎么用?如果用戶在使用你組件的同時又想自己加一些按鈕進去那么此時你的組件要怎么寫?

回答:

1、封裝組件會有哪些考慮,用戶用你的組件要怎么用?

1)、封裝組件和封裝函數(shù)是同樣的道理,需要考慮到組件的通用性。

2)、那么,組件的屬性,組件事件,組件的內(nèi)容都是需要考慮到的。

  • 組件的屬性:需要考慮到屬性的類型限制,屬性的默認值
  • 組件的事件:組件事件對應的函數(shù),需要考慮到函數(shù)的參數(shù)和返回值
  • 組件的內(nèi)容:要充分考慮到組件的通用性,靈活性。組件的內(nèi)容給予使用者以更大的靈活空間。

2、如果用戶在使用你組件的同時又想自己加一些按鈕進去那么此時你的組件要怎么寫?

1)、要么使用內(nèi)容的方式(vue中是插槽)

2)、要么提供一個render函數(shù),由用戶提供需要渲染的內(nèi)容(如:按鈕)。同時,根據(jù)自定義組件的情況,可以考慮讓用戶把按鈕渲染在指定的區(qū)域。即:render函數(shù)里有:渲染的區(qū)域和渲染的內(nèi)容。

84.vue圖片懶加載:①不考慮兼容性做法(你認為最好處理最效率的)②考慮兼容性做法

回答:

1、場景:

一個網(wǎng)頁如果包含了很多的圖片,那么,服務器壓力就會很大。不僅影響渲染速度還會浪費帶寬。

通俗的說:你不看的圖片我先不加載,也許你不看呢(哈哈),我何苦要做無效的事情呢 你想看時,我再加載(哈哈)

2、原理:

  1)、先將img標簽的src鏈接設為同一張圖片(默認圖片:可以是loading),把圖片的實際地址賦給一個自定義屬性。這時候所有的圖片只發(fā)送一次請求。

  2)、然后,當js監(jiān)聽到某張圖片進入可視窗口時(說明你想看了),再將實際地址賦給src屬性。src屬性的值發(fā)生變化時,瀏覽器才會發(fā)送請求加載當前圖片。如果圖片沒有進入可視區(qū)域,就不會加載圖片(說明你還沒想看呢),這樣就大大的提高了效率。

3、示例代碼(兼容性在代碼中有注釋):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
    *{
        margin: 0;
        padding: 0;
    }
    ul{
        list-style: none;
    }
    li{
        width: 100%;    
        height: 200px;
        text-align: center;
        line-height: 200px
    }
    img{
        display: block;
        height: 200px;
    }
</style>
</head>
<body>
    <div id="box">
        
    </div>
</body>
</html>
<script>


let imgDoms = document.getElementsByTagName("img");
// 當前顯示圖片的最大下標:
let maxIndex =  -1;    


window.onload = function(){
    // 1、從后端獲取到所有的圖片地址,先賦值給圖片標簽的自定義屬性(data-src),給圖片的src賦值為loading
    getImgs();
    // 2、加載可視區(qū)域的圖片
    loadingImg();
}


window.onscroll = function(){
    loadingImg();
}


// 從后端獲取到所有的圖片地址,先賦值給圖片標簽的自定義屬性(data-src),給圖片的src賦值為loading
function getImgs(){
    //這個數(shù)組中的圖片,可以是從后端獲取到的,也可以寫死。
    let imgs = ["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg","img/6.jpg","img/7.jpg","img/8.jpg","img/9.jpg","img/10.jpg","img/11.jpg","img/12.jpg","img/13.jpg","img/14.jpg","img/15.jpg","img/16.jpg","img/17.jpg","img/18.jpg","img/19.jpg","img/20.jpg","img/21.jpg","img/22.jpg","img/23.jpg","img/24.jpg","img/25.jpg","img/26.jpg","img/27.jpg","img/28.jpg","img/29.jpg","img/30.jpg","img/31.jpg","img/32.jpg","img/33.jpg"];
    let htmlStr = "";
    for(let i=0;i<imgs.length;i++){
        htmlStr+=`<img src="img/loading02.gif" data-src="${imgs[i]}" />`;
    }
    document.getElementById("box").innerHTML = htmlStr;
}


function loadingImg(){    
    // 1、計算當前滾動的高度+可視區(qū)域的高度(此處考慮的兼容性)
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    let clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
    let height = scrollTop+clientHeight;


    // 2、得到應該顯示圖片的序號(可視區(qū)域最下面的圖片序號);
    let index = Math.ceil(height/200)-1;
    
    // 3、如果應該顯示的圖片的下標大于最大的下標,那就應該做圖片的加載了。
    if(index>maxIndex){
        for(let i=maxIndex+1;i<=index;i++){
            if(imgDoms[i].getAttribute("data-src")){
                imgDoms[i].src = imgDoms[i].getAttribute("data-src");
                imgDoms[i].removeAttribute("data-src");
            }
        }
    }
    maxIndex = index;
}
</script>

85.vue組件中的data為什么必須是函數(shù),為什么不可以是對象,數(shù)組這些

回答:

1、如果vue組件的data是一個對象,那么在復用vue組件時,由于對象是個引用類型。那么,每個組件的data會指向同一塊內(nèi)存空間,組件之間的data就會互相影響。所以,組件中的data不能是對象。

2、vue框架中把data定義成函數(shù),函數(shù)里返回真正的數(shù)據(jù)(引用類型)。每次復用組件時,vue框架都會調(diào)用該函數(shù)。當調(diào)用該函數(shù)時,函數(shù)返回新的對象(申請新的空間)。那么不同的組件的內(nèi)存空間就是獨立的,不會互相影響。文章來源地址http://www.zghlxwxcb.cn/news/detail-730127.html

到了這里,關(guān)于【直接收藏】前端 VUE 高階面試題(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包