Vue组件通信二&数据同步(v-model、属性修饰符.sync、$attrs与$listeners、refs.$children与refs.$parent、provide与inject )(十三)

vue系列文章目录

第一章:Vue基础知识笔记(模板语法、数据绑定、事件处理、计算属性)(一)
第二章:Vue基础知识(计算属性、监视属性、computed和watch之间的区别、绑定样式)(二)
第三章:Vue基础知识(条件渲染、列表渲染、收集表单数据、过滤器)(三)
第四章:Vue基础知识(内置指令、自定义指令、Vue生命周期)(四)
第五章:Vue基础知识之组件机制(非单文件组件、单文件组件)(五)
第六章:Vue创建脚手架(六)
第七章:Vue使用脚手架(ref、props、mixin、插件、scoped)(七)
第八章:Vue组件通信(组件的自定义事件、全局事件总线、消息订阅与发布、插槽、props)(八)
第九章:Vue使用脚手架(nextTick、Vue封装的过度与动画、vue脚手架配置代理)(九)
第十章:Vuex(十)
第十一章:vue-router(基本使用、路由重定向、多级路由、路由命名、路由的query和params参数、路由的props配置)(十一)
第十二章:vue-router(路由的两种工作模式、router-link的replace属性、编程式路由导航、缓存路由组件keep-alive、路由守卫【全局路由守卫、独享路由守卫、组件内路由守卫】)(十二)

转跳 -> Vue3相关文章


承接第八章组件通信继续拓展


一、v-model(实现父子组件数据同步)

v-model: 指令,可以收集表单数据【text、radio、checkbox、range】等等 切记:v-model收集checkbox需要用数组收集
v-model:实现原理 : 通过value和 @input ,实现父子数据同步

代码片段:
Parent.vue

<template>
  <div>
    <h2>父组件-v-model</h2>
    <input type="text" v-model="msg" />
    <span>{{ msg }}</span>
    <br />
    <h2>父组件-value和input事件实现v-model</h2>
    <!-- 原生DOM当中是有oninput事件:当表单元素发生文本的变化的时候就会立即出发,通过value和input事件实现v-model -->
    <input type="text" :value="msg" @input="msg = $event.target.value" />
    <span>{{ msg }}</span>
    <!--并非原生DOM:自定义组件-->

    <!-- 通过value和input事件实现v-model,此处的input为自定义事件 -->
    <Children :value="msg" @input="msg = $event"></Children>
    <Children v-model="msg"></Children>
    <hr />
  </div>
</template>
<script type="text/ecmascript-6">
import Children from "./Children.vue";
export default {
  name: "Parent",
  data() {
    return {
      msg: "哈哈哈",
    };
  },
  components: {
    Children,
  },
};
</script>

Children.vue

<template>
  <div style="background: #ccc; height: 50px">
    <h2>孩子组件----{{ value }}</h2>
    <!-- 通过发送父组件的自定义事件,同步数据 -->
    <input :value="value" @input="$emit('input', $event.target.value)" />
  </div>
</template>
<script type="text/ecmascript-6">
export default {
  name: "Children",
  props: ["value"],
};
</script>

运行结果:
在这里插入图片描述

二、属性修饰符.sync(实现父子组件数据同步)

将.sync修饰符设置在父组件传递给子组件的数据上,可以实现父子数据同步
代码案例:
Parent.vue

<template>
  <div>
    小明的爸爸现在有{{ money }}元
    <h2>不使用sync修改符</h2>
    <Children :money="money" @update:money="money = $event"></Children>
    <h2>使用sync修改符</h2>
    <!--  -->
    <Children :money.sync="money"></Children>
  </div>
</template>
<script type="text/ecmascript-6">
import Children from "./Children.vue";

export default {
  name: "Parent",
  data() {
    return {
      money: 10000,
    };
  },
  components: {
    Children,
  },
};
</script>

Children.vue

<template>
  <div style="background: #ccc; height: 50px">
    <span>小明每次花100元</span>
    <button @click="$emit('update:money', money - 100)">花钱</button>
    爸爸还剩 {{ money }} 元
  </div>
</template>
<script type="text/ecmascript-6">
export default {
  name: "Children",
  props: ["money"],
};
</script>

运行结果:
在这里插入图片描述

三、$ attrs与$ listeners

$attrs: 组件实例的属性,可以获取到父亲传递的props数据(前提子组件没有通过props接受)

$listeners: 组件实例的属性,可以获取到父亲传递自定义事件对象形式呈现

代码案例:
Parent.vue

<template>
  <div>
    <h2>自定义带Hover提示的按钮</h2>
    <!-- 二次封装的HintButton按钮的时候,把人家el-button需要的数据传递过去 -->
    <Children
      type="success"
      icon="el-icon-plus"
      title="我是中国人"
      @click="handler"
    />
  </div>
