参考一:
父组件向子组件传值:
parent:
<parent>
<child :message="msg"></child>
</parent>
data(){
return {
msg: "this is parent message"
}
}
child:
<div>
<p>{{message}}</p>
</div>
data(){
props:["message"]
}
or
props: {
message: {
type: String, //可指定接收类型,如:Array.
default:"this is default" //可设置默认值
}
}
props: {
message: {
type: Array,
default: ['foo','bar','baz'] //默认值
}
}
注意:parent中的子组件标签中传入的是 :message, (v-bind:”message”),如果传入的是message=”msg”,那么子组件接收到的是”msg”这个字符串,因为message没有绑定值。
子组件向父组件传值
由于在vue中子组件不能更改父组件中的内容,所以可以通过子组件触发事件来传值给父组件。
child:
<template>
<button v-on:click ='setValue'>setValue</button>
</template>
data(){
return {
value: "sendValue"
}
},
methods:{
setValue:function(){
this.$emit('getdata',this.value); //this.value为向父组件传递的数据
}
}
parent:
<div id="app">
<child @getdata="receive" ></child> //自动监听由子组件"注册"的 'getdata'事件,然后调用receive方法来更改数据
<p>{{value}}</p>
</div>
data(){
return{
value:"default"
}
},
methods: {
receive:function(val) {
this.value = val;
}
}
这时候就可以看到父组件的p标签中的数据更新了…
非父子组件之间的通讯
有时候两个非父子关系组件也需要通信 。在简单的场景下,可以使用一个空的 Vue 实例作为中央事件总线,类似于一个“中转站”,进行发送和接收数据。
event.js
import Vue from 'vue'
var bus = new Vue() //创建事件"中转站"
export default bus
or
import Vue from 'vue'
export default new Vue
a.vue
<button @click="btnclick">content</button >
// 触发组件 A 中的事件
import eventdata from '.../event.js'
methods: {
btnclick(){
eventdata .$emit('transfer',this.message);
}
}
b.vue
// 在组件B监听事件
<template>
<div>{{message}}</div>
</template>
import eventdata from '.../event.js'
data(){
return{
message:"default"
}
},
created() {
eventdata .$on('transfer', function(msg){ //接收事件
this.message = 'msg';
});
}
在数据简单的情况下可以使用中转或者父组件传值给子组件的方法进行传值,在数据比较多而杂的情况下,应该考虑使用专门的状态管理模式 Vuex插件来实现组件间的通讯.
参考二:
vue中我们常常用到组件. 那么组件总体可以分为如下的几种关系.
父子组件, 爷孙组件, 兄弟组件. 这几种组件之间是如何通信的呢?
父子组件通信
根据vue中的文档可知, 组件的props属性用于接收父组件传递的信息. 而子组件想要向父组件传递信息, 可以使用$emit事件.
我们定义两个组件, 一个为父组件名为father, 另外一个为子组件child. 子组件通过props属性接收父组件传递的值, 这个值为fname, 是父组件的名字. 点击子组件的按钮, 触发toFather事件, 向父组件传递消息. 父组件做出相应的反应.
将父组件和子组件放入名为app的vue实例中
Vue.component('child', {
props: ['fname'],
template: `
<div class="child">
这是儿子, 我爸爸是{{fname}}
<button @click="$emit('toFather')">点我通知爸爸</button>
</div>
`
})
Vue.component('father', {
data() {
return {
info: '无消息'
}
},
template: `
<div class="father">
这是父亲, {{info}}
<child fname="father" @toFather="getSonMsg"></child>
</div>
`,
methods: {
getSonMsg() {
this.info = '我收到儿子传来的消息了'
}
}
})
new Vue({
el: '#app',
})
注意上面的组件定义顺序不能换
让后我们在html文件中写入即可
<div id="app">
<father></father>
</div>
爷孙组件通信
因为vue只是说明了父子组件如何通信, 那么爷孙组件是没有办法直接通信的. 但是它们可以分解为两个父子组件通信.
即爷爷和父亲看成是一个父子组件, 而父亲和孙子看成是一个父子组件. 这样它们之间就可以进行通信了. 通过父亲组件合格桥梁, 可以实现爷孙的通信. (注意: 爷孙组件是无法直接通信的)
兄弟组件通信
兄弟组件通信即组件之间通信. 这就要用到观察者模式了. 因为vue实例的原型全部来自Vue.prototype. 那么我们就可以了将事件中心绑定到Vue.prototype的某个属性上, 暂且叫它为bus吧.
let bus = new Vue()
Vue.prototype.bus = bus
我们再定义两个组件, up组件和down组件, 当点击down组件中的按钮时, 会给up组件传递信息.
Vue.component('up', {
data() {
return {
msg: '未传递消息'
}
},
template: `
<div class="up">
<p>这是up组件, 下一行为down传递的消息</p>
<p>{{msg}}</p>
</div>
`,
mounted() {
this.bus.$on('send', (msg)=> {
this.msg = (msg)
})
}
})
Vue.component('down', {
template: `
<div class="down">
<p>这是down</p>
<button @click="toUp">点击我向up组件传递消息</button>
</div>
`,
methods: {
toUp() {
this.bus.$emit('send', 'down来消息了')
}
}
})
new Vue({
el: '#app',
})
并且将两个组件放入名为app的实例中
<div id="app">
<up></up>
<down></down>
</div>
按钮被点击后, up组件会接收到消息
参考三:
Vue 常用的三种传值方式
1.父传子
2.子传父
3.非父子传值
父子组件的关系
首先,我们要使用Vue的组件传值,我们要知道组件之间的关系。
父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息,如下图所示
什么是Prop
要实现组件传值,我们要了解什么是prop。
Prop是用来传递数据的一种自定义属性。
Prop是单向数据流。所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
父传子
父组件的内容传递给子组件其实很简单
首先建立俩个Vue的组件,例father.vue,child.vue
在father.vue的组件写上
<template>
<div>
<span>父组件:</span>
</div>
</template>
记住,我们的template下,只能拥有一个标签
在child.vue的组件写上
<template>
<div>
<span>子组件:</span>
</div>
</template>
我们把子组件的内容引入到父组件里
于是,我们在father.vue导入
import child from './child.vue' // 引入子组件
然后,我们开始注册自定义标签
export default {
name: "father",
components:{
child //这个名字是上面我们引进来的child.vue,俩个名字需相同
}
}
<template>
<div>
<span>父组件:</span>
<child></child>
</div>
</template>
1
2
3
4
5
6
我们开始v-model绑定数据
在data数据里写上name
export default {
name: "father",
data() {
return {
name: ''
}
},
components:{
child //这个名字是上面我们引进来的child.vue,俩个名字需相同
}
}
data里的数据为什么要return出来呢?
1.不使用return 出来的数据会在项目的全局可见,会污染全局
2.使用return 出来的数据只能在当前组件中使用,不会影响其他组件
当一个组件被定义, data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。
我们在组件中绑定data数据的name,在自定义标签中传递要传递的值
<template>
<div>
<span>父组件:</span>
<input type="text" v-model="name">
<child :notice="name"></child>
</div>
</template>
最后,在child.vue组件中利用props来接收传递来的参数
export default {
name: "child",
data() {
return {}
},
props: ['notice']
}
在上面的模板中运用传递来的参数
<template>
<div>
<span>子组件:{{notice}}</span>
</div>
</template>
父传子所有的代码
father.vue
<template>
<div>
<span>父组件:</span>
<input type="text" v-model="name">
<child :notice="name"></child>
</div>
</template>
<script>
import child from './child.vue' // 引入子组件
export default {
name: "father",
data() {
return {
name: ''
}
},
components:{
child //这个名字是上面我们引进来的child.vue,俩个名字需相同
}
}
</script>
<style scoped>
</style>
child.vue的代码
<template>
<div>
<span>子组件:{{notice}}</span>
</div>
</template>
<script>
export default {
name: "child",
data() {
return {}
},
props: ['notice']
}
</script>
<style scoped>
</style>
子传父
首先,我们要点击一个按钮,使子组件的值传到父组件。
于是,我们在子组件,写点击事件。
(这里在input的标签上绑定数据,还是和之前的一样)
<template>
<div>
<span>子组件:</span>
<input type="text" v-model="childvalue"> //双向绑定childvalue
<input type="button" value="传值到父亲" @click="childclick"> //点击事件
</div>
</template>
export default {
name: "child",
props: ['notice'], //接收父组件传递的值
data() {
return {
childvalue:this.notice
}
},
methods: {
childclick() {
this.$emit("childByvalue", this.childvalue) // 利用$emit的方法把值传递给父组件
}
}
}
我们在父组件中接收传递的值利用的是v-on:,简写用@
<child :notice="name" @childByvalue="childByvalue"></child>
在下面的methods写方法
methods : {
childByvalue (val) {
this.name=val
}
},
这时候细心的同学会发现子传父可以了,但父传子不能用了。
这时候就用到了watch来监听了。
在父组件中监听传递过了的值。
watch:{
notice () {
this.childvalue=this.notice
}
},
这样父子组件的通信就完成了。
父组件的完整代码
<template>
<div>
<span>父组件:</span>
<input type="text" v-model="name">
<child :notice="name" @childByvalue="childByvalue"></child>
</div>
</template>
<script>
import child from './child.vue' // 引入子组件
export default {
name: "father",
data() {
return {
name: ''
}
},
methods : {
childByvalue (val) {
this.name=val
}
},
components:{
child //这个名字是上面我们引进来的child.vue,俩个名字需相同
}
}
</script>
<style scoped>
</style>
子组件的完整代码
<template>
<div>
<span>子组件:</span>
<input type="text" v-model="childvalue">
<input type="button" value="传值到父亲" @click="childclick">
</div>
</template>
<script>
export default {
name: "child",
props: ['notice'],
data() {
return {
childvalue:this.notice
}
},
watch:{
notice () {
this.childvalue=this.notice
}
},
methods: {
childclick() {
this.$emit("childByvalue", this.childvalue)
// 利用$emit的方法把值传递给父组件
}
}
}
</script>
<style scoped>
</style>
非父子传值(兄弟组件传参)
非父子传参,需要有共同的父组件。需要定义公共的公共实例文件,作为中间仓库。不然达不到传值效果。
创建bus.js做为公共的仓库文件
bus.js内容为
import Vue from 'Vue'
export default new Vue
创建child1.vue,child2.vue
child1.vue内容为
<template>
<div>
<span>child1</span>
<span>{{msg}}</span>
<button @click="childclick">点击</button>
</div>
</template>
<script>
import bus from './bus.js'
export default {
name: "child1",
data () {
return {
msg :'123'
}
},
methods : {
childclick () {
bus.$emit('val',this.msg)
}
}
}
</script>
<style scoped>
</style>
child2的内容为
<template>
<div>
<span>child2</span>
<span>{{cmsg}}</span>
</div>
</template>
<script>
import bus from './bus.js'
export default {
name: "child2",
data () {
return {
cmsg : ''
}
},
mounted () {
let that =this
bus.$on('val',(data)=>{
console.log(data);
this.cmsg=data
})
}
}
</script>
<style scoped>
</style>
在父组件中导入注册
import child1 from './child1.vue'
import child2 from './child2.vue'
components:{
child1,
child2
}
<child1></child1>
<child2></child2>
参考四:
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,应该怎样做?那就是自定义事件!
每个vue实例都有触发事件的方法
- 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。然后再对应子组件方法执行处触发事件,两者缺一不可。
<!-- 父组件 --> <div id="app"> <!-- 子组件 --> <!-- 父组件直接用 v-on 来监听子组件触发的事件。 --> <!-- 需跟子组件中的$emit组合使用 --> <mycon v-on:son_method="father_method"></mycon> </div>
// 子组件 Vue.component('mycon', { template: '<button v-on:click="son_method">子按钮</button>', methods: { // 按钮点击时候触发事件 son_method: function () { this.counter += 1; console.log("son"); // 这句话来触发事件 // 必须跟模板中的v-on配合使用 this.$emit('son_method'); } }, }); // 父组件 new Vue({ el: "#app", methods: { father_method: function () { console.log("father"); } } });
绑定原生事件(适用于组件)
有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
使用自定义事件的表单输入组件
表单输入组件,使用 v-model 来进行数据双向绑定。要让组件的 v-model 生效,它必须:
- 接受一个 value 属性
- 在有新的 value 时触发 input 事件
<div id="app"> <input v-model="something"> <!-- 分两步: 第一步:通过v-bind给输入框赋值 第二步:通过v-on:input事件执行一句something = $event.target.value更改something --> <input v-bind:value="something" v-on:input="something = $event.target.value"> <!-- 简写 --> <input v-bind:value="something" v-on:input="something = arguments[0]"><input> </div>
new Vue({ el: "#app", data:{ something:123 }, watch: { something:function() { console.log(234) } } });
非父子组件通信
在简单的场景下,使用一个空的 Vue 实例作为中央事件总线:
var bus = new Vue() // 触发组件 A 中的事件 bus.$emit('id-selected', 1) // 在组件 B 创建的钩子中监听事件 bus.$on('id-selected', function (id) { // ...