vue组件之间的通信方式

组件间的通信方式

1、props

父组件向子组件传数据,子组件接收到数据之后,不能直接修改父组件的数据。否则会报错,因为当父组件重新渲染时,数据会被覆盖。

props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,(仅仅只能接收,props是单向绑定的,即只能父组件向子组件传递,不能反向)若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

  • 父组件
<template>
    <div>
        <h1>我是父组件</h1>
        <br>
        <p>--------------------------</p>
        <br>
        <child :msg='message'></child>
    </div>
</template>

<script>
import child from '../zjlianxi/child.vue';
export default {
  components: { child },
    data() {
        return {
            message:'我是父组件的msg'
        };
    },
};
</script>
  • 子组件
//child.vue
<template>
    <div>
        <h1>我是子组件</h1>
        <br/>
        <h1>{{msg}}</h1>
    </div>
</template>

<script>
export default {
    props:['msg'],
    mounted() {
        console.log(this.msg)
    },
};
</script>
扩展—props
props:{
	title:{
		type:String,
		default:"默认标题"
	},
	time:{
		type:Number,
		default:Date.now()
	},
	list:{                 -------------------注意数组和对象默认值返回格式
		type:Array,
		default(){
			return [1,2,3]
		}
	},
	user:{
		type:Object,
		default(){
			return {name:"匿名",gender:"保密"}
		}
	}
},

2、$emit / v-on

子组件通过派发事件的方式给父组件数据,或者触发父组件更新等操作

  • 父组件
//father.vue
<template>
    <div>
        <h1>我是父组件</h1>
        <br>
        <h1>{{msg}}</h1>
        <p>--------------------------</p>
        <br>
        <child @sendMsg='getMsg'></child>
    </div>
</template>

<script>
import child from '../zjlianxi/child.vue';
export default {
  components: { child },
    data() {
        return {
            msg:""
        };
    },
    methods: {
        getMsg(msg){
            this.msg = msg
            console.log(msg) //接收子组件传过来的数据
        },
    },
};
</script>
  • 子组件
<template>
    <div>
        <h1>我是子组件</h1>
        <br/>
        <el-button @click='changeMsg'>添加</el-button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            msg:'这是给父组件传的信息'
        };
    },
    methods: {
        changeMsg(){
            this.$emit('sendMsg',this.msg)
        }
    },
};
</script>

总结:子组件想要将字符串’'data"传到父组件中。首先需要创建一个事件,在这个事件函数changeMsg中,使用this. e m i t ( ) ,即: t h i s . emit(),即:this. emit(),即:this.emit(“sendMsg”, “data”)。

在父组件中,监听自定义事件sendMsg,当自定义事件触发时,执行新函数getMsg,即:@sendMsg=‘getMsg’

在执行的新函数getMsg中,就可以获取到从子组件传递过来的值,并且自由使用。

3、ref / $refs

ref属性:

1.被用来给元素或子组件注册引用信息(id的替代者)

2.应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)

3.使用方式:

打标识:<h1 ref=" xxx">.....</h1><School ref=" xxx" ></School>
获取: this.$refs.xxx

作用:父组件可以通过this.$refs.xxx的方式去获得子组件的值和调用子组件方法 (xxx是属性ref的值)

代码思路:点击父组件的点击事件,输出子组件的number值20,然后调用子组件的changeAge方法,将number值修改为50,最后输出修改后的number值

  • 父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <br />
    <el-button @click="sendMethod">修改子组件number</el-button>
    <p>--------------------------</p>
    <br />
    <child ref="childRef"></child>
  </div>
</template>

<script>
import child from "../zjlianxi/child.vue";
export default {
  components: { child },
  methods: {
    sendMethod() {
      console.log("点击前", this.$refs.childRef.number); //点击前 20
      this.$refs.childRef.changeNumber();
      console.log("点击后", this.$refs.childRef.number); //点击后 50
    },
  },
};
</script>
  • 子组件

//child.vue
<template>
  <div>
    <h1>我是子组件</h1>
    <br />
    <h1>{{ number }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      number: 20,
    };
  },
  methods: {
    changeNumber() {
      this.number = 50;
    },
  },
};
</script>
4、$parent + $children

