VUE 常問知識(shí)點(diǎn)

  • 1.v-if 和v-show區(qū)別

v-if 真正條件渲染 DOM切換 銷毀 重建,不停的銷毀和創(chuàng)建比較消耗性能。
v-show本質(zhì)就是通過控制css中的display設(shè)置為none,控制隱藏,只會(huì)編譯一次;

  • 2 .created()和mounted()的區(qū)別

created()最早使用data中的數(shù)據(jù) mounted()最早操作dom節(jié)點(diǎn)的函數(shù)
接口請求一般放在mounted中,但需要注意的是服務(wù)端渲染時(shí)不支持mounted,需要放到created中。

  • 3.vue中data為什么必須是一個(gè)函數(shù)

1.data是一個(gè)函數(shù)時(shí),每個(gè)組件實(shí)例都有自己的作用域,每個(gè)實(shí)例相互獨(dú)立,不會(huì)相互影響。Object是引用數(shù)據(jù)類型,如果不用function返回,每個(gè)組件的data都是內(nèi)存的同一個(gè)地址,一個(gè)數(shù)據(jù)改變了其他也改變了
2.對象為引用類型,當(dāng)重用組件時(shí),由于數(shù)據(jù)對象都指向同一個(gè)data對象,當(dāng)在一個(gè)組件中修改data時(shí),其他重用的組件中的data會(huì)同時(shí)被修改;而使用返回對象的函數(shù),由于每次返回的都是一個(gè)新對象(Object的實(shí)例),引用地址不同,則不會(huì)出現(xiàn)這個(gè)問題。

  • 4.watch、computed和methods的區(qū)別

computed 計(jì)算屬性 計(jì)算結(jié)果會(huì)緩存,只有當(dāng)依賴值改變才會(huì)重新計(jì)算
watch 監(jiān)聽屬性 一個(gè)值的改變 需要另一個(gè)值的改變而改變,結(jié)果不會(huì)緩存
methods 事件方法 調(diào)用一次,執(zhí)行一次,結(jié)果不會(huì)緩存

  • 5. mvvm的理解

mvvm主要解決mvc中大量使用DOM,使頁面渲染性能降低,加載速度變慢,影響使用體驗(yàn),mvc模式當(dāng)mode發(fā)生變化,開發(fā)者需要主動(dòng)更新view

  • 6.template 只有一個(gè)根元素

每一個(gè)組件的本質(zhì)就是Vue實(shí)例,既然是Vue的實(shí)例就需要一個(gè)根入口,如果沒有,多個(gè)div就無法指定Vue的實(shí)例根入口,就像HTML只有一個(gè)根元素一樣,多個(gè)根元素?zé)o法構(gòu)成一棵樹,所以template只有一個(gè)根元素。

  • 7.vue中怎么重置data

Object.assign()方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對象復(fù)制到目標(biāo)對象
this.$data獲取當(dāng)前狀態(tài)下的data
this.$options.data()獲取該組件初始狀態(tài)下的data。
Object.assign(this.$data, this.$options.data())

  • 8.Object.defineProperty的理解

Object.defineProperty定義新屬性或修改原有的屬性;
vue的數(shù)據(jù)雙向綁定的原理就是用的Object.defineProperty這個(gè)方法,里面定義了setter和getter方法,通過觀察者模式(發(fā)布訂閱模式)來監(jiān)聽數(shù)據(jù)的變化,從而做相應(yīng)的邏輯處理。

  • 9.vue組件會(huì)在什么時(shí)候下被銷毀?

頁面關(guān)閉、路由跳轉(zhuǎn)、v-if和改變key值

  • 10.vue的is這個(gè)特性

vue中is的屬性引入是為了解決dom結(jié)構(gòu)中對放入html的元素有限制的問題;
動(dòng)態(tài)組件的例子

<ul><li is='my-component'></li></ul>
  <div id="app">
    <button @click="switchComp('A')">首頁 -- 點(diǎn)我顯示A 組件 </button>
    <button @click="switchComp('B')">推薦頁 -- 點(diǎn)我顯示B 組件</button>
    <button @click="switchComp('C')">搜索 -- 點(diǎn)我顯示 C 組件</button>
    <button @click="switchComp('D')">點(diǎn)我顯示 D組件 </button>
    <component :is="currentComp"></component>  <!--  is  -->
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    Vue.component('componentA', {
      template: '<div>你好呀~ 歡迎來到首頁 ~~ </div>'
    });
    Vue.component('componentB',{
      template: '<div>你好呀~  歡迎來到推薦頁 ~~ </div>'
    });
    Vue.component('componentC',{
      template: '<div> 你好呀~  歡迎來到搜索頁 ~~ </div>'
    })
    let componentD = {
      template: '<div>D</div>'
    }
  let app = new Vue({
    el: '#app',
    components: { componentD },
    data: {
      currentComp: 'componentA'
    },
    methods: {
      switchComp(tag) {
        this.currentComp = 'component' + tag
      }
    } 
  })
  </script>
  • 11.vue的:class和:style有幾種表示方式?

:class 1.綁定變量 2.綁定對象 3.綁定一個(gè)數(shù)組 4.綁定三元表達(dá)式
:style 1.綁定變量 2.綁定對象 3.綁定函數(shù)返回值 4.綁定三元表達(dá)式

  • 12.怎么在watch監(jiān)聽開始之后立即被調(diào)用?

