天天看點

Vue學習-13道Vue經典面試題與知識點小串燒

1 Vue路由的兩種模式

小白回答:hash模式url帶#号,history模式不帶#号

大牛解答:hash模式url裡面永遠帶着#号,我們在開發當中預設使用這個模式。那麼什麼時候要用history模式呢?如果使用者考慮url的規範那麼就需要使用history模式,因為history模式沒有#号,是個正常的url适合推廣宣傳。當然其功能也有差別,比如我們在開發app的時候有分享頁面,那麼這個分享出去的頁面就是用vue或是react做的,咱們把這個頁面分享到第三方的app裡,有的app裡面url是不允許帶有#号的,是以要将#号去除那麼就要使用history模式,但是使用history模式還有一個問題就是,在通路二級頁面的時候,做重新整理操作,會出現404錯誤,那麼就需要和後端人配合讓他配置一下apache或是nginx的url重定向,重定向到你的首頁路由上就ok啦。

hash與history的差別:

hash history
url顯示 有#,很Low 無#,好看
回車重新整理 可以加載到hash值對應頁面 一般就是404掉了
支援版本 支援低版本浏覽器和IE浏覽器 HTML5新推出的API

hash模式

我們先來認識下這位朋友#,這個#就是hash符号,中文名哈希符或錨點,當然這在我們前端領域姑且這麼稱呼。