(1)$children:

官方介绍:当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的

即$children是组件自带的属性,它可以获取到当前组件的子组件,并以**数组**的形式返回。

(2)$parent:

官方介绍:指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用 this.$parent 访问父实例,子实例被推入父实例的 $children 数组中。

如果组件没有父组件,他的 p a r e n t 为 u n d e f i n e d , A p p 组件 ( 根组件 ) 的 parent为undefined,App组件(根组件)的 parentundefinedApp组件(根组件)parent不是undefined,也不是App本身。

注意:节制地使用 $parent 和 $children - 它们的主要目的是作为访问组件的应急方法。弊端是:无法在跨级或兄弟间通信.

$parent 获取父节点中所有数据和方法

  • 父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <br />
    <p>--------------------------</p>
    <br />
    <child @sendMethod='sendMethod' :number="number"></child>
  </div>
</template>

<script>
import child from "../zjlianxi/child.vue";
export default {
  components: { child },
  data() {
    return {
      message: "我是父组件的msg",
      number: 20,
    };
  },
  methods: {
    sendMethod() {
        this.number = 50 ----给子组件的
    },
  },
};
</script>
  • 子组件
<template>
  <div>
    <h1>我是子组件</h1>
    <br />
    <h1>{{ parentMessage }}</h1>
    <h1>{{number}}</h1>
  </div>
</template>

<script>
export default {
  props:['number'],
  mounted() {
     this.$parent.sendMethod()  //获取父组件的方法   未调用时number为20,调用时number为50
  },
  computed: {
    parentMessage() {
      return this.$parent.message; //获取父组件中的属性
    },
  },
};
</script>

$children 获取子组件中所有数据和方法

  • 父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <br />
    <h1>{{name}}</h1>
    <p>--------------------------</p>
    <br />
    <child></child>
  </div>
</template>

<script>
import child from "../zjlianxi/child.vue";
export default {
  components: { child },
  data() {
    return {
      name:''
    };
  },
  mounted() {
    // this.$children[0].sendMethod()   //调用子组件的方法  未调用时name:小李,调用时name:小王
    this.name =this.$children[0].name   //获取子组件的属性值   小李
  },
};
</script>
  • 子组件
<template>
  <div>
    <h1>我是子组件</h1>
    <br />
  </div>
</template>

<script>
export default {
  data() {
    return {
      name:'小李'
    };
  },
  methods: {
    sendMethod(){
        this.name = '小王'
    },
  },
};
</script>
5、provide + inject

provide/inject可以轻松实现跨级访问父组件的数据

provide / inject 是依赖注入,在一些插件或组件库里被常用

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。(如果你熟悉 React,这与 React 的上下文特性很相似。)

provide:可以让我们指定想要提供给后代组件的数据或方法

inject:在任何后代组件中接收想要添加在这个组件上的数据或方法,不管组件嵌套多深都可以直接拿来用

要注意的是 provide 和 inject 传递的数据不是响应式的,也就是说用 inject 接收来数据后,provide 里的数据改变了,后代组件中的数据不会改变,除非传入的就是一个可监听的对象 所以建议还是传递一些常量或者方法

  • 父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <br />
    <p>--------------------------</p>
    <br />
    <child></child>
  </div>
</template>

<script>
import child from "../zjlianxi/child.vue";
export default {
  components: { child },
  name: "ProjectFather",
  // 方法一
  provide: {
    name: "oldCode",
  },
  // 方法二
  provide() {
    return {
      name: "oldCode",
      age: this.age, //this.data中的属性,
      someMethod: this.someMethod, // methods 中的方法
    };
  },
  data() {
    return {
      age: 20,
    };
  },
  methods: {
    someMethod() {
      console.log("这是注入的方法");
    },
  },
};
</script>
};
</script>
  • 子组件
<template>
  <div>
    <h1>我是子组件</h1>
    <br />
    <h1>{{ name }}</h1>
    <h1>{{ age }}</h1>
  </div>
</template>