watch時(shí)有一個(gè)特點(diǎn),就是當(dāng)值第一次綁定的時(shí)候,不會(huì)執(zhí)行監(jiān)聽函數(shù),只有值發(fā)生改變才會(huì)執(zhí)行。如果我們需要在最初綁定值的時(shí)候也執(zhí)行函數(shù),則就需要用到immediate屬性。

  let vm=new Vue({
        el:"#first",
        data:{msg:'liuneng'},
        watch:{

            msg:{
                handler (newMsg,oldMsg){
                    console.log(newMsg);
                },
                immediate:true  //設(shè)置immediate屬性為true
            }
        }
    })
  • 13.Vue怎么在路由中配置404頁面

在router.js中,由于路由是從上到下執(zhí)行的,只要在路由配置中最后面放個(gè)*號(hào)就可以了,例如:
最后一個(gè)就是404

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/index'
import na from '@/components/newDetail'
import ga from '@/components/goodlist'
import notfount from '@/components/404'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/newDetail',
      name: 'newDetail',
      component: na
    },
    {
      path: '/goodlist',
      name: 'goodlist',
      component: ga
    },
    {
  path: '*',
    name: 'notfount',
    component: notfount
    }
  ]
})
  • 14.CLI2 Runtime-Compiler和Runtime-only的區(qū)別

runtime-compiler(v1)(運(yùn)行過程)): template -> ast -> render -> vdom -> UI
runtime-only(v2 1.性能更高, 2.代碼量更少):render -> vdom -> UI
那.vue文件中的template是由誰處理的呢? 是由vue-template-compiler這個(gè)開發(fā)時(shí) 工具依賴來處理的,他將.vue文件解析成了render函數(shù),解析之后,是沒有tamplate這個(gè) 東西的
總結(jié):
如果在開發(fā)中,依然使用template,就需要選擇Runtime-Compiler
如果在開發(fā)中,使用的是.vue文件夾開發(fā),那么可以選擇Runtime-Only

  • 15.強(qiáng)制更新組件的方法有哪些?分別有何利弊?

簡單粗暴的方式:重新加載整個(gè)頁面
不妥的方式:使用 v-if
較好的方法:使用Vue的內(nèi)置forceUpdate方法
最好的方法:在組件上進(jìn)行 key 更改

調(diào)用強(qiáng)制更新方法this.$forceUpdate()會(huì)更新視圖和數(shù)據(jù),觸發(fā)updated生命周期。

<button @click="reload()">強(qiáng)制更新</button>
updated(){
      console.log("更新了");
  },
  methods:{
      reload(){
          this.$forceUpdate();
      }
  }
  • 16.什么是虛擬DOM?

虛擬DOM是:用JS來模擬一顆 DOM 樹,放在瀏覽器內(nèi)存中
當(dāng)你要改變時(shí),虛擬 DOM 使用 diff 算法進(jìn)行 新舊虛擬 dom 的比較將修改了的更新到實(shí)際的 DOM 樹,減少了 DOM 操作
虛擬 dom 是相對于瀏覽器所渲染出來的真實(shí) dom 的,在react,vue等技術(shù)出現(xiàn)之前,我們要改變頁面展示的內(nèi)容只能通過遍歷查詢 dom 樹的方式找到需要修改的 dom 然后修改樣式行為或者結(jié)構(gòu),來達(dá)到更新 ui 的目的。這種方式相當(dāng)消耗計(jì)算資源,因?yàn)槊看尾樵?dom 幾乎都需要遍歷整顆 dom 樹,如果建立一個(gè)與 dom 樹對應(yīng)的虛擬 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那么每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象的屬性變化要比查詢 dom 樹的性能開銷小。

  • 17.vue組件之間的通信都有哪些?

父子Coms: 1/2/3 ..
兄弟Coms: 4/5
跨級(jí)Coms: 4/5/6/7
1.props
2.$emit/$on
3.( $parents/$children ) / $refs
4.Vuex
5.Bus
6.( provide/inject )
7.( $attrs/$listeners )

  • 18.route 和$router的區(qū)別

$router是new Router的實(shí)例,是全局路由對象,用于進(jìn)行路由跳轉(zhuǎn)等操作,想要導(dǎo)航到不同 URL,則使用 $router.push 方法;
$route是路由信息對象,表示當(dāng)前活躍的路由對象,用于讀取路由參數(shù);可以從里面獲取name,path,params,query等;
簡單來說也就是,操作找$router,讀參找$route。

  • 19.@click 綁定多個(gè)事件?
1,v-on綁定多個(gè)方法多個(gè)函數(shù)?:
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>
一個(gè)事件綁定多個(gè)函數(shù):
<p @click="one(),two()">點(diǎn)擊</p>
  • 20.切換到新路由時(shí),頁面要滾動(dòng)到頂部或保持原先的滾動(dòng)位置

在路由實(shí)例中配置
scrollBehavior(ro,form,savedPosition){
//滾動(dòng)到頂部
return {x:0,y:0}
//保持原先的滾動(dòng)位置
return {selector:falsy}
}

  • 21.vue 修飾符sync的功能

vue 修飾符sync的功能是:當(dāng)一個(gè)子組件改變了一個(gè) prop 的值時(shí),這個(gè)變化也會(huì)同步到父組件中所綁定,這樣就實(shí)現(xiàn)了prop的雙向綁定。

  • 22.vue complier