</template>
<script type="text/ecmascript-6">
import Children from "./Children";
export default {
  name: "Parent",
  components: {
    Children,
  },
  methods: {
    handler() {
      alert("弹弹弹");
    },
  },
};
</script>

Children.vue

<template>
  <div>
    <a :title="title">
      <!-- v-bind动态绑定属性 -->
      <el-button v-bind="$attrs" v-on="$listeners">添加</el-button>
    </a>
  </div>
</template>
<script>
export default {
  name: "Children",
  props: ["title"],
  mounted() {
    //this.$attrs:可以获取到父亲传递的数据【props】
    //this.$attrs是可以获取父亲传递的props数据,如果子组件通过
    //props:[],接受的属性,this.$attrs是获取不到的
    console.log(this.$attrs);
    console.log(this.$listeners);
  },
};
</script>

运行结果:
在这里插入图片描述

四、refs.$ children与refs.$ parent

ref可以获取到某一个组件,子组件的数据
可以在父组件内部获取子组件—实现父子通信
$children: 可以在父组件内部获取全部的子组件【返回数组】

$parent: 可以在子组件内部获取唯一的父组件【返回组件实例】

代码案例:
Parent.vue

<template>
  <div>
    <h2>BABA有存款: {{ money }}</h2>
    <button @click="JieQianFromXM(100)">找小明借钱100</button><br />
    <button @click="JieQianFromXH(150)">找小红借钱150</button><br />
    <button @click="JieQianAll(200)">找所有孩子借钱200</button><br />
    <button @click="SendInfo">我是baba</button>
    <br />
    <!-- 小明 -->
    <Son ref="xm" />
    <br />
    <!-- 小红 -->
    <Daughter ref="xh" />
  </div>
</template>
<script>
import Son from "./Son";
import Daughter from "./Daughter";
export default {
  name: "Parent",
  data() {
    return {
      money: 1000,
    };
  },
  mounted() {
    console.log(this.$refs.xm);
    console.log(this.$refs.xh);
  },
  methods: {
    //找儿子借钱
    JieQianFromXM(money) {
      //父组件的数据累加100
      this.money += money;
      this.$refs.xm.money -= money;
    },
    JieQianFromXH(money) {
      //父组件的数据累加150
      this.money += money;
      this.$refs.xh.money -= money;
    },
    JieQianAll(money) {
      this.money += 2 * money;
      this.$children.forEach((item) => (item.money -= money));
      //不建议用枚举获取子组件:因为没办法确定到底是那个子组件
      // this.$children[0].money -=money;
    },
    SendInfo() {
      //在父组件中获取到子组件(数据+方法)
      this.$refs.xm.tinghua();
    },
  },
  components: {
    Son,
    Daughter,
  },
};
</script>

Daughter.vue


<template>
  <div style="background: #ccc; height: 50px">
    <h3>女儿小红: 有存款: {{ money }}</h3>
    <button @click="geiQian(50)">给BABA钱: 50</button>
  </div>
</template>
<script>
export default {
  name: "Daughter",
  data() {
    return {
      money: 50000,
    };
  },
  methods: {
    geiQian(money) {
      this.money -= money;
      this.$parent.money += money;
    },
  },
};
</script>

Son.vue

<template>
  <div style="background: #ccc; height: 50px">
    <h3>儿子小明: 有存款: {{ money }}</h3>
    <button @click="geiQian(50)">给BABA钱: 50</button>
  </div>
</template>
<script>
export default {
  name: "Son",
  data() {
    return {
      money: 30000,
    };
  },
  methods: {
    tinghua() {
      console.log("我是小明,我听爸爸的话");
    },
    geiQian(money) {
      this.money -= money;
      this.$parent.money += money;
    },
  },
};
</script>

运行结果:
在这里插入图片描述
在这里插入图片描述

五、provide与inject

由祖先组件使用provide方法传递数据

provide(){
		return {
			//传递的数据
			"属性名":属性值/this.msg
		}
	}

由子孙组件使用inject注入数据

inject:['属性',"属性"]

代码案例:
Parent.vue

<template>
  <div>
    <h3>Parent</h3>
    {{ money }}
    <hr />
    <Children></Children>
  </div>
</template>
<script type="text/ecmascript-6">
import Children from "./Children.vue";

export default {
  name: "Parent",
  data() {
    return {
      money: 10000,
    };
  },
  components: {
    Children,
  },
  provide() {
    return {
      money: this.money,
    };
  },
};
</script>

Children.vue

<template>
  <div>
    <h3>Children</h3>
    <hr />
    <grandChildren></grandChildren>
  </div>
</template>
<script>
import grandChildren from "./grandChildren.vue";
export default {
  name: "Children",
  components: {
    grandChildren,
  },
};
</script>

grandChildren.vue

<template>
  <div>
    <h3>grandChildren</h3>
    {{ money }}
  </div>
</template>
<script>
export default {
  name: "grandChildren",
  inject: ["money"],
};
</script>

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值