高級前端軟件工程師知識整理之Vue技術棧篇

1. 什麼是MVVM?

MVVM是Model-View-ViewModel的簡寫,它本質上就是MVC的改進版。MVVM就是將View的狀態和行爲抽象化,將視圖UI和業務邏輯分開,View和Model之間並沒有直接的聯繫,而是通過ViewModel進行交互,它們之間的交互是雙向的。

  • Model - 代表數據模型,定義了視圖的狀態或行爲。
  • View - 代表視圖,負責將數據模型轉化成可視化界面。
  • ViewModel - 負責監聽模型數據和視圖狀態或行爲的變化,同步了View和Model的對象,即實現了雙向綁定。

以下是Vue技術棧中一個雙向綁定的典型例子:

<div id="app6">
    <p>{{message}}</p>
    <input type="text" v-model="message" />
</div>
<script>
    var app6 = new Vue({
        el: "#app",
        data: {
            message: "HelloWorld"
        }
    });
</script>

示例中當修改input標籤中的內容時,p標籤的內容也會同步修改。

2. Vue的生命週期函數有哪些?

Vue生命週期:

名稱 描述
beforeCreate 實例剛被創建,vue所有屬性都還不存在
created 實例創建完成,但$el還不存在
beforeMount 掛載之前
mounted 掛載之後,即data中的數值已經被渲染到元素中
beforeUpdate 更新之前
updated 更新之後
activated <keep-alive>組件被激活時
deactivated <keep-alive>組件移除時
beforeDestroy 實例被銷燬前
destroyed 實例被銷燬後

示例:https://blog.csdn.net/zeping891103/article/details/78135698

3. Vue實現數據雙向綁定的原理是什麼?

雙向綁定的原理是利用Object.defineProperty()進行數據劫持,然後採用結合發佈者-訂閱者模式監聽數據的變化。當把一個 Javascript 對象傳給 Vue 實例來作爲它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉爲 getter/setter。如第一題中的雙向綁定的示例代碼,它的數據劫持方式爲:

var data = { message: 'HelloWorld' }
Object.defineProperty(data, 'message', {
    get: function () {
        return data.message;
    },
    set: function (newValue) {
    	data.message = 'newValue';
        // data-v-xxxxx爲Vue實例在初始化時給dom元素添加的唯一屬性值
        // 當message數據發生變化時,通知相關v-model綁定的元素也發生變化            
        document.getElementByAttr('input','data-v-xxxxx','').value = newValue; 
    }
})

另外,當input元素被v-modal綁定時,Vue實例爲該元素添加了一個input事件,當內容發生變化時,觸發this.$emit('input',' ')函數發出事件告訴Vue實例 data.message發生變化了,實現數據同步。更多有關Object.defineProperty的用法可以參考本系列的基礎篇(四)中有介紹。

發佈者-訂閱者模式的設計思想是發佈者管理所有相依於它的訂閱者,並且在發佈者本身的狀態改變時主動發出通知,訂閱者接到通知後開始響應變化並刷新。

4.Vue組件間的參數通過什麼方法傳遞?

1.父組件與子組件傳參
父組件傳給子組件:子組件通過props方法接受參數
子組件傳給父組件:$emit方法傳遞參數

示例:父組件向子組件mycomp傳遞參數message,並添加對子組件的cbmsg事件監聽

<template>
	<div>
		<p>{{callback_msg}}</p>
		<mycomp :message="message" @cbmsg="cbmsgHandle"  />
	</div>
</template>

<script>
	import mycomp from './vmcomp.vue';

	export default {
		name: '我是父組件',
		data() {
			return {
				message:'父組件向子組件傳參',
				callback_msg:''
			}
		},
		methods: {
			cbmsgHandle(response){
				this.callback_msg = response;
			}
		},
		components: {
			mycomp
		}
	}
</script>

子組件通過props屬性接收父組件傳入的參數,並通過觸發cbmsg事件向父組件傳遞參數

<template>
    <div>
        <p>{{message}}</p>
        <button @click="clickHandle">click</button>
    </div>
</template>

<script>
    export default {
        props: {
            message: {
                type: String,
                default: ''
            }
        },
        methods: {
            clickHandle() {
                this.$emit('cbmsg', '子組件向父組件傳參');
            }
        }
    }
</script>

2.非父子組件間的數據傳遞,兄弟組件傳值

使用事件總線EventBus,創建一個事件中心,相當於中轉站,可以用它來傳遞事件和接收事件。

示例:創建Bus