compiler模塊Vue框架中用于模板編譯的,它的作用就是將Vue中的組件模板轉(zhuǎn)換成render函數(shù),render函數(shù)在運(yùn)行時(shí)可以生成虛擬節(jié)點(diǎn)vnode,它是Vue中虛擬DOM樹的基本實(shí)現(xiàn)流程。完整版的Vue是包含runtime和compiler的,也就是說模板的編譯過程可以在運(yùn)行時(shí)進(jìn)行,這無疑是一種性能負(fù)擔(dān)。Vue官方也提供了獨(dú)立的runtime版本,其中只包含運(yùn)行時(shí)環(huán)境,把從template到render函數(shù)的生成部分放在構(gòu)建時(shí)完成(利用vue-templete-compiler模塊),以提高運(yùn)行時(shí)的效率。

  • 23.Vue.use() 作用

提供install 方法,只是為了讓 Vue 可以將組件注冊到框架里去,使其能夠被全局使用。

  • 24.怎么解決vue動(dòng)態(tài)設(shè)置img的src不生效的問題?

因?yàn)閯?dòng)態(tài)添加src被當(dāng)做靜態(tài)資源處理了,沒有進(jìn)行編譯,所以要加上require。
<img :src="require('@/assets/images/xxx.png')" />

  • 25.怎么解決vue打包后靜態(tài)資源圖片失效的問題?

找到config/index.js 配置文件,找build打包對象里的assetsPublicPath屬性
默認(rèn)值為/,更改為./就好了
最新的vue-cli 需要在根目錄下建一個(gè)vue.config.js 在里面配置publicPath即可

  • 26.vue渲染模板時(shí)怎么保留模板中的HTML注釋呢?

設(shè)置comments屬性,官網(wǎng)默認(rèn)為舍棄注釋
<template comments> ... </template>

  • 27.vue中使用插件的步驟?

安裝:npm install xxx
引入: import ... from ...;
使用:Vue.use(xxx)

  • 28.vue中引入組件有幾種方式?

兩種:采用 ES6 的 import ... from ... 語法或 CommonJS 的 require() 方法引入組件

//方法一
import Calendar from "./calendar";
export default {
  name: "SymptomMain",
  components: {
    Calendar
  },
}
//方法二
export default {
//1.直接在components中寫入子組件
components: {
    Calendar:require('./calendar.vue').default
  },
}
  • 29.vue-router 有哪幾種導(dǎo)航鉤子

1.全局導(dǎo)航鉤子 作用:跳轉(zhuǎn)前進(jìn)行判斷攔截。
router.beforeEach(to,from,next);
router.beforeResolve(to,from,next);
router.afterEach(to,from,next);

2.組件內(nèi)鉤子
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

3.單獨(dú)路由獨(dú)享組件
beforeEnter

  • 30.v-model的原理

原生input其實(shí)只是一個(gè)語法糖
:bind="value"與@change="value = $event.target.value"的結(jié)合。

  • 31.父組件怎么接收子組件的多個(gè)參數(shù)

this.$emit("eventName",data)
data為一個(gè)對象
data 對象或數(shù)組都可以的。

  • 32.怎么解決vue動(dòng)態(tài)設(shè)置img的src不生效的問題?

因?yàn)閯?dòng)態(tài)添加src被當(dāng)做靜態(tài)資源處理了,沒有進(jìn)行編譯,所以要加上require。

<img :src="require('../../../assets/images/xxx.png')" />
  • 33.keep-alive有關(guān)的生命周期是哪些?描述下這些生命周期

activated和deactivated
keep-alive的生命周期
1.activated: 頁面第一次進(jìn)入的時(shí)候,鉤子觸發(fā)的順序是created->mounted->activated
2.deactivated: 頁面退出的時(shí)候會(huì)觸發(fā)deactivated,當(dāng)再次前進(jìn)或者后退的時(shí)候只觸發(fā)activated

  • 34.vue中怎么重置data?

Object.assign()方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對象復(fù)制到目標(biāo)對象。

this.$data獲取當(dāng)前狀態(tài)下的data
this.$options.data()獲取該組件初始狀態(tài)下的data。
Object.assign(this.$data, this.$options.data())

  • 35.在vue事件中傳入$event,使用e.target和e.currentTarget有什么區(qū)別?

currentTarget:事件綁定的元素
target:鼠標(biāo)觸發(fā)的元素
event.currentTarget指向事件所綁定的元素,而event.target始終指向事件發(fā)生時(shí)的元素。

  • 36.vue如果想擴(kuò)展某個(gè)現(xiàn)有的組件時(shí),怎么做呢?

1.使用Vue.extend直接擴(kuò)展
2.使用Vue.mixin全局混入
3.HOC封裝
4.slot擴(kuò)展

  • 36.v-once的使用場景

v-once這個(gè)指令不需要任何表達(dá)式,它的作用就是定義它的元素或組件只會(huì)渲染一次,包括元素或者組件的所有字節(jié)點(diǎn)。首次渲染后,不再隨著數(shù)據(jù)的改變而重新渲染。也就是說使用v-once,那么該塊都將被視為靜態(tài)內(nèi)容。<div v-once>{{count}}</div>

  • 37.表單修飾符和事件修飾符

事件修飾符.stop .prevent .capture .self .once .passive
表單修飾符.number .lazy .trim

  • 38.v-clock和v-pre指令

