Vue 面試知識點總結(二)【持續更新中~】

1、Vue核心面試高頻知識點

一、vue計算屬性的理解

模板內能夠放表達式,可是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板太重且難以維護。例如:html

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

因此,對於任何複雜邏輯,都應當使用計算屬性。前端

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
computed: {
    // 計算屬性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 實例
      return this.message.split('').reverse().join('')
    }
  }
computed計算屬性實質上就是對模版語法的增強,可讓咱們編寫更爲複雜的邏輯。

二、父組件如何向子組件傳值

  • 傳入一個靜態屬性

傳入的靜態屬性會綁定在組件內最外層元素上vue

<blog-post title="My journey with Vue"></blog-post>
  • 傳入任何形式的變量

數字、字符串、對象、數組等node

<blog-post v-bind="post"></blog-post>
  • 傳遞自定義事件
<a @select="selectItem"></a>

三、如何在組件中共享全局常量

├── src
│   ├── const
│   │    ├── const.js
│   │    
│   └── main.js
└── ...

在 const.js 文件下,設置常量react

// const.js
export default {
    install(Vue,options){

        Vue.prototype.global = {
            title:'全局',
            isBack: true,
            isAdd:  false,
        };
        
    }

 }

引入webpack

//引入全局常量
import constant from './const/const.js'
Vue.use(constant);

而後咱們就能夠在任何地方使用了web

//經過js方式使用:
this.global.title
//或在 html 結構中使用
{{global.title}}

四、計算屬性的緩衝與方法調用的不一樣之處

一、計算屬性必須返回值
二、計算屬性是基於他的依賴來自動執行的,只有當依賴屬性發生變化了,它纔會從新計算
三、method能夠不須要返回值,它依賴事件的調用,不會自動執行
四、當你在抉擇的時候,你要注意你是否須要緩衝數據,若是須要那你就使用計算屬性。面試

五、自定義指令你須要知道哪些?

一般咱們自定義一些指令是知足咱們對DOM操做的需求

Vue裏面有許多內置的指令,好比v-if和v-show,這些豐富的指令能知足咱們的絕大部分業務需求,不過在須要一些特殊功能時,咱們仍然但願對DOM進行底層的操做,這時就要用到自定義指令。vue-router

自定義指令的幾個鉤子函數:express

  • bind:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。
  • inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
  • update:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 。
  • componentUpdated:指令所在組件的 VNode 及其子 VNode 所有更新後調用。
  • unbind:只調用一次,指令與元素解綁時調用。

鉤子函數的參數:

  • el:指令所綁定的元素,能夠用來直接操做 DOM 。
  • binding:一個對象,包含如下屬性:

    name:指令名,不包括 v- 前綴。
    value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲2。
    oldValue:指令綁定的前一個值,僅在update和 componentUpdated鉤子中可用。不管值是否改變均可用。
    expression:字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式爲 "1 + 1"。
    arg:傳給指令的參數,可選。例如 v-my-directive:foo中,參數爲 "foo"。
    modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲{ foo: true, bar: true }。
    vnode:Vue 編譯生成的虛擬節點。

  • oldVnode:上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

new Vue({
  el: '#hook-arguments-example',
  data: {
    message: 'hello!'
  }
})

clipboard.png

六、面試必考之組件通訊:

Vue面試必問,組件直接通訊之超詳細易懂

七、watch考點

Vue.js中watch的高級用法,深度和註銷觀察

vue技術分享-你可能不知道的7個祕密

2、vue-router路由面試知識點

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,讓構建單頁面應用變得易如反掌。

一、一個簡單的路由實例,來分析$route和$router的不一樣

// router.js
import Vue from "vue";
import Router from "vue-router"; // 【1】引入router
import Home from "./views/Home.vue"; // 組件引入

Vue.use(Router); // 【2】使用

// 【3】new Router(param)
//  param 是一個路由配置對象
export default new Router({
  routes: [
    {
      path: "/",
      name: "home",
      component: Home
    },
    {
      path: "/about",
      name: "about",
      // 懶加載
      component: () =>
        import(/* webpackChunkName: "about" */ "./views/About.vue")
    }
  ]
});

引入路由配置

// main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router"; // 【1】引入

new Vue({
  router,  // 【2】綁定路由
  render: h => h(App)
}).$mount("#app");
// app.vue
<template>
  <div id="app">
      <router-link to="/">首頁</router-link>
      <router-link to="/about">Abour</router-link>
      <p>
          <router-view></router-view>
      </p>
  </div>