然後哈希符後面的值,我們稱之為哈希值。OK,接下來我們繼續分析他的原理。路由的哈希模式其實是利用了window可以監聽onhashchange事件,也就是說你的url中的哈希值(#後面的值)如果有變化,前端是可以做到監聽并做一些響應(搞點事情),這麼一來,即使前端并沒有發起http請求他也能夠找到對應頁面的代碼塊進行按需加載。

後來人們給他起了一個霸氣的名字叫前端路由,成為了單頁應用标配。

history模式

我們先介紹一下H5新推出的兩個神器:pushState與replaceState

具體自行百度,簡而言之,這兩個神器的作用就是可以将url替換并且不重新整理頁面,好比挂羊頭賣狗肉,http并沒有去請求伺服器該路徑下的資源,一旦重新整理就會暴露這個實際不存在的“羊頭”,顯示404。

那麼如何去解決history模式下重新整理報404的弊端呢,這就需要伺服器端做點手腳,将不存在的路徑請求重定向到入口檔案(index.html),前後端聯手,齊心協力做好“挂羊頭賣狗肉”的完美特效。

總之,pushState方法不會觸發頁面重新整理,隻是導緻history對象發生變化,位址欄會有反應。

history模式下,build之後本地 index.html 打開是無效的。

hash模式下,build之後本地 index.html 打開正常!

2 Vue元件之間如何傳值

  1. 父元件向子元件傳值:

    父元件:

    <template>
      <div class="parentOne">
        <children-item :content="item" v-for="item in list" :key="item.id"></children-item>
      </div>
    </template>
    
    <script>
      import ChildrenItem from "../children/ChildrenOne.vue"
      export default {
        name: "ParentOne",
        data() {
          return {
            list: [
              { id: "001", title: "這是父元件第一項内容" },
              { id: "002", title: "這是父元件第二項内容" },
              { id: "003", title: "這是父元件第三項内容" }
            ]
          }
        },
        components: {
          "children-item": ChildrenItem
        }
      }
    </script>
    
    <style>
    </style>
               
    **在父元件中使用子元件,并且在子元件中添加需要傳遞的值

    :content="item"**

    子元件:
    <template>
      <div class="ChildrenOne">
        <ul>
          <li v-for="childItem in content">{{childItem}}</li>
          <li>{{message}}</li>
        </ul>
      </div>
    </template>
    <script>
      export default {
        name: 'ChildrenOne',
        props: ["content"],
        data() {
          return {
            message: this.content.id
          }
        }
      }
    </script>
    <style></style>
               
    在子元件中添加props數組,接收從父元件中傳遞過來的

    content

    值,然後就可以在上邊的template中像使用data中的資料一樣使用props中的接收值,進而實作父元件向子元件的傳值
  2. 子元件向父元件傳值:
    子元件向父元件傳值這一個技術點有個專業名詞,叫做“釋出訂閱模式”,很明顯在這裡子元件為釋出方,而父元件為訂閱方
    子元件:
    <template>
      <div class="ChildrenTwo">
        <ul>
          <li v-for="childItem in content" @click="ChildrenOnclick()">{{childItem}}</li>
        </ul>
      </div>
    </template>
    
    <script>
      export default {
        name: 'ChildrenTwo',
        props: ["content", "index"],
        data() {
          return {
          }
        },
        created() {
          console.log(this.index);
        },
        methods: {
          ChildrenOnclick() {
            console.log(this.index);
            // 釋出訂閱模式
            this.$emit("delete", this.index)
          }
        }
      }
    </script>
    
    <style>
    </style>
               
    在該子元件中中觸發li的

    click

    事件,調用

    ChildrenOnclick

    方法,在該方法中通過使用

    $emit

    方法定義了一個

    delete

    方法,并傳遞index值給父元件
    父元件:
    <template>
      <div class="parentTwo">
        <children-item 
        	:content="item" 
        	:index="index" 
        	v-for="(item,index) in list" 
        	:key="item.id" 
        	@delete="handleParentClick"
        >
        </children-item>
      </div>
    </template>
    
    <script>
      import ChildrenItem from "../children/ChildrenTwo.vue"
      export default {
        name: "ParentTwo",
        data() {
          return {
            list: [
              { id: "001", title: "這是父元件第一項内容" },
              { id: "002", title: "這是父元件第二項内容" },
              { id: "003", title: "這是父元件第三項内容" }
            ]
          }
        },
        methods: {
          handleParentClick(index) {
            this.list.splice(index, 1);
          }
        },
        components: {
          "children-item": ChildrenItem
        }
      }
    </script>
    
    <style>
    </style>
               
    在父元件使用子元件時,使用子元件中自定義的

    delete

    方法實作接收到子元件傳遞過來的值

    @delete="handleParentClick"

    ,調用

    handleParentClick

    方法将傳遞的值作為參數傳入父元件
  3. 兄弟(或者沒有關系)元件的元件傳值:
    1. 建立中轉站:bus.js
      Vue學習-13道Vue經典面試題與知識點小串燒
    2. 在需要引用的地方引入bus.js
    兄弟元件2:
    <template>
        <div id="two">
          <h3>小弟元件</h3>
          <p>
            <button @click="say">給大哥說話</button>
          </p>
        </div>
    </template>
    
    <script>
    // 引入bus.js進來
    import bus from '@/bus.js'
    
    export default {
      name: 'Two',
      methods: {
        // 實作給大哥傳遞資料的
        say () {
          // 讓bus調用自己的事件
          bus.$emit('receive', '1000元保護費')
        }
      }
    }
    </script>
    
    <style lang="less" scoped>
    #two{
      width: 300px;
      height: 100px;
      border:1px solid greenyellow;
    }
    </style>
    
               
    在兄弟元件2小弟元件中,通過

    click

    事件調用say方法,在say方法裡再調用

    bus.$emit

    ,向

    receive

    事件傳遞值

    1000元保護費

    兄弟元件1:
    <template>
        <div id="one">
          <h3>大哥元件</h3>
          <span>接收小弟的禮物:{{money}}</span>
        </div>
    </template>
    
    <script>
    // 引入bus.js進來
    import bus from '@/bus.js'
    
    export default {
      name: 'One',
      // 在created中給bus綁定事件,時機最靠前,随時可以響應使用
      data () {
        return {
          // 接收小弟來到資料
          money: ''
        }
      },
      created () {
        // this:元件執行個體對象
        // 注意:設定為箭頭函數
        bus.$on('receive', val => {
          // val:是其他應用處給傳遞的資料
          // 把獲得的資料賦予money
          this.money = val
        })
      }
    }
    </script>
    
    <style lang="less" scoped>
    #one{
      width: 300px;
      height: 100px;
      border:1px solid red;
      margin-bottom:20px;
    }
    </style>
    
               
    在兄弟元件1大哥元件中,在created()方法裡調用

    bus.$on

    ,執行

    receive

    方法,接收小弟元件傳遞過來的值(

    1000元保護費

    ),然後進行其他操作,這樣就完成了兄弟元件之間的值傳遞
    提一筆:隻要沒有直接套用關系的元件都是兄弟

3 MVC與MVVM的差別

MVVM與MVC最大的差別就是:MVVM實作了View和Model的自動同步,也就是當Model的屬性改變時,我們不用再自己手動操作Dom元素,來改變View的顯示,而是改變屬性後該屬性對應View層顯示會自動改變

進一步了解

一、MVC

