组件通信大全

首先

组件时vue.js最强大的功能之一,而组件实例的作用的域是相互独立的,这就意味着不同组件之间的数据无法相互引用。一般来说,组件可以有以下几种关系
在这里插入图片描述

如图所示

A是父级、B是A的子级C和D的父级,C和D是兄弟关系,A和C、D是隔代关系。

针对于不同的场景,我们可以使用不同的组件方式。

第一种:父子组件传值

1、父传子

  • 在父组件的子组件标签上绑定一个属性,挂载要传输的变量
    • 在子组件中通过props来接收数据,props可以是数组也可以是对象,接受的数据可以直接是props:['属性名']props:{属性名:数据类型}
// 父组件
<template>
   <div id = 'app'>
     <Child :msg='msg'></mycom>
   </div>
</template>
<script>
import Child from "./components/child"
export default {
  name: 'App',
  data(){
    return{
      msg:" 2 "
    }
  },
  components:{
   Child
  }
}
// 子组件
<template>
   <div id = 'child'> </div>
</template>
<script>
export default {
  name: 'child',
  // 第一种
   props:['msg']
  // 第二种
    props:{
       type:String,
       default:function(){
          return :""
        }
      }
  data(){
    return:{}
  },
}

2、子传父

  • 在父组件的子组件标签上自定义一个事件,然后调用需要的方法
  • 在子组件的方法中通过this.$emit("事件")来触发在父组件中定义的事件,数据是以参数的形式来进行传递的
// 父组件
<template>
   <div id = 'app'>
       // 自定义一个事件
     <Child :msg='msg' @reception='add'></mycom>
   </div>
</template>
<script>
import Child from "./components/child"
export default {
  name: 'App',
  data(){
    return{
      msg:" 2 "
    }
  },
  components:{
     Child
  }
  methods:{
    // 调用方法
    add(data){
        console.log(data)
    }
  }
}
// 子组件
<template>
   <div id = 'child' @click='add()'> </div>
</template 
<script>
export default {
  name: 'child',
  props:['msg']
  data(){
    return{
        child:"Son"
    }
  },
  methods:{
      add(){
          this.$emit('reception',this.child)
      }
  }
}
第二种:兄弟组件传参

注意:

​ 兄弟之间传值和子传父的方式类似,都是通过$emit事件发射的形式,但是兄弟之间要找一个Vue实例作为媒介,也就是通过一个eventBus事件总线

兄弟组件传参也有多种方式

第一种

  • src中新建一个Bus.js文件,然后导出一个空的vue实例
  • 在传输数据的一方引入Bus.js,然后通过Bus.$emit("事件名","参数")来派发事件,数据是以$emit()的参数来进行传递的
  • 在接受的数据的一方,引入Bus.js,然后通过Bus.$on("事件名",(data)=>{data是接受的数据})

创建一个BUS.js文件

// 1、创建事件中心
const eventBus = new Vue();
//2、把创建出来的空的Vue对象挂载到Vue的原型上
Vue.prototype.eventBus = eventBus //eventBus【属性名】

在组件中引入刚才创建的js

import '@/eventBus.js' 

methods中定义一个函数

// 在传输数据的组件中
methods:{
    changesize(){
        eventBus.$emit('add',this.arg)
    }
}
/*
 --------------------------------------------------------------
*/
// 在接收数据的组件中
created(){
      eventBus.$on('add',(message)=>{
        //一些操作,message就是从top组件传过来的值
        console.log(message)
    }) 
}

第二种

main.js中也可以创建事件中心,创建成功后,在组件中,直接使用,不用导入

代码就不贴了,简单,太累,

第三种:vuex传参

Vuex 实现了一个单向数据流,在全局拥有一个 State 存放数据,当组件要更改 State 中的数据时,必须通过 Mutation 进行,Mutation 同时提供了订阅者模式供外部插件调用获取 State 数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走 Action,但 Action 也是无法直接修改 State 的,还是需要通过 Mutation 来修改 State 的数据。最后,根据 State 的变化,渲染到视图上。

两种写法:一种是直接操作数据,一种是先赋值

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
	state:{
		name:jing,
		age:18,
		look:beautiful
	},
	mutations:{},
	actions:{}
})