// vue-bus.js
const install = function(Vue) {
	const Bus = new Vue({
		methods: {
			emit(event, ...args) {
				this.$emit(event, ...args);
			},
			on(event, callback) {
				this.$on(event, callback);
			},
			off(event, callback) {
				this.$off(event, callback);
			}
		}
	});
	Vue.prototype.$bus = Bus;
}
export default install;

// Vue首次創建實例時一次性引入
import VueBus from '@/assets/js/vue-bus';
Vue.use(VueBus);

new Vue({
	el: '#app',
	...
})

// 組件間使用
this.$bus.on('eventName',function(value){})
this.$bus.emit('eventName', value)

使用Vuex,父組件與子組件共享相同的狀態值,配合...mapGetters實現數據同步更新,這時會觸發變化組件的updated鉤子函數,但並不會重新掛載。這裏要加個題外話,在Vuex中狀態是存儲在一個共享對象裏的,所以當有相同getters的時候將會報錯,針對這種情況,可以使用命名空間namespaced: true,添加這個屬性後,無論是存值、取值還是執行函數都需要加上前綴命名空間,詳細可參考:https://blog.csdn.net/weixin_39015132/article/details/84143962

5. Vue的路由實現:hash模式 和 history模式

hash模式:在瀏覽器顯示的URL中帶有符號“#”,#以及#後面的字符稱之爲hash,通過hashChange事件來監聽URL的改變,用window.location.hash讀取。

特點:hash雖然在URL中,但不被包括在HTTP請求中,因此hash不會重加載頁面。hash內容是用來指導瀏覽器動作,對服務端安全無用。

history模式:在瀏覽器顯示的URL中以“ / ”分割,沒有#。這種模式採用HTML5的新特性且提供了兩個新方法:pushState(),replaceState()可以對瀏覽器歷史記錄棧進行修改,以及popState事件的監聽到狀態變更。

特點:前端的 URL 必須和實際向後端發起請求的 URL 一致,如http://www.xxx.com/items/id,後端如果缺少對 /items/id 的路由處理,將返回 404 錯誤。解決辦法:當訪問不到頁面時,重定向到index.html頁面,即app依賴的頁面。

6. Vue路由的鉤子函數有哪些?

主要有兩個:beforeEach,afterEach。用於對路由導航跳轉前、後的監聽,如跳轉前檢查是否包括有效Token,沒有則返回登錄頁面。

beforeEach有3個參數to,from,next:

  • to:route即將進入的目標路由對象。
  • from:route當前正要離開的路由對象。
  • next :一定要調用該方法完成路由跳轉,默認情況不設參數,跳轉至to指定的路由對象;也可以設置把路由對象作爲入參傳入,跳轉到指定頁面。

示例:

// Router跳轉頁面時,驗證token
export const SetRouterTransition = function(router, store) {
	/* router before */
	router.beforeEach((to, from, next) => {
		// check this router need auth
		if(to.meta.requireAuth) {
			if(store.state.app.token || getLocalStorage('api_token')) {
				next();
			} else {
				alert('沒有找到模擬TOKEN值')
				next({
					path: '/',
					query: {
						redirect: to.fullPath
					}
				})
			}
		} else {
			next();
		}
	});

	/* router after */
	router.afterEach((transition) => {
		let title = transition.name;
		document.title = title;
	});
}

// 在入口文件添加參數router和store
SetRouterTransition(router, store);

7. Vuex是什麼?

Vuex是一種用來實現狀態管理的機制,它的應用核心就是 store(倉庫)。“store”基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。Vuex主要有四個模塊組成:

  • state:用來存儲組件狀態。Vuex使用單一狀態樹,即每個應用將僅僅包含一個store 實例,但單一狀態樹和模塊化並不衝突。存放的數據狀態,不可以直接修改裏面的數據。
  • mutations:用於同步修改store中的狀態。使用this.$store.commit(mutationsType, ...param);觸發。
  • getters:類似Vue的計算屬性,主要用來過濾一些數據或者直接返回某個狀態值。使用this.$store.getters.xxx獲取。
  • action:用於同步修改store中的狀態。使用this.$store.dispatch(actionType, ...param) 觸發。

8. vue-cli如何新增自定義指令?

自定義指令使用Vue.directive來定義,簡單而言,就是從指令賦值中獲取對添加該指令元素的操作說明,通過對操作的解析後按要求初始化該元素。

定義指令有5個鉤子函數:

  • bind:只調用一次,指令第一次綁定到元素時調用,用這個鉤子函數可以定義一個在綁定時執行的初始化動作。
  • inserted:被綁定元素插入父節點時調用。
  • update:所在組件的 VNode 更新時調用,指令的值可能發生了改變也可能沒有。
  • componentUpdated:所在組件的 VNode 及其孩子的 VNode 全部更新時調用。
  • unbind:只調用一次,指令與元素解綁時調用。

