vue祖孙组件之间的数据传递案例


Posted in Vue.js onDecember 07, 2020

**解决的问题:**

使用$attrs和$listeners实现祖孙组件之间的数据传递,也就是多重嵌套组件之间的数据传递。

**注意:**

本方法针对vue2.4版本及以上,使用$attrs和$listeners来实现的

**解决方案:**

**首先创建父组件:** 父组件用于动态数据的绑定与事件的定义

<template>
 
 <div>
   <!--这里 :one和:two是向后代组件传递数据-->
  <child1 :one="child1" :two="child2" @test1="onTest1" @test2="onTest2"></child1>
 </div>
</template>
<script> 
import Child1 from './Child.vue'; 
export default { 
 data () {
   return {
   child1:'lihua',
   child2:'lignag',
   parent: 0
   };
  },
 
 components: {
  'child1':Child1 //引入子组件
  },
 
 methods: {
   onTest1 () {
    console.log('child')
   },
 
  onTest2 (val) {
   this.parent = val
   }
  }
 }
 </script>

子组件的写法: 通过设置v-bind="$attrs" 和v-on="$listeners"来充当中间人,

<template>
 <div class="child-1">
  <p>$attrs:{{$attrs['two']}}</p> 
  <hr>
  <!-- 子组件中通过v-bind='$attrs'接受数据,通过$listeners接收事件 -->
  <child2 v-bind="$attrs" v-on="$listeners"></child2>
 </div>
</template>
<script>
import child2 from './Child2.vue';
export default {
 props: ['one','two'], //可写可不写
 data () {
  return {
   
  }
 },
 inheritAttrs: false, //父组件传递动态数据后,子组件的默认行为
 components: {
  child2 
 },
 mounted () {
  this.$emit('test1') //触发父组件方法的一种方式
  this.$listeners.test2(123) //触发父组件方法的另一种方式
 }
}
</script>

孙组件写法: 通过props或者$attrs和$listeners来获取父组件数据和事件。

<template>
 <div class="child-2">
  <p>props:{{one}}</p>
  <p>props:{{two}}</p>
  <p>$attrs: {{$attrs['one']}}</p> 
  <hr>
 </div>
</template>
<script>
export default {
 props:['one','two'], //接收父组件传递的数据,可以不写,通过$attrs来获取
 data(){
  return {};
 },
 inheritAttrs: false, //默认行为需要取消
 mounted(){
  this.$emit('test1') //触发父组件方法的一种方式
  this.$listeners.test1(123)//触发父组件方法的另一种方式
 }
}
</script>

另:inheritAttrs的作用:

先注意一点:使用$attrs时inhertAttrs设置为false.

当inheritAttrs设置为true时,父元素动态绑定组件的数据,子组件如果没有通过props接收的话,该属性就会附加于子组件的根元素上。什么意思看代码

//父组件
 
<child :one="help"></child>
 
data(){
 return {
 help:123 
 }
 }
 
//子组件
 <template>
 <div>
 <h1>作为子组件的我并没有设置props来接收父组件的one属性。</h1>
 </div>
</template>
 
//父组件解析出来就是这样
 
<div one="123">
 <h1>作为子组件的我并没有设置props来接收父组件的one属性。</h1>
</div>

所以呢我们通过v-bind="$attrs"来指定父组件数据的绑定位置,同时设置inheritAttrs为false来取消默认行为

补充知识:理解Vue.mixin,利用Vue.mixin正确的偷懒

关于Vue.mixin在vue官方文档中是这么解释的:

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

我们的理解:

Vue.mixin给我们提供了一种混入Vue实例的方法,创建了混入对象之后,我们自定义的方法或者变量可以很轻松的挂载在Vue实例上,给我们的偷懒带来方便;

Vue.mixin为我们提供了两种混入方式:局部混入和全局混入;

本文还是以demo形式来进行学习讲解,如果有条件最好还是跟着demo敲一遍,这样印象才会深刻;

局部混入:

顾名思义就是部分混入,也就是只有引入了mixin的混入对象才可以使用,并且只有在引入了mixin混入对象的组件中才生效;

来,知道了概念,我们一起来看看代码:

首先自己搭建Vue的开发环境,然后我们在src目录中新建两个vue文件,分别是page1.vue和page2.vue;

page1.vue

<template>
 <div>page1的值是:</div>
</template>

<script>
export default {
 data () {
 return {
  
 }
 },
}
</script>

<style scoped>
</style>

page2.vue

<template>
 <div>page2的值是:</div>
</template>

<script>
export default {
 data () {
 return {
  
 }
 }
}
</script>

<style scoped>

</style>

然后我们修改App.vue

<template>
 <div id="app">
 <button @click="method1">page1</button>
 <button @click="method2">page2</button>

 <router-view></router-view>
 </div>
</template>

<script>
export default {
 name: 'App',
 methods:{
 method1(){
  this.$router.push('/page1');
 },
 method2(){
  this.$router.push('/page2');
 }
 }
}
</script>