在组件中

组件一

<div>
	name:{{username}}
	<button @click="add"> 确认</button>
</div>
data(){
	return(){
		//注意 写在data中,因为先赋值给了username,那么store值如有改变,这里将不能发生改变
		// username:this.$store.state.name 
	}
},
computed:{
	username(){
		return this.$store.state.name
	}
}
methods:{
	add(){
		this.$store.state.name = 'jing+1'
	}
}

组件二

<div>
	name02:{{$store.state.name}}
</div>

如果sore中有许多的值需要获取的话

在组件中引入mapState

import {mapState} from 'vuex'
//1
computed:mapState(['name','age','look']),
//2
computed:mapState({
	storeName:state => state.name,
	storeAge:state => state.age,
	storeLook:state => state.look
})
//但computed也有自己的运算函数,就不能写1、2这样了
computed:{
	...mapState({
		storeName:state => state.name,
		storeAge:state => state.age,
		storeLook:state => state.look
	})
}
第四种:ref/$refs

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

在父组件中

<template>
  <div>
      <login ref="loginRef" />
  </div>
</template>
<script>
import Login from '@/components/login.vue'
export default {
  components:{
    Login
  }
  data() {
    return {};
   },
};
</script>

在子组件中methods中定义一个方法

methods:{
  hider() {
      this.show = true;
    },
}

在父组件中methods中调用

methods:{
    regis() {
      this.$refs.register.shower();
    },
   }

注意

在父组件中是通过this.$refs来调用自组件中的方法,自组件中的方法不用在标签上定义事件,只需要在methods中直接定义一个事件的方法。

第五种:本地存储

根据项目需求,了解localStoragesessionStorage两种本地存储的特性

  • localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据
  • sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;
  • 作用域不同sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的

通过本地存储实现数据的传输

// 保存数据到 sessionStorage
sessionStorage.setItem('key', 'value');

// 从 sessionStorage 获取数据
let data = sessionStorage.getItem('key');

// 从 sessionStorage 删除保存的数据
sessionStorage.removeItem('key');

// 从 sessionStorage 删除所有保存的数据
sessionStorage.clear();

注意

存的是键值对,只能是字符串类型,如果要存对象的话,需要使用JSON.stringify(obj) 转义字符串然后再存储

使用的时候 JSON.parse(objStr) 解析为对象。
推荐一个库 good-storage ,它封装了sessionStorage ,可以直接用它的API存对象

//localStorage
 storage.set(key,val) 
 storage.get(key, def)
//sessionStorage
 storage.session.set(key, val)
 storage.session.get(key, val)

拓展:

推荐使用seeionStorage,随着浏览器的关闭而清除,不会影响下次操作

第六种:路由传值

通过路由传参依旧是有多种方式

出现场景

<div class="examine" @click="details(2)">查看详情</div>

第一种路由拼接

  • 页面刷新数据不丢失
