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

    2. 在需要引用的地方引入bus.js

      import bus from '@/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的生命週期可以分爲以下八個階段:

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不友好的解決方法

開局一張圖:

先分析下原因:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章