<script>
export default {
  inject: ["name"],
  inject: ["name", "age", "someMethod"],
  mounted() {
    this.someMethod()
  },
6、$attrs + $listeners

多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果**仅仅是传递数据,而不做中间处理,**使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法 ---- $attrs / $listeners。

  • $attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=" $attrs"传入内部组件。通常配合 interitAttrs 选项一起使用。
  • l i s t e n e r s :包含了父作用域中的 ( 不含 . n a t i v e 修饰器的 ) v − o n 事件监听器。它可以通过 v − o n = " listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=" listeners:包含了父作用域中的(不含.native修饰器的)von事件监听器。它可以通过von="listeners" 传入内部组件.

实现思路:

父组件定义name和age传给子组件,子组件使用v-bind=“ a t t r s " 的方式传给孙子组件,孙子组件使用 attrs"的方式传给孙子组件,孙子组件使用 attrs"的方式传给孙子组件,孙子组件使用attrs.name的形式使用name和age的值,子组件通过点击事件(@click=”$listeners.changeName")调用父组件的changeName方法,将name值修改为小李

  • 父组件
<template>
  <div>
    <h1>我是父组件</h1>
    <br />
    <p>--------------------------</p>
    <br />
    <child :name="name" :age='age' @changeName="changeName"></child>
  </div>
</template>

<script>
import child from "../zjlianxi/child.vue";
export default {
  components: { child },
  data() {
    return {
      age: 20,
      name:'小李'
    };
  },
  methods: {
    changeName(){
        this.name = '小明'
    }
  },
};
</script>
  • 子组件
//child.vue
<template>
  <div>
    <h1>我是子组件</h1>
    <br />
    <h1>年龄:{{age}}</h1>
    <el-button @click="$listeners.changeName">修改name</el-button>
    <br/>
    <p>------------------</p>
    <br/>
    <grandson v-bind='$attrs'></grandson>   ------$attrs会传没有从props获取之外的属性给子子组件
  </div>
</template>

<script>
import grandson from '../zjlianxi/grandson.vue';
export default {
  components: { grandson },
  props:['age'],----------------------------props接收的属性
};
</script>
  • 孙组件
//grandson.vue
<template>
    <div>
        <h1>我是子子组件</h1>
        <h1>{{$attrs.name}}</h1> 
    </div>
</template>
7、 EventBus

注意:

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

app.vue

<template>
  <div class="container">
    <my-a></my-a>
    <my-b></my-b>
    <my-c></my-c>
  </div>
</template>

<script>
import myA from "./a.vue";
import myB from "./b.vue";
import myC from "./c.vue";
export default {
  components: {
    myA,
    myB,
    myC,
  },
};
</script>

(1)局部

在src/components中新建一个Bus.js文件,然后导出一个空的vue实例

import Vue from 'vue'
export default new Vue;

组件

//a.vue     要传数据的一方
<template>
  <div>
    <h3>A组件:{{ name }}</h3>
    <button @click="send">将数据发送给C组件</button>
  </div>
</template>

<script>
import bus from '../../components/Bus'   ------引入
export default {
  data() {
    return {
      name: "tom",
    };
  },
  methods: {
    send() {
      bus.$emit("data-a", this.name);
    },
  },
};
</script>

//b.vue  要传数据的一方
<template>
  <div>
    <h3>B组件:{{ age }}</h3>
    <button @click="send">将数组发送给C组件</button>
  </div>
</template>

<script>
import bus from '../../components/Bus'    ------引入
export default {
  data() {
    return {
      age: 20,
    };
  },
  methods: {
    send() {
      bus.$emit("data-b", this.age);
    },
  },
};
</script>


!!!接收数据的一方
//c.vue
<template>
  <div>
    <h3>C组件:{{ name }},{{ age }}</h3>
  </div>
</template>

<script> 
import bus from '../../components/Bus'     ------引入
export default {
  data() {
    return {
      name: "",
      age: "",
    };
  },
  mounted() {
    bus.$on("data-a", (name) => {
      //箭头函数内部不会产生新的this,这边如果不用=>,this指代Event
      this.name = name;
    });
    bus.$on("data-b", (age) => {
      this.age = age;
    });
  },
};
</script>

(2)全局注册

在main.js中

Vue.prototype.$bus = new Vue()

