### 组件传值
一、父传子
传递:当子组件中在父组件中当作标签使用的时候,给子组件绑定一个自定义属性,值为须要传递的数据
接收:在子组件内部经过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>