MVC允許在不改變視圖的情況下改變視圖對使用者輸入的響應方式,使用者對View的操作交給了Controller處理,在Controller中響應View的事件調用Model的接口對資料進行操作,一旦Model發生變化便通知相關視圖進行更新。

? 如果前端沒有架構,隻使用原生的html+js,MVC模式可以這樣了解。将html看成view;js看成controller,負責處理使用者與應用的互動,響應對view的操作(對事件的監聽),調用Model對資料進行操作,完成model與view的同步(根據model的改變,通過選擇器對view進行操作);将js的ajax當做Model,也就是資料層,通過ajax從伺服器擷取資料。

二、MVVM

MVVM與MVC最大的差別就是:它實作了View和Model的自動同步,也就是當Model的屬性改變時,我們不用再自己手動操作Dom元素,來改變View的顯示,而是改變屬性後該屬性對應View層顯示會自動改變。

這裡我們拿典型的MVVM模式的代表,Vue,Vue執行個體中的data相當于Model層,而ViewModel層的核心是Vue中的雙向資料綁定,即Model變化時VIew可以實時更新,View變化也能讓Model發生變化。

整體看來,MVVM比MVC精簡很多,不僅簡化了業務與界面的依賴,還解決了資料頻繁更新的問題,不用再用選擇器操作DOM元素。因為在MVVM中,View不知道Model的存在,Model和ViewModel也觀察不到View,這種低耦合模式提高代碼的可重用性。

這裡隻是簡單地說一下差別,詳細的可以參考以下文章:

https://www.jianshu.com/p/b0aab1ffad93

https://blog.csdn.net/u013282174/article/details/51220199

https://www.jianshu.com/p/f07cf01056b1

4 Vue的生命周期

啥也先别說,開局一張圖:

Vue學習-13道Vue經典面試題與知識點小串燒

Vue的生命周期可以分為以下八個階段:

beforeCreate 執行個體建立前

created 執行個體建立完成

beforeMount 挂載前

mounted 挂載完成

beforeUpdate 更新前

updated 更新完成

beforeDestory 銷毀前

destoryed 銷毀完成

  1. BeforeCreated:

    這個鈎子是new Vue()之後觸發的第一個鈎子,在目前階段中data、methods、computed以及watch上的資料和方法均不能被通路。

  2. created

    這個鈎子在執行個體建立完成後發生,目前階段已經完成了資料觀測,也就是可以使用資料,更改資料,在這裡更改資料不會觸發updated函數。可以做一些初始資料的擷取,注意請求資料不易過多,會造成白屏時間過長。在目前階段無法與Dom進行互動,如果你非要想,可以通過vm.$nextTick來通路Dom。

  3. Beforemounted

    這個鈎子發生在挂載之前,在這之前template模闆已導入渲染函數編譯。而目前階段虛拟Dom已經建立完成,即将開始渲染。在此時也可以對資料進行更改,不會觸發updated。

  4. mounted

    這個鈎子在挂載完成後發生,在目前階段,真實的Dom挂載完畢,資料完成雙向綁定,可以通路到Dom節點,使用

    $ref

    屬性對Dom進行操作。也可以向背景發送請求,拿到傳回資料。
  5. BeforeUpdate

    這個鈎子發生在更新之前,也就是響應式資料發生更新,虛拟dom重新渲染之前被觸發,你可以在目前階段進行更改資料,不會造成重渲染。

  6. updated

    這個鈎子發生在更新完成之後,目前階段元件Dom已完成更新。要注意的是避免在此期間更改資料,因為這可能會導緻無限循環的更新。

  7. BeforeDestroy

    這個鈎子發生在執行個體銷毀之前,在目前階段執行個體完全可以被使用,我們可以在這時進行善後收尾工作,比如清除計時器。

  8. destroyed

    這個鈎子發生在執行個體銷毀之後,這個時候隻剩下了dom空殼。元件已被拆解,資料綁定被卸除,監聽被移出,子執行個體也統統被銷毀。

提一筆:

在使用生命周期時有幾點注意事項需要我們牢記。

1.第一點就是上文曾提到的created階段的ajax請求與mounted請求的差別:前者頁面視圖未出現,如果請求資訊過多,頁面會長時間處于白屏狀态。

2.除了beforeCreate和created鈎子之外,其他鈎子均在伺服器端渲染期間不被調用。

3.上文曾提到過,在updated的時候千萬不要去修改data裡面指派的資料,否則會導緻死循環。

4.Vue的所有生命周期函數都是自動綁定到this的上下文上。是以,你這裡使用箭頭函數的話,就會出現this指向的父級作用域,就會報錯。

