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 相关文章推荐
vue-drawer-layout实现手势滑出菜单栏
Nov 19 Vue.js
Vue实现简单购物车功能
Dec 13 Vue.js
vue 基于abstract 路由模式 实现页面内嵌的示例代码
Dec 14 Vue.js
vue 数据操作相关总结
Dec 17 Vue.js
vue中activated的用法
Jan 03 Vue.js
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
May 25 Vue.js
vue实现锚点定位功能
Jun 29 Vue.js
详解gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
Nov 27 Vue.js
Vue.js中v-bind指令的用法介绍
Mar 13 Vue.js
vue使用refs获取嵌套组件中的值过程
Mar 31 Vue.js
Vue+TypeScript中处理computed方式
Apr 02 Vue.js
vue生命周期钩子函数以及触发时机
Apr 26 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 register_shutdown_function函数的深入解析
2013/06/03 PHP
PHP函数strip_tags的一个bug浅析
2014/05/22 PHP
用 Composer构建自己的 PHP 框架之设计 MVC
2014/10/30 PHP
Javascript学习笔记9 prototype封装继承
2010/01/11 Javascript
轻量级 JS ToolTip提示效果
2010/07/20 Javascript
jQuery学习笔记之控制页面实现代码
2012/02/27 Javascript
关于JavaScript中name的意义冲突示例介绍
2014/05/29 Javascript
深入学习JavaScript对象
2015/10/13 Javascript
jQuery实现简易的天天爱消除小游戏
2015/10/16 Javascript
JavaScript事件代理和委托详解
2016/04/08 Javascript
你不需要jQuery(三) 新AJAX方法fetch()
2016/06/14 Javascript
浅谈JS运算符&amp;&amp;和|| 及其优先级
2016/08/10 Javascript
Vuejs第十一篇组件之slot内容分发实例详解
2016/09/09 Javascript
解析微信JS-SDK配置授权,实现分享接口
2016/12/09 Javascript
JS基于面向对象实现的多个倒计时器功能示例
2017/02/28 Javascript
python中合并两个文本文件并按照姓名首字母排序的例子
2014/04/25 Python
Python3实现Web网页图片下载
2016/01/28 Python
python基于socket实现的UDP及TCP通讯功能示例
2019/11/01 Python
python读取dicom图像示例(SimpleITK和dicom包实现)
2020/01/16 Python
如何用Anaconda搭建虚拟环境并创建Django项目
2020/08/02 Python
python属于哪种语言
2020/08/16 Python
详解基于python的全局与局部序列比对的实现(DNA)
2020/10/07 Python
手把手教你配置JupyterLab 环境的实现
2021/02/02 Python
英国汽车座椅和婴儿车购物网站:Uber Kids
2017/04/19 全球购物
高山背包:High Sierra
2017/11/23 全球购物
俄罗斯天然和有机产品、健康生活网上商店:Fitomarket.ru
2020/10/09 全球购物
应用化学专业本科生求职信
2013/09/29 职场文书
主持人演讲稿范文
2013/12/28 职场文书
培训自我鉴定
2014/01/31 职场文书
高三毕业典礼演讲稿
2014/05/13 职场文书
小学生美德少年事迹材料
2014/08/24 职场文书
学位证书委托书
2014/09/30 职场文书
幼儿园万圣节活动总结
2015/05/05 职场文书
来探秘“德国中小企业”的成功之道
2019/07/26 职场文书
React中的Context应用场景分析
2021/06/11 Javascript
JavaScript中document.activeELement焦点元素介绍
2021/11/27 Javascript