v-cloak指令只是在標(biāo)簽中加入一個(gè)v-cloak自定義屬性,在HTML還編譯完成之后該屬性會(huì)被刪除。
v-pre可以用來阻止預(yù)編譯,有v-pre指令的標(biāo)簽內(nèi)部的內(nèi)容不會(huì)被編譯,會(huì)原樣輸出。

  • 39.proxy的理解

vue的數(shù)據(jù)劫持有兩個(gè)缺點(diǎn):

1、無法監(jiān)聽通過索引修改數(shù)組的值的變化
2、無法監(jiān)聽object也就是對象的值的變化

所以vue2.x中才會(huì)有$set屬性的存在
proxy是es6中推出的新api,可以彌補(bǔ)以上兩個(gè)缺點(diǎn),所以vue3.x版本用proxy替換object.defineproperty

  • 40. Proxy只會(huì)代理對象的第一層,那么Vue3又是怎樣處理這個(gè)問題的呢?

判斷當(dāng)前Reflect.get的返回值是否為Object,如果是則再通過reactive方法做代理, 這樣就實(shí)現(xiàn)了深度觀測。

  • 41. 監(jiān)測數(shù)組的時(shí)候可能觸發(fā)多次get/set,那么如何防止觸發(fā)多次呢?

我們可以判斷key是否為當(dāng)前被代理對象target自身屬性,也可以判斷舊值與新值是否相等,只有滿足以上兩個(gè)條件之一時(shí),才有可能執(zhí)行trigger。

  • 42.父組件可以監(jiān)聽到子組件的生命周期嗎?

可以通過@hook來監(jiān)聽生命周期事件,用法如下:

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
   console.log('父組件監(jiān)聽到 mounted 鉤子函數(shù) ...');
},
    
//  Child.vue
mounted(){
   console.log('子組件觸發(fā) mounted 鉤子函數(shù) ...');
},    
    
// 以上輸出順序?yàn)椋?// 子組件觸發(fā) mounted 鉤子函數(shù) ...
// 父組件監(jiān)聽到 mounted 鉤子函數(shù) ... 
  • 43.Vue實(shí)現(xiàn)數(shù)據(jù)雙向綁定的原理:Object.defineProperty()

1.vue實(shí)現(xiàn)數(shù)據(jù)雙向綁定主要是:采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個(gè)屬性的setter,getter,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)監(jiān)聽回調(diào)。當(dāng)把一個(gè)普通 Javascript 對象傳給 Vue 實(shí)例來作為它的 data 選項(xiàng)時(shí),Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter。用戶看不到 getter/setter,但是在內(nèi)部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時(shí)通知變化。
2.vue的數(shù)據(jù)雙向綁定 將MVVM作為數(shù)據(jù)綁定的入口,整合Observer,Compile和Watcher三者,通過Observer來監(jiān)聽自己的model的數(shù)據(jù)變化,通過Compile來解析編譯模板指令(vue中是用來解析 {{}}),最終利用watcher搭起observer和Compile之間的通信橋梁,達(dá)到數(shù)據(jù)變化 —>視圖更新;視圖交互變化(input)—>數(shù)據(jù)model變更雙向綁定效果。
3.通過Observer 把數(shù)據(jù)劫持(Object.defineProperty()) 、加入到訂閱器(Dep) 訂閱器收集訂閱者(Watcher )、視圖通過編譯(Compile)、解析指令(Directive)等一些列操作收集給訂閱者 、最后通過觸發(fā)數(shù)據(jù)變化update 通知所有訂閱者完成數(shù)據(jù)驅(qū)動(dòng)

  • 44.服務(wù)端渲染(SSR)和預(yù)渲染(Prerendering)有什么區(qū)別?

1.服務(wù)端渲染的過程為:解析執(zhí)行JS => 構(gòu)建HTML頁面 => 輸出給瀏覽器
2.預(yù)渲染:直接輸出HTML頁面給瀏覽器

  • 45.vue從data改變到頁面渲染的過程

(1)把模板編譯為render函數(shù)
(2)實(shí)例進(jìn)行掛載,根據(jù)節(jié)點(diǎn)render函數(shù)的調(diào)用,遞歸的生成虛擬dom;
(3)對比虛擬dom,渲染真實(shí)dom;
(4)組件內(nèi)部data發(fā)生變化,組件和子組件引用data作為props重新調(diào)用render函數(shù)生成虛擬dom返回 對比虛擬dom,渲染真實(shí)dom的操作;

  • 46 介紹一下Vue的響應(yīng)式系統(tǒng)

Vue為MVVM框架,當(dāng)數(shù)據(jù)模型data變化時(shí),頁面視圖會(huì)得到響應(yīng)更新,其原理對data的getter/setter方法進(jìn)行攔截(Object.defineProperty或者Proxy),利用發(fā)布訂閱的設(shè)計(jì)模式,在getter方法中進(jìn)行訂閱,在setter方法中發(fā)布通知,讓所有訂閱者完成響應(yīng)。
在響應(yīng)式系統(tǒng)中,Vue會(huì)為數(shù)據(jù)模型data的每一個(gè)屬性新建一個(gè)訂閱中心作為發(fā)布者,而監(jiān)聽器watch、計(jì)算屬性computed、視圖渲染template/render三個(gè)角色同時(shí)作為訂閱者,對于監(jiān)聽器watch,會(huì)直接訂閱觀察監(jiān)聽的屬性,對于計(jì)算屬性computed和視圖渲染template/render,如果內(nèi)部執(zhí)行獲取了data的某個(gè)屬性,就會(huì)執(zhí)行該屬性的getter方法,然后自動(dòng)完成對該屬性的訂閱,當(dāng)屬性被修改時(shí),就會(huì)執(zhí)行該屬性的setter方法,從而完成該屬性的發(fā)布通知,通知所有訂閱者進(jìn)行更新。

  • 47computed與watch的區(qū)別