Vue生命周期先寫到這兒吧,發現需要寫的東西很多,後期專門寫一篇Vue生命周期的博文

5 Vue-Router有哪幾種導航鈎子

全局前置守衛:
    const router = new VueRouter({ ... })

    router.beforeEach((to, from, next) => {
      // ...
    })
全局解析守衛:
你可以用 router.beforeResolve 注冊一個全局守衛。這和 router.beforeEach 類似,
差別是在導航被确認之前,同時在所有元件内守衛和異步路由元件被解析之後,解析守衛就被調用。

全局後置鈎子:
你也可以注冊全局後置鈎子,然而和守衛不同的是,這些鈎子不會接受 next 函數也不會改變導航本身:

router.afterEach((to, from) => {
  // ...
})

路由獨享的守衛:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
元件内的守衛:
你可以在路由元件内直接定義以下路由導航守衛:
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該元件的對應路由被 confirm 前調用
    // 不!能!擷取元件執行個體 `this`
    // 因為當守衛執行前,元件執行個體還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在目前路由改變,但是該元件被複用時調用
    // 舉例來說,對于一個帶有動态參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 由于會渲染同樣的 Foo 元件,是以元件執行個體會被複用。而這個鈎子就會在這個情況下被調用。
    // 可以通路元件執行個體 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該元件的對應路由時調用
    // 可以通路元件執行個體 `this`
  }
}


           

6 路由之間怎麼跳轉

聲明式–

<router-link :to="{name:'index',query:{id:'xxx',name:'xxx'}}">

程式設計式–this.$router.push({name:‘元件名’)};

7 Vue全家桶都有哪些

Vue-cli 項目建構工具;vue-router 路由;vuex 狀态管理;axios http請求工具;webpack

這題感覺沒啥意思,但目錄都寫好了,不想重新改了…

8 Vue和Jquery的差別有哪些

差別一:

1).jQuery是一個類庫,提供了很多的方法,不能算架構,在過去和現在Jquery是最流行的web前端js庫,可是現在無論國内還是國外,他的使用率正在漸漸被其他的js庫所替代。随着浏覽器廠商對H5規範統一遵循以及ECMA6在浏覽器端的實作,jquery的使用率會越來越低。

2).vue的介紹:vue是一個剛興起不久的前端架構,有一套完整的體系,是一個精簡的MVVM。從技術角度講,vue.js專注于MVVM模型的ViewModel層,通過雙向資料綁定把view層和Model層連接配接起來,通過對資料的操作就可以完成對頁面視圖的渲染。

差別二:

1).jQuery是直接操作DOM的;使用選擇器($)選取DOM對象,對其進行指派、取值、事件綁定等操作;

和原生的js差別隻在于可以更友善的選取和操作DOM對象;

? 資料和界面是在一起,比如擷取input标簽的内容

? 2)vue基于一種MVVM模式,使用資料驅動的方式,通過Vue對象将資料和View完全分離開來。

? 對資料進行操作,不在需要引用相應的DOM對象,通過vue對象,将資料和相應的DOM對象互相綁定起來。

差別三

? 1).JQuery适用的場景:JQuery側重樣式操作,比如一些H5的動畫頁面;需要js來操作頁面樣式的頁面

? 2).Vue适用的場景:vue側重資料綁定,比如複雜資料操作的背景頁面;表單填寫頁面

9 v-if和v-show的差別

v-if是通過動态建立或者移除元素實作動态切換 v-show是通過控制元素的css樣式display:none樣式實作切換 一般來說,v-if 有更高的切換消耗 而 v-show 有更高的初始渲染消耗。 是以,如果需要頻繁切換 v-show 較好,如果在運作時條件不大可能改變 v-if 較好。

10 Vue封裝元件的流程

  1. 建立元件模闆
  2. 通過props接收外部資料
  3. 在需要的子產品中引入該元件,使用該元件,最終在網頁中輸出元件與資料
    這個在網上沒有找到比較好的文章,是以是自己根據自己為數不多的封裝小元件的經驗寫的,如果大家有更好的更規範的流程,可以在下方評論,我及時更新