组件

//a.vue   要传数据的一方
<template>
  <div>
    <h3>A组件:{{ name }}</h3>
    <button @click="send">将数据发送给B组件</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "tom",
    };
  },
  methods: {
    send() {
      this.$bus.$emit("data-a", this.name);  --------------this.$bus.$emit()
    },
  },
};
</script>

//b.vue    接收数据的一方
<template>
  <div>
    <h3>B组件:{{ name }}</h3>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "",
    };
  },

  mounted() {
    this.$bus.$on("data-a", (name) => { ---------------------------- this.$bus.$on()
      //箭头函数内部不会产生新的this,这边如果不用=>,this指代Event
      this.name = name;
    });
  },
};
</script>
8、slot

插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。

(1)简单示例

  • 父组件
//father.vue
<template>
  <div>
    <h1>我是父组件</h1>
    <br />
    <p>--------------------------</p>
    <child>
        <div style="margin-top: 30px">我是子组件slot的内容</div>
    </child>
  </div>
</template>

<script>
import child from "../zjlianxi/child.vue";
export default {
  components: { child },
};
</script>
  • 子组件
//child.vue
<template>
  <div>
    <h1>我是子组件</h1>
    <br />
    <slot></slot>----------------------------slot
  </div>
</template>

(2)具名插槽

父组件 :父组件通过 v-slot:[name] 的方式指定到对应的插槽中

子组件 :设置了两个插槽(header和footer):

  • 父组件
//father.vue
<template>
<div>
    <div>slot内容分发</div>
    <child>
        <template slot="header">
            <p>我是页头的具体内容</p>
        </template>
        <template slot="footer">
            <p>我是页尾的具体内容</p>
        </template>
    </child>
</div>
</template>
 
<script>
import child from "../zjlianxi/child.vue";
    export default {
        components: {
            child
        }
    }
</script>
  • 子组件
//child.vue
<template>
    <div>
        <div class="header">
            <h1>我是页头标题</h1>
            <div>
                <slot name="header"></slot>
            </div>
        </div>
        <div class="footer">
            <h1>我是页尾标题</h1>
            <div>
                <slot name="footer"></slot>
            </div>
        </div>
    </div>
</template>
9、vuex

https://blog.csdn.net/qq_55031668/article/details/128715292?spm=1001.2014.3001.5501

10、路由传值

方法一:

//father.vue
<template>
  <div class="container">
    <h1>我是父组件!</h1>
    <button @click="details(2)">查看详情页</button>
  </div>
</template>
methods: {
  details(id){
     this.$router.push({ path: "/a", query: { id: id, flag:'details' } });
  },
},
//app.vue   ------ 在mounted获取
mounted() {
  this.Id = this.$route.query.id;
  this.flag = this.$route.query.flag;
  console.log(this.Id);
  console.log(this.flag);
},

方法二
router.js 注意::id?—?代表可有可无

{
    path: '/employee/detail/:id?', // 员工详情的地址
    component: () => import('@/views/employee/detail.vue'),
    hidden: true, // 表示隐藏在左侧菜单
    meta: {
      title: '员工详情' // 显示在导航的文本
    }
}


//在页面中获取参数的中id
created() {
    // 如何获取路由参数的中id
    //可以打印下console.log(this.$route.params)
    let id = this.$route.params.id
},

vue页面

 <el-button size="mini" type="primary" @click="$router.push('/employee/detail')">添加员工</el-button>
  <el-button size="mini" type="text" @click="$router.push(`/employee/detail/${row.id}`)">查看</el-button>   ===>传参
11、.sync修饰符

父组件:接收子组件传过来的值

<!-- 表示会接收子组件的事件   update:showExcelDialog, 值 => 属性-->
 <import-excel :show-excel-dialog.sync="showExcelDialog"  />

子组件:
1、通过$emit(“update:showDialog”,false)把false传给父组件

<el-button size="mini" type="primary" @click="close">取消</el-button>
close(){
	//修改父组件的值,子传父
	this.$emit('update:showExcelDialog',false)
}

2、

 <el-button size="mini" type="primary" @click="$emit('update:showDialog', false)">取消</el-button>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值