計(jì)算屬性computed和監(jiān)聽器watch都可以觀察屬性的變化從而做出響應(yīng),不同的是:

計(jì)算屬性computed更多是作為緩存功能的觀察者,它可以將一個(gè)或者多個(gè)data的屬性進(jìn)行復(fù)雜的計(jì)算生成一個(gè)新的值,提供給渲染函數(shù)使用,當(dāng)依賴的屬性變化時(shí),computed不會(huì)立即重新計(jì)算生成新的值,而是先標(biāo)記為臟數(shù)據(jù),當(dāng)下次computed被獲取時(shí)候,才會(huì)進(jìn)行重新計(jì)算并返回。

而監(jiān)聽器watch并不具備緩存性,監(jiān)聽器watch提供一個(gè)監(jiān)聽函數(shù),當(dāng)監(jiān)聽的屬性發(fā)生變化時(shí),會(huì)立即執(zhí)行該函數(shù)。

  • 48介紹一下Vue的生命周期

beforeCreate:是new Vue()之后觸發(fā)的第一個(gè)鉤子,在當(dāng)前階段data、methods、computed以及watch上的數(shù)據(jù)和方法都不能被訪問。

created:在實(shí)例創(chuàng)建完成后發(fā)生,當(dāng)前階段已經(jīng)完成了數(shù)據(jù)觀測,也就是可以使用數(shù)據(jù),更改數(shù)據(jù),在這里更改數(shù)據(jù)不會(huì)觸發(fā)updated函數(shù)??梢宰鲆恍┏跏紨?shù)據(jù)的獲取,在當(dāng)前階段無法與Dom進(jìn)行交互,如果非要想,可以通過vm.$nextTick來訪問Dom。

beforeMount:發(fā)生在掛載之前,在這之前template模板已導(dǎo)入渲染函數(shù)編譯。而當(dāng)前階段虛擬Dom已經(jīng)創(chuàng)建完成,即將開始渲染。在此時(shí)也可以對數(shù)據(jù)進(jìn)行更改,不會(huì)觸發(fā)updated。

mounted:在掛載完成后發(fā)生,在當(dāng)前階段,真實(shí)的Dom掛載完畢,數(shù)據(jù)完成雙向綁定,可以訪問到Dom節(jié)點(diǎn),使用$refs屬性對Dom進(jìn)行操作。

beforeUpdate:發(fā)生在更新之前,也就是響應(yīng)式數(shù)據(jù)發(fā)生更新,虛擬dom重新渲染之前被觸發(fā),你可以在當(dāng)前階段進(jìn)行更改數(shù)據(jù),不會(huì)造成重渲染。

updated:發(fā)生在更新完成之后,當(dāng)前階段組件Dom已完成更新。要注意的是避免在此期間更改數(shù)據(jù),因?yàn)檫@可能會(huì)導(dǎo)致無限循環(huán)的更新。

beforeDestroy:發(fā)生在實(shí)例銷毀之前,在當(dāng)前階段實(shí)例完全可以被使用,我們可以在這時(shí)進(jìn)行善后收尾工作,比如清除計(jì)時(shí)器。

destroyed:發(fā)生在實(shí)例銷毀之后,這個(gè)時(shí)候只剩下了dom空殼。組件已被拆解,數(shù)據(jù)綁定被卸除,監(jiān)聽被移出,子實(shí)例也統(tǒng)統(tǒng)被銷毀。

  • 49為什么組件的data必須是一個(gè)函數(shù)

一個(gè)組件可能在很多地方使用,也就是會(huì)創(chuàng)建很多個(gè)實(shí)例,如果data是一個(gè)對象的話,對象是引用類型,一個(gè)實(shí)例修改了data會(huì)影響到其他實(shí)例,所以data必須使用函數(shù),為每一個(gè)實(shí)例創(chuàng)建一個(gè)屬于自己的data,使其同一個(gè)組件的不同實(shí)例互不影響。

  • 50組件之間是怎么通信的

父子組件通信
父組件 -> 子組件:prop

子組件 -> 父組件:on/emit

獲取組件實(shí)例:使用parent/children,$refs.xxx,獲取到實(shí)例后直接獲取屬性數(shù)據(jù)或調(diào)用組件方法

兄弟組件通信
Event Bus:每一個(gè)Vue實(shí)例都是一個(gè)Event Bus,都支持on/emit,可以為兄弟組件的實(shí)例之間new一個(gè)Vue實(shí)例,作為Event Bus進(jìn)行通信。

Vuex:將狀態(tài)和方法提取到Vuex,完成共享

跨級(jí)組件通信
使用provide/inject

Event Bus:同兄弟組件Event Bus通信

Vuex:將狀態(tài)和方法提取到Vuex,完成共享

  • 51 Vue事件綁定原理說一下

每一個(gè)Vue實(shí)例都是一個(gè)Event Bus,當(dāng)子組件被創(chuàng)建的時(shí)候,父組件將事件傳遞給子組件,子組件初始化的時(shí)候是有$on方法將事件注冊到內(nèi)部,在需要的時(shí)候使用$emit觸發(fā)函數(shù),而對于原生native事件,使用addEventListener綁定到真實(shí)的DOM元素上。

  • 52 slot是什么?有什么作用?原理是什么?