<style>
#app {
 font-family: 'Avenir', Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #2c3e50;
 margin-top: 60px;
}
</style>

在src目录下创建router.js文件,配置路由实现跳转

import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);

import page1 from "./page1";
import page2 from "./page2";

const routes=[
 {path:"/page1",component:page1},
 {path:"/page2",component:page2}
]

const router=new VueRouter({
 routes
})

export default router

最后将路由引入main.js中:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router.js'

Vue.config.productionTip = false


/* eslint-disable no-new */
new Vue({
 el: '#app',
 router,
 components: { App },
 template: '<App/>'
})

完成上述准备工作之后,我们可以看到现在的页面效果如下:

vue祖孙组件之间的数据传递案例

没有报错,我们开始正式进入学习Vue.mixin:

首先我们在src目录下新建一个名为mixin的文件夹并在mixin文件中创建一个mixin.js文件:

//抛出混入对象,方便外部访问
export const mixin={
 data(){
  return {
   number:1
  }
 }
}

可以看到我们在混入对象中创建了一个变量,是的,混入对象跟Vue实例的格式是一样的;

然后我们可以将mixin.js引入到我们的page1.vue和page2.vue中

page1.vue

<template>
 //这里读的值其实是mixin的值,因为这个时候mixin已经混入到vue实例中了
 <div>page1的值是:{{number}}</div>
</template>

<script>
//引入mixin.js
import {mixin} from "./mixin/mixin"
export default {
//这里注意:属性名为mixins,值为数组类型
 mixins:[mixin],
 data () {
 return {
  
 }
 },
}
</script>

<style scoped>

</style>

page2.vue

<template>
 <div>page2的值是:{{number}}</div>
</template>

<script>
import {mixin} from "./mixin/mixin"
export default {
 mixins:[mixin],
 data () {
 return {
  
 }
 }
}
</script>

<style scoped>

</style>

这个时候我们的混入对象已经成功混入到Vue实例中,你们可以点击看看效果,是可以正常运行并且能读取到值的;

现在我们来修改page1.vue的代码: 

<template>
 <div>page2的值是:{{number}}</div>
</template>

<script>
import {mixin} from "./mixin/mixin"
export default {
 mixins:[mixin],
 data () {
 return {
  
 }
 }
}
</script>

<style scoped>

</style>

page2不变,再运行可以发现,我们的page1.vue中的值是执行了mounted,所以产生了自增

由此,我们可以知道mixin混入对象的变量是不会共享的;也就是你page1发生了变化,并不会通知mixin进行实时刷新数据,发生的变化只会在page1.vue中生效,不影响其他组件;

现在我们修改mixin.js和page1.vue中的代码:

mixin.js

export const mixin={
 data(){
  return {
   number:1
  }
 },
 created(){
   console.log("mixin混入对象")
 }
}

page1.vue

<template>
 <div>page1的值是:{{number}}</div>
</template>

<script>
import {mixin} from "./mixin/mixin"
export default {
 mixins:[mixin],
 data () {
 return {
  
 }
 },
 created(){
   console.log("这里是page1");
 }
}
</script>

<style scoped>

</style>

这个时候我们再运行可以发现控制台输出是这个样子的:

vue祖孙组件之间的数据传递案例

是的,mixin混入对象中声明了:如果是同名钩子函数将合并为一个数组,因此都被调用,但是混入对象的钩子将在自身实例钩子之前触发;

值为对象的选项,例如methods,components等如果变量名和mixin混入对象的变量名发生冲突,将会以组件优先并进行递归合并,相当于组件数据直接覆盖了mixin中的同名数据;

我们可以修改代码mixin.js和page1.vue

mixin.js

export const mixin={
 data(){
  return {
   number:1
  }
 },
 methods:{
  demo1(){
   console.log("mixin混入对象")
  }
 }
}

page1.vue

<template>
 <div>page1的值是:{{number}}</div>
</template>

<script>
import {mixin} from "./mixin/mixin"
export default {
 mixins:[mixin],
 data () {
 return {
  number:10
 }
 },
 mounted(){
  this.demo1();
 },
 methods:{
  demo1(){
  console.log("这里是page1");
  } 
 }
}
</script>

<style scoped>

</style>

运行代码我们可以很清晰的看到都是执行我们组件内的值;

vue祖孙组件之间的数据传递案例

因为在vue中我们在实例中声明变量也是通过键值对的形式来声明的,其实也是一个对象;

全局混入:

全局混入我们只需要把mixin.js引入到main.js中,然后将mixin放入到Vue.mixin()方法中即可;

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router.js'
import mixin from "./mixin/mixin.js"
Vue.config.productionTip = false
Vue.mixin(mixin)

/* eslint-disable no-new */
new Vue({
 el: '#app',
 router,
 components: { App },
 template: '<App/>'
})