</template>

<script>
    export default {
        name: "APP",
        data () {
            return {

            }
        }
    };
</script>

這樣就能夠實現簡單的路由切換。

經過Home組件來區分$route和$router的區別:

<template>
  <div class="home">
    Home
    <button @click="goBack">返回</button>
  </div>
</template>

<script>

export default {
  name: "home",
  mounted () {
    console.log(this.$route);
  },
  methods: {
    goBack() {
      this.$router.go(-1);
    }
  }
};
</script>
this.$router來訪問路由器,進行一些路由跳轉等操做。this.$route能夠拿到當前路由信息。

好比: this.$router.go(-1);來實現回退,console.log(this.$route);來查看當前路由。
咱們能夠在this.$route中拿到路由信息,好比一些參數和查詢條件等。
clipboard.png

vue-router提供了params、query、meta三種頁面間傳遞參數的方式。
// 字符串,不帶參數 /home
this.$router.push('home') 

// 對象,不帶參數 /home
this.$router.push({ path: 'home' })

// params(推薦):命名的路由,params 必須和 name 搭配使用 /user/123
this.$router.push({ name:'user',params: { userId: 123 }})

// 這裏的 params 不生效
this.$router.push({ path:'/user',params: { userId: 123 }})

// query:帶查詢參數,變成 /register?plan=private
this.$router.push({ path: 'register', query: { plan: 'private' }})

//meta方式:路由元信息
export default new Router({
    routes: [
        {
            path: '/user',
            name: 'user',
            component: user,
            meta:{
                title:'我的中心'
            }
        }
    ]
})
//經過 $route 對象獲取,注意是route,麼有r
this.$route.params

this.$route.query

this.$route.meta

二、動態路由

咱們常常須要把某種模式匹配到的全部路由,全都映射到同個組件。例如,咱們有一個 User 組件,對於全部 ID 各不相同的用戶,都要使用這個組件來渲染。這時候咱們須要設置動態路由參數來實現:

{
    // // 動態路徑參數 以冒號開頭
    path: '/user/:id',
    name: 'user',
    component: User
}

一個「路徑參數」使用冒號 : 標記。當匹配到一個路由時,參數值會被設置到 this.$route.params,能夠在每一個組件內使用。因而,咱們能夠更新 User 的模板,輸出當前用戶的 ID:

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

你能夠在一個路由中設置多段「路徑參數」,對應的值都會設置到 $route.params 中。例如:

clipboard.png

注意點

當使用路由參數時,例如從 /user/foo 導航到 /user/bar,原來的組件實例會被複用。由於兩個路由都渲染同個組件,比起銷燬再建立,複用則顯得更加高效。不過,這也意味着組件的生命週期鉤子不會再被調用。
  • 解決辦法一:

使用watch監聽:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 對路由變化做出響應...
    }
  }
}
  • 解決辦法二:
<template>
    <div class="user">
        <h1>This is an user page</h1>
        <p>{{$route.params.id}}</p>
        <router-link to="/user/22">去22</router-link>
    </div>
</template>

<script>
    export  default {
        created() {
            console.log("created");
        },
        // 使用導航守衛
        beforeRouteUpdate (to, from, next) {
            // react to route changes...
            // don't forget to call next()
            console.log(to, from , next);
        }
    }
</script>

三、嵌套路由(子路由)

若是咱們想實現/user/12/more或者是user/userother這類的路由,並且要在user組件下去動態匹配內容的顯示。這時候就可使用咱們的嵌套路由。

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User,
      children: [
        {
          // 當 /user/:id/profile 匹配成功,
          // UserProfile 會被渲染在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 當 /user/:id/posts 匹配成功
          // UserPosts 會被渲染在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  ]
})

這時候對咱們的User組件也須要作必定的處理,添加一個<router-view></router-view>

const User = {
  template: `
    <div class="user">
      <h2>User {{ $route.params.id }}</h2>
      <router-view></router-view>
    </div>
  `
}

這時候咱們匹配/user/12/profile這些都是能夠的了~

觸發跳轉能夠是:

<router-link :to="'/userprofile'+ $route.params.id +'/'"></router-link>
// 或者是

<router-link :to="profile" append></router-link>