slot又名插槽,是Vue的內(nèi)容分發(fā)機(jī)制,組件內(nèi)部的模板引擎使用slot元素作為承載分發(fā)內(nèi)容的出口。插槽slot是子組件的一個(gè)模板標(biāo)簽元素,而這一個(gè)標(biāo)簽元素是否顯示,以及怎么顯示是由父組件決定的。

slot又分三類,默認(rèn)插槽,具名插槽和作用域插槽。

默認(rèn)插槽:又名匿名查抄,當(dāng)slot沒有指定name屬性值的時(shí)候一個(gè)默認(rèn)顯示插槽,一個(gè)組件內(nèi)只有有一個(gè)匿名插槽。
具名插槽:帶有具體名字的插槽,也就是帶有name屬性的slot,一個(gè)組件可以出現(xiàn)多個(gè)具名插槽。
作用域插槽:默認(rèn)插槽、具名插槽的一個(gè)變體,可以是匿名插槽,也可以是具名插槽,該插槽的不同點(diǎn)是在子組件渲染作用域插槽時(shí),可以將子組件內(nèi)部的數(shù)據(jù)傳遞給父組件,讓父組件根據(jù)子組件的傳遞過來的數(shù)據(jù)決定如何渲染該插槽。
實(shí)現(xiàn)原理:當(dāng)子組件vm實(shí)例化時(shí),獲取到父組件傳入的slot標(biāo)簽的內(nèi)容,存放在vm.$slot中,默認(rèn)插槽為vm.$slot.default,具名插槽為vm.$slot.xxx,xxx 為插槽名,當(dāng)組件執(zhí)行渲染函數(shù)時(shí)候,遇到slot標(biāo)簽,使用$slot中的內(nèi)容進(jìn)行替換,此時(shí)可以為插槽傳遞數(shù)據(jù),若存在數(shù)據(jù),則可稱該插槽為作用域插槽。

  • 53 Vue模板渲染的原理是什么?

vue中的模板template無法被瀏覽器解析并渲染,因?yàn)檫@不屬于瀏覽器的標(biāo)準(zhǔn),不是正確的HTML語法,所有需要將template轉(zhuǎn)化成一個(gè)JavaScript函數(shù),這樣瀏覽器就可以執(zhí)行這一個(gè)函數(shù)并渲染出對應(yīng)的HTML元素,就可以讓視圖跑起來了,這一個(gè)轉(zhuǎn)化的過程,就成為模板編譯。

模板編譯又分三個(gè)階段,解析parse,優(yōu)化optimize,生成generate,最終生成可執(zhí)行函數(shù)render。

parse階段:使用大量的正則表達(dá)式對template字符串進(jìn)行解析,將標(biāo)簽、指令、屬性等轉(zhuǎn)化為抽象語法樹AST。
optimize階段:遍歷AST,找到其中的一些靜態(tài)節(jié)點(diǎn)并進(jìn)行標(biāo)記,方便在頁面重渲染的時(shí)候進(jìn)行diff比較時(shí),直接跳過這一些靜態(tài)節(jié)點(diǎn),優(yōu)化runtime的性能。
generate階段:將最終的AST轉(zhuǎn)化為render函數(shù)字符串。

  • 54 template預(yù)編譯是什么?

對于 Vue 組件來說,模板編譯只會(huì)在組件實(shí)例化的時(shí)候編譯一次,生成渲染函數(shù)之后在也不會(huì)進(jìn)行編譯。因此,編譯對組件的 runtime 是一種性能損耗。

而模板編譯的目的僅僅是將template轉(zhuǎn)化為render function,這個(gè)過程,正好可以在項(xiàng)目構(gòu)建的過程中完成,這樣可以讓實(shí)際組件在 runtime 時(shí)直接跳過模板渲染,進(jìn)而提升性能,這個(gè)在項(xiàng)目構(gòu)建的編譯template的過程,就是預(yù)編譯。

  • 55 template和jsx的有什么分別?

對于 runtime 來說,只需要保證組件存在 render 函數(shù)即可,而我們有了預(yù)編譯之后,我們只需要保證構(gòu)建過程中生成 render 函數(shù)就可以。

在 webpack 中,我們使用vue-loader編譯.vue文件,內(nèi)部依賴的vue-template-compiler模塊,在 webpack 構(gòu)建過程中,將template預(yù)編譯成 render 函數(shù)。

與 react 類似,在添加了jsx的語法糖解析器babel-plugin-transform-vue-jsx之后,就可以直接手寫render函數(shù)。

所以,template和jsx的都是render的一種表現(xiàn)形式,不同的是:

JSX相對于template而言,具有更高的靈活性,在復(fù)雜的組件中,更具有優(yōu)勢,而 template 雖然顯得有些呆滯。但是 template 在代碼結(jié)構(gòu)上更符合視圖與邏輯分離的習(xí)慣,更簡單、更直觀、更好維護(hù)。

  • 56 說一下什么是Virtual DOM

