### 組件傳值
一、父傳子
傳遞:當子組件中在父組件中當作標籤使用的時候,給子組件綁定一個自定義屬性,值爲須要傳遞的數據
接收:在子組件內部經過props進行接收,props接收的方式有2種:
①經過數組進行接收 props:["屬性"]
②經過對象進行接收 props:{
屬性:{
(1)type:限制數據的類型
(2)default:默認值
(3)required:布爾值,和default二選一
}
}
步驟:
①在父組件中給子組件標籤上添加自定義屬性:
<son :custom="100"></son>
②子組件中經過props接收:
props:["custom"]
③接收到的custom能夠直接在標籤中使用 {{custom}}
注意:從此只要看到props就要想到這個屬性是用來接收外部數據的。
二、子傳父
①接收:當子組件在父組件中當作標籤使用的時候,給當前子組件綁定一個自定義事件,值爲須要接收值的函數,這個函數不容許加 ()
②傳遞的過程:在子組件內部經過this.$emit("自定義事件名稱",須要傳遞的參數)來進行數據的傳遞
步驟:
①父組件中給須要接收參數的子組件綁定自定義事件,值爲須要接收值的函數:
<son @handler="handlerMsg"></son>
methods:{
handlerMsg(value){
console.log(value)// 這個值是經過this.$emit()觸發傳來的
}
}
②子組件中觸發自定義事件:
this.$emit("handler",100);
三、非父子傳遞
第一種方法:經過給vue原型上添加一個公共的vue實例對象(vue實例對象上有$on()和$emit()),須要傳遞的一方調用$emit(),須要接收的一方調用$on()。
步驟:
①main.js中:
Vue.prototype.$observer=new Vue();
②須要傳遞的組件中:
this.$observer.$emit("handler",100);
③須要接收的組件中:
this.$observer.$on("handler",(value)=>{
console.log(value)
});
注意:在掛載前(created)進行$on()綁定,先綁定好,再觸發。
*第二種方法:手動封裝事件訂閱observer
步驟:
①src下新建observer.js:
const eventList={};
const $on=function (eventName,callback) {
if(!eventList[eventName]){
eventList[eventName]=[];
}
eventList[eventName].push(callback);
}
const $emit=function(eventName,params){
if(eventList[eventName]){
let arr=eventList[eventName];
arr.forEach((cb)=>{
cb(params);
});
}
}
const $off=function(eventName,callback){
if(eventList[eventName]){
if(callback){
let index=eventList[eventName].indexOf(callback);
eventList[eventName].splice(index,1);
}else{
eventList[eventName].length=0;
}
}
}
export default{
$on,
$emit,
$off
}
②main.js中用手動封裝的observer替代new Vue()
import observer from "./observer.js";
Vue.prototype.$observer=observer;
③在須要傳遞的組件中用this.$observer.$emit()觸發自定義事件:
this.$observer.$emit("customHandler","須要傳遞的值");
④在須要接收的組件中用this.$observer.$on()綁定自定義事件:
this.$observer.$on("customHandler",this.toggle);
第三種方法:事件總線(Eventbus)
步驟:
①先建立一個空實例:
let bus=new Vue();
②經過bus.$on()綁定自定義事件:
bus.$on("customHandler",要觸發的函數);
③經過bus.$emit()來觸發自定義事件:
bus.$emit("customHandler");
第四種方法:vuex
注:若是是親兄弟:(父傳子和子傳父)
步驟:
①父組件中聲明data數據 state:true ,將state經過props傳給其中一個子組件:
<two :show="state"></two>
props:show
此時show的值隨着state的變化而變化
②再經過另外一個子組件去改變父組件的state:
標籤上綁定自定義事件:
<one @customHandler="toggle"></one>
再在子組件內部經過$emit()觸發customHandler事件:
this.$emit("customHandler");
### provide / inject(提供/注入)跨組件傳值,其實就是父傳子
provide / inject:依賴注入。能夠實現跨組件傳值,數據的流向只能是向下傳遞,就是大範圍有效的props
provide:這個配置項必需要在父級進行使用,用來定義後代組件所須要的一些屬性和方法。
語法:
provide:{
}
// 推薦
provide(){
return{
}
}
inject:這個配置項必須在後代組件中使用,用來獲取根組件定義的跨組件傳值的數據。
語法:
inject:[]
// 推薦
inject:{
key:{
from:"父組件名稱",
default:默認值
}
}
### 插槽 slot
做用:默認狀況下組件內部包裹的內容是不會顯示的,若是須要進行顯示則須要經過插槽來進行顯示。
一、匿名插槽:沒有名字的插槽(v-slot:default)
v-slot
在組件內部經過<slot></slot>進行接收
步驟:
①App.vue中在組件標籤中添加template標籤(裏面能夠寫多個標籤),寫上v-slot屬性
<Header>
<template v-slot>
<p>111</p>
<p>222</p>
</template>
</Header>
②在Header.vue組件中經過<slot></slot>開闢一塊空間:
<div class="header">
<slot></slot>
</div>
二、命名插槽:有名字的插槽
v-slot:slotName
在組件內部經過<slot name="slotName"></slot>來進行接收
步驟:
①給插槽指令加上名字:
<template v-slot:slotName>
<p>111</p>
</template>
②slot標籤添加name屬性:
<div class="header">
<slot name="slotName"></slot>
</div>
若是還有匿名插槽template,就在Header.vue中用<slot></slot>再開闢一塊空間接收匿名插槽。
三、插槽做用域:(子傳父)
v-slot:slotName(名字可寫可不寫,若是不寫默認是default)="變量(這個變量是一個對象)"
做用:讓組件來提供自身須要顯示的內容
步驟:
①App.vue中template中設置v-slot="props"(props是一個對象):
<template v-slot="props">
<h2>{{props.info}}</h2>
</template>
②Header.vue中slot標籤綁定自定義屬性info:
<div class="header">
<slot :info="'111'"></slot>
</div>
③在template中能夠經過props.info拿到子組件中傳來的值
若是要用命名插槽:
App.vue:直接在v-slot後面加上 :slotName
Header.vue:<slot name="slotName" :info="'111'"></slot>
`以上都是組件傳值`
### 動態組件
經過vue的內置組件components的is屬性來動態的切換頁面
is的值是哪一個組件就會顯示哪一個組件,通常is前面有冒號表示動態組件。
步驟:
①在Mine.vue中,在組件配置項中添加name屬性:
export default{
name:Mine
}
②App.vue中設置data屬性,用一個變量componentName接收name:
export default{
data(){
return{
componentName:"Mine"
}
}
}
而後在component標籤中添加is屬性爲變量componentName,就會渲染Mine組件:
<component :is="componentName"></component>
注意:component標籤不顯示在頁面上
場景:不在意瀏覽器地址的時候能夠用動態組件,如選項卡
### keep-alive
keep-alive是vue的內置組件,用來包裹動態切換到路由或者組件,能夠防止組件頻繁的進行建立和銷燬,從而達到性能優化的效果,當組件被keep-alive包裹的時候會增長兩個生命週期:
activated----活躍狀態,進入的時候觸發,能夠進行數據請求
deactivated----緩存狀態,離開的時候觸發
使用:
<keep-alive>
<component :is="componentName"></component>
</keep-alive>
正常的組件顯示會顯示建立前、建立後、掛載前、掛載後4個生命週期。在切換時會經歷當前組件的建立前、建立後、掛載前,上一個組件的銷燬前和銷燬後,再進行當前組件的掛載後,共6個生命週期。
使用keep-alive包裹後,切換組件的時候,會直接經歷當前組件的建立前、建立後、掛載前、掛載後,共4個生命週期,而省去了上一個組件的銷燬前和銷燬後。當全部的組件都經歷了建立和掛載後,就所有儲存在緩存裏,以後進行的切換都是在緩存中拿數據。
在當前組件mounted的先後分別是上一個組件的deactivated和當前組件的activated。deactivated和activated每次都會切換都會觸發,因此數據請求放在activated中。
屬性:
include----包括,須要被緩存的組件(字符串、正則)
exclude----排除,不須要被緩存的組件(實時更新的組件)(字符串、正則)
max----最多能被緩存多少個組件,項目中組件特別多的時候即便用了include也會形成緩存壓力,就用max規定下最多能夠緩存幾個,超過該值後面的會將前面的替代掉,會從新走一遍生命週期流程(Number)
注意:
一、include和exclude不能同時使用,若是使用正則,屬性前加冒號
二、實時更新的組件不要用keep-alive
### 自定義指令 directive
全局自定義指令:Vue.directive()
局部自定義指令:directives
directive(參數一,參數二)
參數一:指令名稱
參數二:指令的配置項,能夠是函數,也能夠是對象
函數:
參數一:使用當前指令的元素
參數二:指令的詳細信息
{
modifiers:修飾符(只要自定義指令後面跟了修飾符,modifiers對象中就有值,爲true),
value:指令的值(假設指令這樣寫:<div v-test="'aaa'"></div>,那麼value就是aaa)
}
指令的做用:操做DOM元素
步驟:
①src下新建utils/utils.js:
import Vue from "vue";
/**
* v-test指令:
* <div v-test="'發發發'"></div>
* 至關於
* <div>發發發</div>
*
*/
Vue.directive("test",(el,{value})=>{
el.innerText=value;
});
/**
* 設置背景顏色的指令
*
*/
Vue.directive("backgroundColor",(el,{value,...rest})=>{
el.style.backgroundColor=value;
});
/**
* 阻止瀏覽器默認事件:v-event.prev
*
*/
Vue.directive("event",(el,{modifiers})=>{
let {prev}=modifiers;
el.addEventListener("contextmenu",(e)=>{
if(prev){
e.preventDefault();
}
});
});
/**
* 自動聚焦
*
*/
Vue.directive("focus",{
inserted(el){
el.focus();
}
});
②main.js中引入:
import "./utils/utils.js";
③App.vue中使用自定義指令:
<div v-test="'發發發'" v-backgroundColor.not="'blue'"></div>
<div v-test="'阻止瀏覽器默認事件'" v-backgroundColor="'yellow'" v-event.prev></div>
<input type="text" v-focus>