组件传值 provide-inject 非响应式
通常情况下,父组件向孙组件传递数据,可以采用父子props
层层传递,也可以使用bus
和Vuex
直接交互
在Vue2.2.0之后,Vue还提供了provide/inject
选项
但是不建议在应用中直接使用该办法,因为怕"管不好",如果管理不好后续做业务会很麻烦
App.vue
<template>
<div>
<Box1></Box1>
<button @click="change">change1</button>
<br>
<div>
<br>
{{ msg }}
</div>
</div>
</template>
<script>
import Box1 from "./Box1.vue";
export default {
data() {
return {
msg: "app组件提供的数据",
};
},
provide: function () {
return { msg: this.msg };
},
methods: {
// msg里面的数据改了也没有效果,Box里面接收的数据不会改变
change() {
this.msg = "6666";
},
},
components: {
Box1,
},
mounted() {
console.log(this.msg, 111111111111);
},
};
</script>
Box.vue
<template>
<div>
<p>box1---{{msg}}</p>
</div>
</template>
<script>
export default {
inject:["msg"],
// 即可以接收数据也可以传递数据
provide:{n:10}
}
</script>
<style>
</style>
组件传值 provide-inject 响应式
App.vue
<template>
<div>
<Box1></Box1>
<button @click="change">change</button>
{{msg}}
</div>
</template>
<script>
import Box1 from "./Box1.vue"
export default {
data() {
return {
msg:"app组件提供的数据"
}
},
provide:function(){
// 将这里改了即可
return {msg:()=>this.msg}
},
methods:{
change(){
this.msg="6666"
}
},
components:{
Box1
},
mounted() {
console.log(this.msg,111111111111)
}
}
</script>
Box.vue
<template>
<div>
<p>box1---{{msg()}}</p>
</div>
</template>
<script>
export default {
inject:["msg"],
}
</script>
<style>
</style>
自定义事件
Vue提供的技术:继承Vue的组件有三个功能
- 触发x组件的a事件: x.$emit(“a事件”,参数…)
- 给x组件绑定a事件 x.$on(“a事件”,监听器函数)
- 给x组件解绑a事件 x.$off(“a事件”,监听器函数)
App.vue
<template>
<div>
<button @click="fn1">点击给app组件绑定一个a事件</button>
<br>
<button @click="fn2">触发自定义a事件</button>
</div>
</template>
<script>
export default {
methods:{
fn1(){
this.$on("a",function(arg1,arg2){
console.log("我自己设计的事件触发了 a",arg1)
})
},
fn2(){
this.$emit("a",100)
}
}
}
</script>
fn1绑定一个a事件,事件触发就会打印数据,而事件触发的条件是fn2函数的调用,所以当点击 触发自定义a事件 时就触发了a事件,从而打印 我自己设计的事件触发了 a 100
中央传值
通过创建一个新的vm对象,专门统一注册事件,供所有组件共同操作,达到所有组件随意隔代传值的效果
App.vue
<template>
<div>
<Box1></Box1>
</div>
</template>
<script>
import Box1 from "./Box1.vue"
export default {
methods:{
},
components:{
Box1
}
}
</script>
<style>
</style>
Box.vue
<template>
<div>
<h1>box3</h1>
<button @click="fn">给box1传值</button>
</div>
</template>
<script>
export default {
methods: {
fn() {
this.$bus.emit("box1data", "box1的数据")
}
}
}
</script>
<style>
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.prototype.$bus=new Vue({
data:{
arr:[]
},
methods:{
on(eventname,callback){
if(this.arr.includes(eventname)){
throw "eventname events already regist!!"
}else{
this.arr.push(eventname)
this.$on(eventname,callback)
}
},
emit(eventname,...arg){
this.$emit(eventname,...arg)
},
off(eventname,callback){
this.$off(eventname,callback)
}
}
})
var vm=new Vue({
render: h => h(App),
})
vm.$mount('#app')
在main.js中实例一个新vm对象,在其余组件中就能直接调用,就不需要一层一层的传值
动态组件
有的时候,我们希望页面中的某个地方,在不同组件之间进行动态切换,这时候除了条件渲染,还可以使用动态组件
component 标签的 is属性语法:is后跟组件的变量名决定使用哪个组件来渲染
注意: is是组件名 :is是data中的变量中保存的组件名
App.vue
<template>
<div>
<button @click="mytemp='Box1'">1</button>
<button @click="fn('Box2')">2</button>
<button @click="mytemp='Box3'">3</button>
<component v-bind:is="mytemp"></component>
</div>
</template>
<script>
import Box1 from "./Box1.vue"
import Box2 from "./Box2.vue"
import Box3 from "./Box3.vue"
export default {
data() {
return {
arr: [true,false,false],
mytemp:"Box2"
}
},
components:{
Box1,
Box2,
Box3
},
methods:{
fn(index){
this.mytemp=index
}
}
}
</script>
Box1.vue
<template>
<div>
box1
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
Box2.vue
<template>
<div>
box2
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
Box3.vue
<template>
<div>
box3
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
我们给button绑定点击事件,当我们点击的时候就会切换box,而这个效果的实现是使用了component 标签的 is属性,给is一个v-bind指令,那么当我们点击的不同的box时,就会往fn函数里面传入不同的参数,这个参数又赋值给了mytemp,这时页面上的mytemp就会动态的改变成相应的数据了,也就实现了动态切换效果
缓存组件
动态组件的切换,切换后是不会缓存之前被切换掉的组件的,每次切换新组件的时候,Vue 都创建了一个新的组件对象
有时候我们希望在A组件时用户做了一些操作,切换B组件时做了一些操作,当切回A组件时希望记住A的操作,不要重新创建A组件,keep-alive可以缓存动态切换的组件
App.vue
<keep-alive>
<component v-bind:is="mytemp"></component>
</keep-alive>
Box.vue
<template>
<div class="box">
box1<br>
email:<input type="text" v-model="email"> <br>
pwd:<input type="password" v-model="pwd">
</div>
</template>
<script>
export default {
data() {
return {
email: "",
pwd:""
}
}
}
</script>
<style scoped="scoped">
.box{
width: 400px;
height: 400px;
background-color: aliceblue;
}
</style>
App.vue里面的内容都是一样的,只是给div加了一个keep-alive标签而已,这样我们就把用户输入的信息缓存了起来
异步组件
Vue允许将组件定义为一个异步解析(加载)组件定义的工厂函数,即Vue只在实际需要渲染组件时,才会触发调用工厂函数,并且将结果缓存起来,用于将来再次渲染
就有点类似于懒加载,在用户用到的时候才会去加载,因为一个完整的网站内容是非常多的,如果不管用户使不使用都全部一股脑的加载,那么势必会造成网页打开卡顿,性能不好,用户体验感差,所以我们要使用异步组件来懒加载
App.vue
<template>
<div>
<h1>test</h1>
<button @click="fn">b</button>
<component :is="n"></component>
<Box2></Box2>
</div>
</template>
<script>
// 需要使用的就在这里引入,直接打包
// 不需要一开始就使用的就在下面加载,用户需要使用的时候在点击加载
import a from "./a.vue"
// import b from "./b.vue"
// 官方提供的加载前后的提示效果
import LoadingComponent from "./LoadingComponent.vue"
import ErrorComponent from "./ErrorComponent.vue"
export default {
data() {
return {
n: "Box1"
}
},
methods: {
fn() {
this.n = "Box2"
}
},
components: {
Box1: a,
// Box2: function(resolve) {
// require(['./b.vue'], resolve)
// }
// Box2:()=>import("./b.vue") //最常用的方式
Box2: () => ({
// 需要加载的组件 (这个 `import` 函数会返回一个 `Promise` 对象。)
component: import('./b.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
}
}
</script>
<style>
</style>
a.vue
<template>
<div>
a
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
b.vue
<template>
<div>
b
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
LoadingComponent.vue
<template>
<div>
加载中.....
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
ErrorComponent.vue
<template>
<div>
网络不行 加载失败了 刷新试试
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>