前提回顾
为了能让需要通信的两个组件可以说上话,往往需要借助一些手段来实现这个目的,本文的写作目标就是为了总结每一种可以用于通信手段的方法。
第一:props/$emit
下面使用了props/$emit方法做到了让Foo组件和Bar组件通信
- App.vue
<template>
<div id="app">
<Foo></Foo>
</div>
</template>
<script>
import Foo from "./components/Foo";
export default {
name: "App",
components: {
Foo,
},
};
</script>
- components/Foo.vue
<template>
<div id='Foo'>
使用props/$emit来做到父子组件通信
<Bar
:
@changeTitle='handleChangeTitle'>
</Bar>
</div>
</template>
<script>
import Bar from './Bar';
export default {
name: 'Foo' ,
components: {
Bar
},
data() {
return {
title:"this is a message"
}
},
methods: {
handleChangeTitle(props){
this.title=props
}
}
};
</script>
- components/Bar.vue
<template>
<div id='Bar'>
使用props/$emit来做到父子组件通信
{{title}}
<button @click="toParent">改变title</button>
</div>
</template>
<script>
export default {
name: 'Bar' ,
props: ['title'],
methods: {
toParent(){
this.$emit('changeTitle','this is a new message')
}
}
};
</script>
第二:$refs/ref
- App.vue的代码同上省略
- components/Foo.vue
<template>
<div id='Foo'>
Foo
<Bar
:
@changeTitle='handleChangeTitle'
ref='bar'
></Bar>
<button
@click="getBar"
>getBar</button>
</div>
</template>
<script>
import Bar from './Bar';
export default {
name: 'Foo' ,
components: {
Bar
},
props: [''],
data() {
return {
title:"this is a message"
}
}
methods: {
getBar(){
// 调用了Bar组件上的setBarTitle方法
console.log(this.$refs.bar.setBarTitle());
// console.log(this.$refs.bar);
}
}
};
</script>
- components/Bar.vue
<template>
<div id='Bar'>
Bar
{{title}}
<button @click="toParent">改变title</button>
</div>
</template>
<script>
export default {
name: 'Bar' ,
props: ['title'],
methods: {
toParent(){
this.$emit('changeTitle','this is a new message')
},
setBarTitle(){
console.log('changeBarTitle');
}
}
};
</script>
第三:children/parent
使用$children获取组件的子组件实例的时候是依赖下标来获取的,这种获取方式是不稳定的,易出错。
- App.vue的代码同上省略
- components/Foo.vue
<template>
<div id='Foo'>
Foo
<button
@click="getChildren"
>getChildren</button>
</div>
</template>
<script>
import Bar from './Bar';
export default {
name: 'Foo' ,
components: {
Bar
},
props: ['']
methods: {
getChildren(){
//可以获取到当前Foo组件的所有子组件实例
//(是数组格式[VueCompoent])
//依赖下标来获取具体子组件实例
//即通过this.$children[下标]
console.log(this.$children);
}
}
};
</script>
<style>
</style>
- components/Bar.vue
<template>
<div id='Bar'>
<button
@click="getParent">
getBarParent</button>
</div>
</template>
<script>
export default {
name: 'Bar' ,
methods: {
getParent(){
//就可以获取到Bar组件的父级组件了
//接着可以调用父级组件上的方法等等操作进行通信
console.log(this.$parent);
}
}
};
</script>
第四:attrs/listeners
- App.vue
<template>
<div id="app">
<Foo></Foo>
</div>
</template>
<script>
import Foo from './components/Foo';
export default {
name: "App",
components: {
Foo
},
};
</script>
- components/Foo.vue
<template>
<div>
这里是Foo
<Bar
class="heihei"
@a="handleA"
@b="handleB"
@click='handleFooClick'
disabled='disabled'
></Bar>
</div>
</template>
<script>
import Bar from "./Bar";
export default {
components: {
Bar,
},
methods: {
getName() {
return "CompA";
},
handleA() {
console.log("handleA")
},
handleB() {
console.log("handleB")
},
handleFooClick(){
console.log(" handleFooClick")
}
},
};
</script>
- components/Bar.vue
<template>
<div>
这里是Bar
<Baz
:
v-on="$listeners"
></Baz>
<button
disabled='$attrs.disabled'
>禁用状态</button>
</div>
</template>
<script>
import Baz from "./Baz";
export default {
//一般可以用props来接收父级组件传递下来的内容
// 如果传入的值没有在 props 中声明,那么就会在 $attrs 获取到
// props:["title"],
//默认行为:
//我们之前书写了<Bar ></Bar>
//并且没有通过props来接收声明title的话Vue会把
//给添加到组件容器内即<div ></div>
//如果不希望出现这种情况可以使用inheritAttrs: false
inheritAttrs: false,
components: {
Baz,
},
mounted() {
// $attrs 属性:
// 如果传入的值没有在 props 中声明,那么就会在 $attrs 获取到
//{title: "this is a foo"}
console.log(this.$attrs,'this.$attrs');
//{a: ƒ, b: ƒ, click: ƒ}
console.log(this.$listeners,'this is bar');
this.$listeners.a()
},
methods: {
getName() {
return "CompB";
},
},
};
</script>
- components/Baz.vue
<template>
<div>
这里是Baz
{{ title }}
</div>
</template>
<script>
export default {
props: ["title"],
methods: {
},
mounted(){
//成功传递进来了{a: ƒ, b: ƒ, click: ƒ}
console.log(this.$listeners,'this is baz');
}
};
</script>
<style></style>
第五:provide/inject
- App.vue
<template>
<div id="app">
<CompA></CompA>
</div>
</template>
<script>
import CompA from "./components/CompA";
export default {
name: "App",
components: {
CompA
},
};
</script>
- components/CompA.vue
<template>
<div>
这里是CompA
<CompB></CompB>
</div>
</template>
<script>
import CompB from "./CompB";
export default {
components: {
CompB,
},
mounted() {
},
//把当前的组件实例传递给别人
//别人拿到组件实例后可以调用该组件实例上的方法
//第二种写法:
provide() {
return {
foo: "foo",
compA: this, //注意this的指向问题
};
},
// 第一种写法:
// provide: {
// foo: "foo",
// compA: this, //注意this的指向问题
// },
methods: {
getName() {
return "CompA";
},
},
};
</script>
- components/CompB.vue
<template>
<div>
这里是CompB
<CompC></CompC>
</div>
</template>
<script>
import CompC from "./CompC";
export default {
components: {
CompC,
},
provide() {
return {
compA: this, //this指向compB组件
//名字却故意取为compA
//在注入时会取最近的注入名
};
},
methods: {
getName() {
return "CompB";
},
},
};
</script>
- components/CompC.vue
<template>
<div>
CompC
直接就可以使用了:{{foo}}
<button @click="getCompA">getCompA</button>
</div>
</template>
<script>
export default {
inject: ["foo", "compA"],
methods: {
getCompA(){
//获取到组件实例
console.log(this.compA);
//该组件实例上有getName方法
//输出的结果为CompB(取的是最近的注入名 "compA" )
console.log(this.compA.getName())
}
},
};
</script>
第六:EventBus通信
- bus.js
import Vue from "vue";
// event bus
export const bus = new Vue();
- components/CompA.vue
<template>
<div>
CompA
<CompB></CompB>
</div>
</template>
<script>
import CompB from "./CompB";
import {bus} from '../bus';
export default {
components: {
CompB,
},
mounted() {
bus.$on('to-CompoA',(message)=>{
console.log(message);
})
}
};
</script>
- components/CompB.vue
<template>
<div>
CompB
<CompC></CompC>
</div>
</template>
<script>
import CompC from "./CompC";
export default {
components: {
CompC,
},
};
</script>
- components/CompC.vue
<template>
<div>
CompC
<button @click="getCompA">getCompA</button>
</div>
</template>
<script>
import {bus} from '../bus';
export default {
methods: {
getCompA(){
bus.$emit('to-CompoA','this is message from CompoC')
}
},
};
</script>
- App.vue
<template>
<div id="app">
<CompA></CompA>
</div>
</template>
<script>
import CompA from './components/CompA';
export default {
name: "App",
components: {
CompA
},
};
</script>
第七:v-model
- App.vue
<template>
<div id="app">
<Foo></Foo>
</div>
</template>
<script>
import Foo from './components/Foo';
export default {
name: "App",
components: {
Foo
},
};
</script>
- components/Foo.vue
<template>
<div>
这里是Foo
<Bar
v-model="initValue"
></Bar>
</div>
</template>
<script>
import Bar from "./Bar";
export default {
components: {
Bar,
},
data(){
return{
initValue:'hello init'
}
}
};
</script>
- components/Bar.vue
<template>
<div>
这里是Bar
<input type="text"
v-bind:value="handle"
v-on:change="$emit('handleEvent', $event.target.value+'fk')"
>
</div>
</template>
<script>
export default {
components: {
},
model:{
prop:'handle',
event:'handleEvent'
},
//仍然需要在组件的 props 选项里声明
// handle 这个 prop。
props: {
handle: String
},
};
</script>
第八:sync
<script>
const Modal = {
template: `<div v-if="visible">
modal
{{visible}}
{{number}}
<button @click="handleClick">x</button>
</div>`,
props: ["visible", "number"],
methods: {
handleClick() {
this.$emit("update:visible", false);
this.$emit("update:number", 10);
},
},
};
const app = new Vue({
el: "#app",
components: {
Modal,
},
data: {
msg: "hello",
showModel: false,
count: 1,
},
methods: {
handleShowModel() {
this.showModel = true;
},
// handleCloseModel() {
// this.showModel = false;
// },
},
template: `<div>
app
<button @click="handleShowModel"> showModel</button>
<Modal :visible.sync="showModel" :number.sync="count" ></Modal>
</div>`,
});
</script>
第九:VueX
暂时省略
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!