methods:{
  details(id) {
       //直接调用$router.push 实现携带参数的跳转
        this.$router.push({
          path: `/particulars/${id}`,
        })
}

router.js中相应配置。

{
     path: '/particulars/:id',
     name: 'particulars',
     component: particulars
   }

需要在path中添加/:id来对应 $router.pushpath携带的参数。在子组件中可以使用来获取传递的参数值

在页面内个获取参数

this.$route.params.id

第二种:params

页面刷新数据会丢失

通过路由属性中的name来确定匹配的路由,通过params来传递参数

methods:{
  insurance(id) {
       this.$router.push({
          name: 'particulars',
          params: {
            id: id
          }
        })
  }

router.js

 {
     path: '/particulars',
     name: 'particulars',
     component: particulars
   }

在子组件中

this.$route.params.id

注意

这里不能使用:/id来传递参数了,因为组件中,已经使用params来携带参数了

第三种:query传参

使用path来匹配路由,然后通过query来传递参数这种情况下, query传递的参数会显示在url后面?id=?

methods:{
  insurance(id) {
        this.$router.push({
          path: '/particulars',
          query: {
            id: id
          }
        })
  }

router.js

{
     path: '/particulars',
     name: 'particulars',
     component: particulars
   }

对应子组件中

created(){
  this.$route.query.id
}
第七中:全局变量

src目录中新建一个Cloble.js文件,导入到main.js全局文件中,并进行在原型上的一个挂载

main.js中

import Globle from './Globle'
Vue.prototype.$arr = Globle

Goble.js

exports.install = function (Vue) {
    // 每次创建vue实例
    Vue.prototype.$arr = {}
    // 组件中
    // this.$target.arr = arr;
}

相应的组件中

传输数据的一方

 methods: {
    more() {
      let arr = [];
      this.phone.forEach((item) => {
        if (!arr.includes(item.category_id)) {
          arr.push(item.category_id);
        }
      });
      this.$arr.arr = arr;
      this.$router.push({ path: "/goods", query: { categoryID: arr } });
    },

接收数据的一方

  activated() {
    /*
      浏览更多
    */
    if (this.$arr.arr) {
      this.categoryID = this.$arr.arr;
      this.getlist();
    } else {
      this.getlist("list");
    }
  },

全局变量:定义的变量通过挂载可以在全局所有组件中使用,比较方便

存在缺点:页面刷新后,数据会丢失

总结不易,感谢留下脚印

第八中:$root,$parent,$children

$root,$parent都能够实现访问父组件的属性的方法,两者的区别在于,如果存在多级子组件,通过$parent访问得到的是它最近一级的父组件,通过root访问得到的是根组件

1、$children

<body>
		<div id="app">
			<mxc></mxc>
			<mxc></mxc>
			<mxc></mxc>
			<button @click="btnClick">颤抖吧</button>
		</div>
		<template id="mxc">
			<div>我是子组件啊</div>
		</template>
		<script>
			const app=new Vue({
				el:'#app',
				data:{
					message:'你好'
				},
				methods:{
					btnClick(){
						console.log(this.$children)
					}
				},
				components:{
					mxc:{
						template:'#mxc',
						methods:{
							showMessage(){
								console.log('mxcnb')
							}
						}
					}
				}
			})
		</script>
	</body>

通过循环拿到所以的子组件数据

 methods:{
           btnClick(){
                console.log(this.$children)
                 for(let c of this.$children){
                       console.log(c.name)
                  }
               }
           },

注意:

因为是数组,所以我们可以通过比如:this.$children[2]来拿到第三个子组件的数据。
但是这么做有一个问题:比如开发时突然在这三个子组件中又插入了一个子组件(可能相同,也可能不同),这时候【2】就不再是我们需要的了。。。

那么我们就可以用到前面说的的:$refs

2、子访问父组件:$parent

$parent()方法是在子组件中可以直接访问该组件的父实例或组件;

<body>
		<div id="app">
			<mxc></mxc>
		</div>
		<template id="mxc">
			<div>我是子组件啊</div>
			<button @click="btnClick">更加颤抖的child</button>
		</template>
		
		<script>
			const app=new Vue({
				el:'#app',
				data:{
					message:'你好'
				},
				components:{
					mxc:{
						template:'#mxc',
						methods:{
							btnClick(){
								console.log(this.$parent)
							}
						}
					}
				}
			})
		</script>
	</body>

注意:

在实际中$parent用的非常少,主要是考虑到耦合度的原因

3、子组件访问根组件$root

<body>
    <div id="app">
        <mxc></mxc>
    </div>
    <template id="mxc">
        <div>
            <div>我是mxc组件</div>
            <cdn></cdn>
        </div>
    </template>
    <template id="mxca">
        <div>
            <div>我是子子组件啊</div>
            <button @click="btnClick">巨颤祖child</button>
        </div>
    </template>

    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: '你好'
            },
            components: {
                mxc: {
                    template: '#mxc',
                    data() {
                        return {
                            name: '我是中间子组件的name'
                        }
                    },
                    components: {
                        cdn: {
                            template: '#mxca',
                            methods: {
                                btnClick() {
                                    console.log(this.$parent.name)
                                    console.log(this.$root.message)
                                }
                            }
                        }
                    }
                }
            }
        })
    </script>
</body>

码字不易,请留下脚印

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值