若是沒匹配到,咱們想要讓他顯示一個提示性的頁面的時候,在怎麼作呢?

定義一個空白子路由,若是匹配不到路由會匹配該路由。

const router = new VueRouter({
  routes: [
    {
      path: '/user/:id', component: User,
      children: [
        // 當 /user/:id 匹配成功,
        // UserHome 會被渲染在 User 的 <router-view> 中
        { path: '', component: UserHome },

        // ...其餘子路由
      ]
    }
  ]
})

四、編程式路由

有時候咱們須要js去動態的跳轉路由,編程式路由很合適。

在 Vue 實例內部,你能夠經過 $router 訪問路由實例。所以你能夠調用 this.$router.push。這個方法會向 history 棧添加一個新的記錄,因此,當用戶點擊瀏覽器後退按鈕時,則回到以前的 URL。

clipboard.png

// 字符串
router.push('home')

// 對象
router.push({ path: 'home' })

// 命名的路由,提供路由的名稱
router.push({ name: 'user', params: { userId: 123 }})

// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意點: 若是提供了 path,params 會被忽略,上述例子中的 query 並不屬於這種狀況。取而代之的是下面例子的作法,你須要提供路由的 name 或手寫完整的帶有參數的 path:
const userId = 123
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123

// 這裏的 params 不生效,因此不要這麼寫
router.push({ path: '/user', params: { userId }}) // -> /user

router.replace(location, onComplete?, onAbort?)

跟 router.push 很像,惟一的不一樣就是,它不會向 history 添加新記錄,而是跟它的方法名同樣 —— 替換掉當前的 history 記錄。以後回退是不會回退回去的,由於history隊列中已經沒了

router.go(n)

這個方法的參數是一個整數,意思是在 history 記錄中向前或者後退多少步,相似 window.history.go(n)。

// 在瀏覽器記錄中前進一步,等同於 history.forward()
router.go(1)

// 後退一步記錄,等同於 history.back()
router.go(-1)

// 前進 3 步記錄
router.go(3)

// 若是 history 記錄不夠用,那就默默地失敗唄
router.go(-100)
router.go(100)

clipboard.png

五、路由的兩種模式(前端路由)

vue-router路由提供了兩種路由模式:hash模式和history模式。

hash模式

它是利用hash來模擬完整的Url,經過hashChange來監聽hash變化,當頁面變化的時候不會刷新頁面。

history模式

若是不想要很醜的 hash,咱們能夠用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須從新加載頁面。

//設置mode屬性,設置路由模式
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

不過這種模式要玩好,還須要後臺配置支持。由於咱們的應用是個單頁客戶端應用,若是後臺沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就很差看了。

六、路由導航鉤子

vue-router提供了一些導航守衛來,控制咱們的路由跳轉和守衛導航。有多種機會植入路由導航過程當中:全局的, 單個路由獨享的, 或者組件級的。

全局守衛【全局前置守衛】

const router = new VueRouter({ ... })

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

導航守衛是異步的,所以導航在守衛完成以前都是等待狀態,所以須要 咱們手動resolve.

  • to: 要進入的目標路由
  • from: 要離開的路由
  • next: 必定要調用該方法來 resolve 這個鉤子

    next();必定要調用該方法來 resolve 這個鉤子
    next(false): 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。
    next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前導航中斷。

確保要調用 next 方法,不然鉤子就不會被 resolved。

路由獨享的守衛

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`
  }
}

使用場景:

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 經過 `vm` 訪問組件實例
  })
}
// 路由發生變化的時候
beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

這個離開守衛一般用來禁止用戶在還未保存修改前忽然離開。該導航能夠經過 next(false) 來取消。

beforeRouteLeave (to, from , next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

七、完整的導航解析流程

導航被觸發。
在失活的組件裏調用離開守衛。
調用全局的 beforeEach 守衛。
在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
在路由配置裏調用 beforeEnter。
解析異步路由組件。
在被激活的組件裏調用 beforeRouteEnter。
調用全局的 beforeResolve 守衛 (2.5+)。
導航被確認。
調用全局的 afterEach 鉤子。
觸發 DOM 更新。
用建立好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。

好長呀,感受記不住:

咱們來簡化如下,記住一些關鍵步驟。

本組件調用離開守衛 -- 全局的beforeEach -- 全局的before Resolve -- 導航確認,-- 調用全局的afterEach -- DOM更新 --

相關文章
相關標籤/搜索