Virtual DOM 是 DOM 節(jié)點(diǎn)在 JavaScript 中的一種抽象數(shù)據(jù)結(jié)構(gòu),之所以需要虛擬DOM,是因?yàn)闉g覽器中操作DOM的代價(jià)比較昂貴,頻繁操作DOM會(huì)產(chǎn)生性能問題。虛擬DOM的作用是在每一次響應(yīng)式數(shù)據(jù)發(fā)生變化引起頁面重渲染時(shí),Vue對比更新前后的虛擬DOM,匹配找出盡可能少的需要更新的真實(shí)DOM,從而達(dá)到提升性能的目的。

  • 57 介紹一下Vue中的Diff算法

在新老虛擬DOM對比時(shí)

首先,對比節(jié)點(diǎn)本身,判斷是否為同一節(jié)點(diǎn),如果不為相同節(jié)點(diǎn),則刪除該節(jié)點(diǎn)重新創(chuàng)建節(jié)點(diǎn)進(jìn)行替換
如果為相同節(jié)點(diǎn),進(jìn)行patchVnode,判斷如何對該節(jié)點(diǎn)的子節(jié)點(diǎn)進(jìn)行處理,先判斷一方有子節(jié)點(diǎn)一方?jīng)]有子節(jié)點(diǎn)的情況(如果新的children沒有子節(jié)點(diǎn),將舊的子節(jié)點(diǎn)移除)
比較如果都有子節(jié)點(diǎn),則進(jìn)行updateChildren,判斷如何對這些新老節(jié)點(diǎn)的子節(jié)點(diǎn)進(jìn)行操作(diff核心)。
匹配時(shí),找到相同的子節(jié)點(diǎn),遞歸比較子節(jié)點(diǎn)
在diff中,只對同層的子節(jié)點(diǎn)進(jìn)行比較,放棄跨級(jí)的節(jié)點(diǎn)比較,使得時(shí)間復(fù)雜從O(n^3)降低值O(n),也就是說,只有當(dāng)新舊children都為多個(gè)子節(jié)點(diǎn)時(shí)才需要用核心的Diff算法進(jìn)行同層級(jí)比較。

  • 58 key屬性的作用是什么

key值得作用:增加唯一性,更高效的更新虛擬DOM,便于diff算法的更新,key值得唯一性更快的更新虛擬DOM。

diff算法對DOM進(jìn)行原地復(fù)用,減少DOM性能耗費(fèi)。

  • 59 說說Vue2.0和Vue3.0有什么區(qū)別

重構(gòu)響應(yīng)式系統(tǒng),使用Proxy替換Object.defineProperty,使用Proxy優(yōu)勢:

可直接監(jiān)聽數(shù)組類型的數(shù)據(jù)變化
監(jiān)聽的目標(biāo)為對象本身,不需要像Object.defineProperty一樣遍歷每個(gè)屬性,有一定的性能提升
可攔截apply、ownKeys、has等13種方法,而Object.defineProperty不行
直接實(shí)現(xiàn)對象屬性的新增/刪除
新增Composition API,更好的邏輯復(fù)用和代碼組織

重構(gòu) Virtual DOM

模板編譯時(shí)的優(yōu)化,將一些靜態(tài)節(jié)點(diǎn)編譯成常量
slot優(yōu)化,將slot編譯為lazy函數(shù),將slot的渲染的決定權(quán)交給子組件
模板中內(nèi)聯(lián)事件的提取并重用(原本每次渲染都重新生成內(nèi)聯(lián)函數(shù))
代碼結(jié)構(gòu)調(diào)整,更便于Tree shaking,使得體積更小

使用Typescript替換Flow

  • 60 為什么要新增Composition API,它能解決什么問題

Vue2.0中,隨著功能的增加,組件變得越來越復(fù)雜,越來越難維護(hù),而難以維護(hù)的根本原因是Vue的API設(shè)計(jì)迫使開發(fā)者使用watch,computed,methods選項(xiàng)組織代碼,而不是實(shí)際的業(yè)務(wù)邏輯。

另外Vue2.0缺少一種較為簡潔的低成本的機(jī)制來完成邏輯復(fù)用,雖然可以minxis完成邏輯復(fù)用,但是當(dāng)mixin變多的時(shí)候,會(huì)使得難以找到對應(yīng)的data、computed或者method來源于哪個(gè)mixin,使得類型推斷難以進(jìn)行。

所以Composition API的出現(xiàn),主要是也是為了解決Option API帶來的問題,第一個(gè)是代碼組織問題,Compostion API可以讓開發(fā)者根據(jù)業(yè)務(wù)邏輯組織自己的代碼,讓代碼具備更好的可讀性和可擴(kuò)展性,也就是說當(dāng)下一個(gè)開發(fā)者接觸這一段不是他自己寫的代碼時(shí),他可以更好的利用代碼的組織反推出實(shí)際的業(yè)務(wù)邏輯,或者根據(jù)業(yè)務(wù)邏輯更好的理解代碼。

第二個(gè)是實(shí)現(xiàn)代碼的邏輯提取與復(fù)用,當(dāng)然mixin也可以實(shí)現(xiàn)邏輯提取與復(fù)用,但是像前面所說的,多個(gè)mixin作用在同一個(gè)組件時(shí),很難看出property是來源于哪個(gè)mixin,來源不清楚,另外,多個(gè)mixin的property存在變量命名沖突的風(fēng)險(xiǎn)。而Composition API剛好解決了這兩個(gè)問題。

  • 61 都說Composition API與React Hook很像,說說區(qū)別

從React Hook的實(shí)現(xiàn)角度看,React Hook是根據(jù)useState調(diào)用的順序來確定下一次重渲染時(shí)的state是來源于哪個(gè)useState,所以出現(xiàn)了以下限制