11 methods和watch,computed的差別

  1. computed–computed是在HTML DOM加載後馬上執行的,如指派;computed計算屬性是基于它們的依賴進行緩存的,調用函數時,隻要依賴的資料沒發生改變時,會直接從緩存中拿資料,不會再次執行函數
  2. methods–methods則必須要有一定的觸發條件才能執行,如點選事件;隻要發生重新渲染,method 調用總會執行該函數。
  3. watch–檢測一個資料的變化;對應一個對象,鍵是觀察表達式,值是對應回調。值也可以是方法名,或者是對象,包含選項。
  4. 執行順序–先computed再watch,不執行methods;等觸發某一事件後,則是:先methods再watch。

12 如何解決SPA應用首屏加載過慢

  • 将全局引入轉換為按需引入檔案
  • 在 config/index.js 檔案中将productionSourceMap 的值設定為false. 不生成映射資源
  • 路由懶加載:懶加載即元件的延遲加載,通常vue的頁面在運作後進入都會有一個預設的頁面,而其他頁面隻有在點選後才需要加載出來,使用懶加載可以将頁面中的資源劃分為多份,進而減少第一次加載的時候耗時
    這種優化,就是将每個元件的js代碼獨立出來,在使用到這個元件時,才向伺服器請求檔案,并且請求過一次後就會緩存下來,再次使用到這個元件時,就會使用緩存,不再發送請求
  • 壓縮css和js檔案
  • 使用cdn托管(就是把原伺服器上資料複制到其他伺服器上,使用者通路時,哪台伺服器近通路到的就是哪台伺服器上的資料。)

13 Vue項目對SEO不友好的解決方法

開局一張圖:

Vue學習-13道Vue經典面試題與知識點小串燒

先分析下原因:

1.搜尋引擎的基礎爬蟲的原理就是抓取你的url,然後擷取你的html源代碼并解析。 而你的頁面通常用了vue等js的資料綁定機制來展示頁面資料,爬蟲擷取到的html是你的模型頁面而不是最終資料的渲染頁面,是以說用js來渲染資料對seo并不友好。

2.seo 本質是一個伺服器向另一個伺服器發起請求,解析請求内容。但一般來說搜尋引擎是不回去執行請求到的js的。也就是說,如果一個單頁應用,html在伺服器端還沒有渲染部分資料資料,在浏覽器才渲染出資料,而搜尋引擎請求到的html是沒有渲染資料的。 這樣就很不利于内容被搜尋引擎搜尋到。 是以服務端渲染就是盡量在伺服器發送到浏覽器前 頁面上就是有資料的。

3.一般的資料邏輯操作是放在後端的。排序這個如果僅僅是幾條資料,前後端排序開起來是一樣的,如果是有1000條資料,前端要排序就要都請求過來。這樣顯然是不合理的。

常用的解決方案:

1.頁面預渲染

2.服務端渲染

3.路由采用h5 history模式

大廠如何做優化的呢?

1) bilibili做了基本的seo優化,比如

(1)TDK描叙詳細。

(2)提升網頁加載速度:對外聯css,以及js使用了延遲加載以及dns-prefetch,preload。

(3)外聯較多,關鍵詞排名高。

2) 掘金網站使用了vue-meta-info 管理網站的meta,應該配合使用了prerender-spa-plugin 對SEO進行了優化

3) Element在logo上加了首頁的位址,并且隻有logo是放在h1标簽中。

4) 有一些流量不太高的網站比如http://www.marshall.edu (Marshall University)做了seo社會化分享優化,在meta資訊中出現了property=”og:title”這種新東西;https://we.dji.com/zh-CN/campus (大疆招聘)使用了Nuxt

這些網站中出現率最高的公共元件或公共方法有四個:

1) 面包屑導航

2) Icon

3) 搜尋框

4) Button元件

關于收錄問題:

搜尋引擎判斷一個網站權重高低的尺度無非兩個:收錄和外鍊。是以百度收錄的高低很大程度上影響着網站在百度的排名

目前百度spider抓取新連結的途徑有兩個:

一是主動出擊發現抓取;

二就是從百度站長平台的連結送出工具中擷取資料,其中通過主動推送功能“收”上來的資料最受百度spider的歡迎。

對于站長來說,如果連結很長時間不被收錄,建議嘗試使用主動推送功能,尤其是新網站,主動推送首頁資料,有利于内頁資料的抓取。

參考文章:

https://blog.csdn.net/codeliuguisheng/article/details/79634422

https://blog.csdn.net/chjj0904/article/details/79388438

@_@

博文參考文章:

https://blog.csdn.net/wang1006008051/article/details/81805932

https://blog.csdn.net/fifteen718/article/details/82529433

https://www.imooc.com/article/257885

https://juejin.im/post/5d1b464a51882579d824af5b