這些鉤子函數具有相同的回調參數:

  • el:指令所綁定的元素,可以用來直接操作 DOM 。
  • binding: 獲取外界數值的對象
  • vnode:vue 編譯生成的虛擬節點
  • oldVnode:上一個虛擬節點

全局指令:

Vue.directive('mydir', {
    inserted(el) {
        console.log(el);
    }
})

局部指令:

var app = new Vue({
    el: '#app',
    // 創建指令(可以多個)
    directives: {
        // 指令名稱
        mydir: {
            inserted(el) {
                console.log(el);
            }
        }
    }
})

示例:

<!DOCTYPE html>
<html>
 
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="../js/libs/vue/2.4.2/vue.js"></script>
	</head>
 
	<body>
		<div id="app">
			<!-- v-myorder:arg.a=value -->
			<!-- arg用於對該指令區別類別 .a表示對該指令類別的修飾符,value類似於值對入參value -->
			<!--如果你不需要arg.a,也可以直接寫成 v-myorder=value -->
			<p v-didemo:foo.a="msg">{{msg}}</p>
			<button @click="change">改變msg</button>
		</div>
	</body>
 
	<script>
		Vue.directive("didemo", {
			bind: function(el, binding, vnode) {
				console.log(1, el, binding);
				el.style.color = "red"; //設置文本字體顏色爲紅色
			},
			inserted: function(el, binding, vnode) {
				console.log(2, el, binding);
			},
			update: function(el, binding, vnode) {
				console.log(3, el, binding);
			},
			componentUpdated: function(el, binding, vnode) {
				console.log(4, el, binding);
			},
			unbind: function(el, binding, vnode) {
				console.log(5, el, binding);
			}
		});
 
		var app = new Vue({
			el: "#app",
			data: {
				msg: "hello world"
			},
			methods: {
				change: function() {
					this.msg = "i am change";
				}
			}
		});
	</script>
 
</html>

指令內容更新前:

指令內容更新後:

9. vue如何自定義一個過濾器?

通過vue實例的 filters 屬性或 Vue.filter() 函數創建過濾器,在值運算中用豎槓 | 表示過濾:

<div id="app">
     <input type="text" v-model="msg" />
     {{ msg | capitalize }}
</div>

局部過濾器:

var vm=new Vue({
    el:"#app",
    data:{
        msg:''
    },
    filters: {
      capitalize: function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
      }
    }
})

全局過濾器:

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

10. 對keep-alive 的瞭解?

keep-alive是 Vue 內置的一個組件,可以使被包含的組件保留狀態,或避免重新渲染。在vue 2.1.0 版本之後,keep-alive新加入了兩個屬性: include(包含的組件緩存) 與 exclude(排除的組件不緩存,優先級大於include) 。

<!-- 逗號分隔字符串,只有組件a與b被緩存。 -->
<keep-alive include="a,b">
  <component></component>
</keep-alive>

該組件也常用於路由導航是否緩存頁面內容:

<keep-alive>
  <router-view/>
</keep-alive>

這時,在進入導航頁面時將不會重新渲染頁面,如果需要更新頁面數據可以在生命週期鉤子函數 activated 裏操作。

11. 什麼是事件修飾符?

事件修飾符是指與事件觸發相關的修飾符。如要阻止冒泡事件需要用到event.stopPropagation(),然而使用事件修飾符,僅需@click.stop即可。

事件修飾符有以下幾種,以click事件爲例:

  • @click.stop 阻止繼續冒泡
  • @click.capture 由默認冒泡模式轉爲捕獲模式
  • @click.prevent 提交事件不再重載頁面
  • @click.self 只當事件在該元素本身觸發時觸發回調
  • @click.once 僅執行一次

修飾符間可以串聯使用,如用 @click.stop.once,表示阻止冒泡並僅執行一次。

12. 什麼是按鍵修飾符?

按鍵修飾符是指與鍵盤事件相關的修飾符。如對Enter鍵的監聽@keyup.enter,快捷組合件的監聽等。按鍵修飾符一般與input標籤配合使用,有以下幾種:

  • .enter
  • .tab
  • .delete (捕獲 “刪除” 和 “退格” 鍵)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

vue2.x版本後新增了下面幾種修飾符:

  • .ctrl
  • .alt
  • .shift
  • .meta

13. Vue中Methods與計算屬性computed的區別?

Methods裏的函數每次調用都會從頭開始執行一遍;computed裏的函數只要入參相同,只在首次執行計算過程,其它的會從緩存中直接返回已經計算過的值,不會重新計算。

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