不能在循環(huán)、條件、嵌套函數(shù)中調(diào)用Hook
必須確保總是在你的React函數(shù)的頂層調(diào)用Hook
useEffect、useMemo等函數(shù)必須手動(dòng)確定依賴關(guān)系
而Composition API是基于Vue的響應(yīng)式系統(tǒng)實(shí)現(xiàn)的,與React Hook的相比

聲明在setup函數(shù)內(nèi),一次組件實(shí)例化只調(diào)用一次setup,而React Hook每次重渲染都需要調(diào)用Hook,使得React的GC比Vue更有壓力,性能也相對于Vue來說也較慢
Compositon API的調(diào)用不需要顧慮調(diào)用順序,也可以在循環(huán)、條件、嵌套函數(shù)中使用
響應(yīng)式系統(tǒng)自動(dòng)實(shí)現(xiàn)了依賴收集,進(jìn)而組件的部分的性能優(yōu)化由Vue內(nèi)部自己完成,而React Hook需要手動(dòng)傳入依賴,而且必須必須保證依賴的順序,讓useEffect、useMemo等函數(shù)正確的捕獲依賴變量,否則會(huì)由于依賴不正確使得組件性能下降。
雖然Compositon API看起來比React Hook好用,但是其設(shè)計(jì)思想也是借鑒React Hook的。

  • 62 SSR有了解嗎?原理是什么?

在客戶端請求服務(wù)器的時(shí)候,服務(wù)器到數(shù)據(jù)庫中獲取到相關(guān)的數(shù)據(jù),并且在服務(wù)器內(nèi)部將Vue組件渲染成HTML,并且將數(shù)據(jù)、HTML一并返回給客戶端,這個(gè)在服務(wù)器將數(shù)據(jù)和組件轉(zhuǎn)化為HTML的過程,叫做服務(wù)端渲染SSR。

而當(dāng)客戶端拿到服務(wù)器渲染的HTML和數(shù)據(jù)之后,由于數(shù)據(jù)已經(jīng)有了,客戶端不需要再一次請求數(shù)據(jù),而只需要將數(shù)據(jù)同步到組件或者Vuex內(nèi)部即可。除了數(shù)據(jù)意外,HTML也結(jié)構(gòu)已經(jīng)有了,客戶端在渲染組件的時(shí)候,也只需要將HTML的DOM節(jié)點(diǎn)映射到Virtual DOM即可,不需要重新創(chuàng)建DOM節(jié)點(diǎn),這個(gè)將數(shù)據(jù)和HTML同步的過程,又叫做客戶端激活。

  • 63 使用SSR的好處:

有利于SEO:其實(shí)就是有利于爬蟲來爬你的頁面,因?yàn)椴糠猪撁媾老x是不支持執(zhí)行JavaScript的,這種不支持執(zhí)行JavaScript的爬蟲抓取到的非SSR的頁面會(huì)是一個(gè)空的HTML頁面,而有了SSR以后,這些爬蟲就可以獲取到完整的HTML結(jié)構(gòu)的數(shù)據(jù),進(jìn)而收錄到搜索引擎中。
白屏?xí)r間更短:相對于客戶端渲染,服務(wù)端渲染在瀏覽器請求URL之后已經(jīng)得到了一個(gè)帶有數(shù)據(jù)的HTML文本,瀏覽器只需要解析HTML,直接構(gòu)建DOM樹就可以。而客戶端渲染,需要先得到一個(gè)空的HTML頁面,這個(gè)時(shí)候頁面已經(jīng)進(jìn)入白屏,之后還需要經(jīng)過加載并執(zhí)行 JavaScript、請求后端服務(wù)器獲取數(shù)據(jù)、JavaScript 渲染頁面幾個(gè)過程才可以看到最后的頁面。特別是在復(fù)雜應(yīng)用中,由于需要加載 JavaScript 腳本,越是復(fù)雜的應(yīng)用,需要加載的 JavaScript 腳本就越多、越大,這會(huì)導(dǎo)致應(yīng)用的首屏加載時(shí)間非常長,進(jìn)而降低了體驗(yàn)感。

  • 64 vue 數(shù)組使用push pop 等為什么是響應(yīng)式的?

把數(shù)組原有的方法, 繼續(xù)執(zhí)行, 后面增加了ob.dep.notify() ,這個(gè)里面放著訂閱者模式里面的訂閱者,通過notify來通知訂閱者做處理

  • 65 render和template 的關(guān)系

1.性質(zhì)相同 都是類編譯器. 2. template=>render(創(chuàng)建)=》虛擬DOM(js對象)=》真實(shí)DOM. 3.互補(bǔ)的關(guān)系

  • 66 vuex為什么不建議在action中修改state

action的回調(diào)會(huì)被當(dāng)作普通函數(shù)執(zhí)行,而當(dāng)如果有多個(gè)聲明時(shí),它們是被視為Promise實(shí)例,并且用Promise.all執(zhí)行,總所周知,Promise.all在執(zhí)行Promise時(shí)是不保證順序的,也就是說,假如有3個(gè)Promise實(shí)例:P1、P2、P3,它們3個(gè)之中不一定哪個(gè)先有返回結(jié)果,那么我們仔細(xì)思考一下:如果同時(shí)在多個(gè)action中修改了同一個(gè)state,那會(huì)有什么樣的結(jié)果?

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

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