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实现两个区域滚动条同步滚动
Dec 13 Vue.js
Vue实现省市区三级联动
Dec 27 Vue.js
Vite和Vue CLI的优劣
Jan 30 Vue.js
Vue如何实现变量表达式选择器
Feb 18 Vue.js
Vue多选列表组件深入详解
Mar 02 Vue.js
vue如何批量引入组件、注册和使用详解
May 12 Vue.js
Vue3.0写自定义指令的简单步骤记录
Jun 27 Vue.js
Vue实现tab导航栏并支持左右滑动功能
Jun 28 Vue.js
详解Vue router路由
Nov 20 Vue.js
Vue的生命周期一起来看看
Feb 24 Vue.js
Vue+TypeScript中处理computed方式
Apr 02 Vue.js
vue递归实现树形组件
Jul 15 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边学边教》(02.Apache+PHP环境配置――上篇)
2006/12/13 PHP
php输出echo、print、print_r、printf、sprintf、var_dump的区别比较
2013/06/21 PHP
php while循环得到循环次数
2013/10/26 PHP
php中$_GET与$_POST过滤sql注入的方法
2014/11/03 PHP
浅谈PDO的rowCount函数
2015/06/18 PHP
PHP7新特性之抽象语法树(AST)带来的变化详解
2018/07/17 PHP
jQuery 技巧小结
2010/04/02 Javascript
javaScript call 函数的用法说明
2010/04/09 Javascript
异步JavaScript编程中的Promise使用方法
2015/07/28 Javascript
jqPlot jQuery绘图插件的使用
2016/06/18 Javascript
JavaScript实现url参数转成json形式
2016/09/25 Javascript
Angularjs中的页面访问权限怎么设置
2016/11/11 Javascript
jquery处理checkbox(复选框)是否被选中实例代码
2017/06/12 jQuery
浅谈vue中数据双向绑定的实现原理
2017/09/14 Javascript
支付宝小程序自定义弹窗dialog插件的实现代码
2018/11/30 Javascript
Vue v-text指令简单使用方法示例
2019/09/19 Javascript
js判断密码强度的方法
2020/03/18 Javascript
React中使用Vditor自定义图片详解
2020/12/25 Javascript
Python实现Mysql数据库连接池实例详解
2017/04/11 Python
django_orm查询性能优化方法
2018/08/20 Python
selenium+python截图不成功的解决方法
2019/01/30 Python
Python3多目标赋值及共享引用注意事项
2019/05/27 Python
Python 堆叠柱状图绘制方法
2019/07/29 Python
Ubuntu下Python+Flask分分钟搭建自己的服务器教程
2019/11/19 Python
基于Python和PyYAML读取yaml配置文件数据
2020/01/13 Python
在echarts中图例legend和坐标系grid实现左右布局实例
2020/05/16 Python
印度最大的酒店品牌网络:OYO Rooms
2016/07/24 全球购物
New Balance法国官方网站:购买鞋子和服装
2019/09/01 全球购物
项目经理任命书
2014/06/04 职场文书
公司总经理岗位职责范本
2014/08/15 职场文书
物流管理专业推荐信
2014/09/06 职场文书
绿色校园广播稿
2014/10/13 职场文书
2014年节能降耗工作总结
2014/12/11 职场文书
党员公开承诺书2015
2015/01/21 职场文书
导游词之京东大峡谷旅游区
2019/10/29 职场文书
Elasticsearch6.2服务器升配后的bug(避坑指南)
2022/09/23 Servers