是的,全局混入更为便捷,我们将不用在子组件声明,全局混入将会影响每一个组件的实例,使用的时候需要小心谨慎;这样全局混入之后,我们可以直接在组件中通过this.变量/方法来调用mixin混入对象的变量/方法;

很多同学可能看到这里会有一些疑问,这不就跟Vuex差不多嘛,其实不是的:

mixin混入对象和Vuex的区别:

Vuex是状态共享管理,所以Vuex中的所有变量和方法都是可以读取和更改并相互影响的;

mixin可以定义公用的变量或方法,但是mixin中的数据是不共享的,也就是每个组件中的mixin实例都是不一样的,都是单独存在的个体,不存在相互影响的;

mixin混入对象值为函数的同名函数选项将会进行递归合并为数组,两个函数都会执行,只不过先执行mixin中的同名函数;

mixin混入对象值为对象的同名对象将会进行替换,都优先执行组件内的同名对象,也就是组件内的同名对象将mixin混入对象的同名对象进行覆盖;

以上这篇vue祖孙组件之间的数据传递案例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Vue.js 相关文章推荐
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
Dec 02 Vue.js
vue使用require.context实现动态注册路由
Dec 25 Vue.js
Vue仿百度搜索功能
Dec 28 Vue.js
Vue实现简单计算器
Jan 20 Vue.js
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
Feb 23 Vue.js
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
Mar 01 Vue.js
vue首次渲染全过程
Apr 21 Vue.js
vue实现无缝轮播效果(跑马灯)
May 14 Vue.js
vue实现拖拽交换位置
Apr 07 Vue.js
vue项目proxyTable配置和部署服务器
Apr 14 Vue.js
Vue OpenLayer 为地图绘制风场效果
Apr 24 Vue.js
vue3 自定义图片放大器效果的示例代码
Jul 23 Vue.js
在vue中动态修改css其中一个属性值操作
Dec 07 #Vue.js
在vue中使用inheritAttrs实现组件的扩展性介绍
Dec 07 #Vue.js
vue中利用three.js实现全景图的完整示例
Dec 07 #Vue.js
详解Vue中的自定义指令
Dec 07 #Vue.js
vue-router定义元信息meta操作
Dec 07 #Vue.js
Vue如何实现验证码输入交互
Dec 07 #Vue.js
Vue $attrs &amp; inheritAttr实现button禁用效果案例
Dec 07 #Vue.js
You might like
PHP下用rmdir实现删除目录的三种方法小结
2008/04/20 PHP
PHP获取当前完整URL地址的函数
2014/12/21 PHP
PHP中的静态变量及static静态变量使用详解
2015/11/05 PHP
JS BASE64编码 window.atob(), window.btoa()
2021/03/09 Javascript
JavaScript 节点操作 以及DOMDocument属性和方法
2007/12/06 Javascript
JavaScript Prototype对象
2009/01/07 Javascript
Mootools 1.2教程(21)——类(二)
2009/09/15 Javascript
Json对象与Json字符串互转(4种转换方式)
2013/03/27 Javascript
JS 修改URL参数(实现代码)
2013/07/08 Javascript
jQuery中animate()方法用法实例
2014/12/24 Javascript
jquery插件star-rating.js实现星级评分特效
2015/04/15 Javascript
ionic js 复选框 与普通的 HTML 复选框到底有没区别
2016/06/06 Javascript
AngularJS中$watch和$timeout的使用示例
2016/09/20 Javascript
实现jquery放大镜的两种方法
2018/02/22 jQuery
vue获取当前点击的元素并传值的实例
2018/03/09 Javascript
node打造微信个人号机器人的方法示例
2018/04/26 Javascript
详解微信小程序回到顶部的两种方式
2019/05/09 Javascript
python调用cmd复制文件代码分享
2013/12/27 Python
Python学习笔记之os模块使用总结
2014/11/03 Python
Python实现将n个点均匀地分布在球面上的方法
2015/03/12 Python
介绍Python中的__future__模块
2015/04/27 Python
Python之批量创建文件的实例讲解
2018/05/10 Python
Python爬虫框架scrapy实现的文件下载功能示例
2018/08/04 Python
Python企业编码生成系统之系统主要函数设计详解
2019/07/26 Python
OpenCV利用python来实现图像的直方图均衡化
2020/10/21 Python
基于python实现监听Rabbitmq系统日志代码示例
2020/11/28 Python
美国在线宠物用品商店:Entirely Pets
2017/01/01 全球购物
程序运行正确, 但退出时却"core dump"了,怎么回事
2014/02/19 面试题
商务考察邀请函范文
2014/01/21 职场文书
2014年教师政治学习材料
2014/06/02 职场文书
优秀学生干部个人事迹材料
2014/06/02 职场文书
教师个人成长总结
2015/02/11 职场文书
优秀新员工事迹材料
2019/05/13 职场文书
python 算法题——快乐数的多种解法
2021/05/27 Python
MySQL中order by的使用详情
2021/11/17 MySQL
5个pandas调用函数的方法让数据处理更加灵活自如
2022/04/24 Python