Vue2的16种传参通信方式

embedded/2024/12/21 23:46:31/

前言

先直入主题列出有哪些传参方式,下面再通过事例一一讲解。

props(父传子)
$emitv-on (子传父)
EventBus (兄弟传参)
.syncupdate: (父子双向)
v-model (父子双向)
ref
$children$parent
$attrs$listeners (爷孙双向)
provideinject (多层传参)
Vuex (全局)
Vue.prototype (全局)
路由
浏览器缓存 (全局)
window (全局)
$root (顶层)
slot(父传子)

一、props(父传子)

思路简述:父组件直接用冒号 :绑定变量,然后子组件通过 props接收父组件传过来的内容。

父组件代码:核心代码在第3行,直接用:message="message"传参。

<template><div><child  :message="message" /></div>
</template><script>
import child  from './child .vue';
export default {components: {child },data() {return {message: '这是父组件传过去的'};}
};
</script>

子组件代码: 用props接收消息后可以直接使用,如下第3行和第16行中直接使用

注意: props有两种接收方法,如下第9行注释的就是简写用法,此用法不能设置默认值。

<template><div><p>接收到的消息: {{ message }}</p></div>
</template><script>export default {//props:['message'],props: {message: {type: String,default: '', // 这里能设置默认值,如果父组件没有传参,默认值会生效},},mounted() {console.log(this.message);},};
</script>

注意: 此传参方式是单向的,即子组件接收到父组件的数据后,是不能直接修改props接收的数据,否则会直接报错。

二、$emitv-on (子传父)

思路简述: 子组件通过$emit触发父组件的指定方法并且在此方法中携带任意参数,父组件通过在被触发的方法中拿到携带的参数完成子传父。

语法:$emit(方法名,参数)

子组件代码:核心代码在第11行,触发方法并且携带参数。

<template><div><button @click="sendParent">点击发送数据给父组件</button></div>
</template><script>export default {methods: {sendParent() {this.$emit('my-event', '这是传递的参数');},},};
</script>

父组件代码:核心代码在第3行触发事件,获取到子组件的传参。

<template><div><child v-on:my-event="childEvent" />// 或者用@简写代替v-on<child @my-event="childEvent" /></div>
</template><script>import child from './child.vue';export default {components: {child,},methods: {childEvent(item) {console.log('接收到子组件的传参:', item);},},};
</script>

三、EventBus (兄弟传参)

思路简述: 先创建一个全局的事件总线Bus(可以随意命名),并挂载在Vue.prototype上。

然后兄弟组件A通过$emit发送参数,兄弟组件B通过$on接收参数。

  • 有两种使用方法,下面分别讲解。
方法一:直接挂载全局事件总线,全局直接使用不需要额外引入。

先在项目的入口文件中(main.jsmain.ts)创建全局事件Bus并且挂载在Vue.prototype*

import Vue from 'vue';const Bus = new Vue();Vue.prototype.$Bus = Bus;

兄弟组件A代码:通过this.$Bus.$emit(方法名,参数)发送参数。

<template><div><button @click="sendSibling">点击发送内容给兄弟组件</button></div>
</template><script>export default {methods: {sendSibling() {this.$Bus.$emit('my-event', '参数');},},};
</script>

兄弟组件B代码:通过this.$Bus.$on(对应$emit的方法,本地方法)触发本地的方法,从而接收参数。

<template><div> 我是兄弟组件B </div>
</template><script>export default {created() {this.$Bus.$on('my-event', this.handleMessage);},beforeDestroy() {this.$Bus.$off('my-event', this.handleMessage);},methods: {handleMessage(message) {console.log('来自兄弟的参数:', message);},},};
</script>

注意: 如上第10-12行所示,在组件销毁前要在 beforeDestroy 生命周期中使用$off移除移除$on的事件监听器,防止避免内存泄漏影响性能。如下所示

方法二: 不创建全局事件总线,单独开一个文件,哪里需要就哪里引用。

创建一个单独文件命名为Bus.js(可以自由命名)

import Vue from "vue"export default new Vue()

兄弟组件A代码: 先引入Bus.js文件,然后通过Bus.$emit(方法名,参数)发送参数。

<template><div><button @click="sendSibling">点击发送内容给兄弟组件</button></div>
</template><script>import Bus from './Bus.js';export default {methods: {sendSibling() {Bus.$emit('my-event', '参数');},},};
</script>

兄弟组件B代码:先引入Bus.js文件,然后通过Bus.$on(对应$emit的方法,本地方法)触发本地的方法,从而接收参数。同样也需要使用$off销毁事件监听。

<template><div> 我是兄弟组件B </div>
</template><script>import Bus from './Bus.js';export default {created() {Bus.$on('my-event', this.handleMessage);},beforeDestroy() {Bus.$off('my-event', this.handleMessage);},methods: {handleMessage(message) {console.log('来自兄弟的参数:', message);},},};
</script>

四、.syncupdate: (父子双向)

思路简述: .sync其实是一个语法糖, 配合子组件用 this.$emit('update:绑定的属性名', 方法)修改父组件属性, 能解决 props只能单向传递的问题。

父组件代码:核心代码在第3行,比普通的父传子多使用了.sync修饰符。

<template><div><chile :myprop.sync="myData" /></div>
</template><script>
import chile from './chile.vue';export default {components: {chile},data() {return {myData: '父组件数据'};}
};
</script>

子组件代码:核心代码是第14行,通过this.$emit同步修改父组件内容。

<template><div><button @click="updateData">点击子修改父传过来的数据</button></div>
</template><script>export default {props: {myprop: String,},methods: {updateData() {this.$emit('update:myprop', 新内容);},},};
</script>

注意:使用.sync修饰符时,this.$emit里面总是以update:开头,后面接要修改的属性名称。

五、v-model (父子双向)

思路简述:v-model最常用于表单,它其实是一个语法糖,并且和上面.sync有点类似。v-model本质上是v-bind:value@input组件效果。通过v-bind:value绑定数据父传子,通过@input触发对应事件子传父从而实现双向绑定。

父组件代码:直接用v-model绑定要传给子组件的参数,当子组件触发input事件时父组件myData会同步更新。

<template><div><child v-model="myData" /></div>
</template><script>
import child from './child.vue';export default {components: {child},data() {return {myData: '天天鸭'};}
};
</script>

子组件代码:input输入框的内容发生变化时,就会触发@input事件,然后this.$emit同步修改父组件的值

<template><div><input :value="childData" @input="handleChange" /></div>
</template><script>
export default {model: {prop: 'myProp',event: 'input'},props: {myProp: String},data() {return {childData: this.myProp};},methods: {handleChange(event) {this.childData = event.target.value;this.$emit('input', this.childData);}}
};
</script>

注意:在子组件当中,必须要定义model来指定props和事件名称(名称默认为input)。

六、ref

思路讲解: ref主要用来访问子组件的方法和属性,是直接操纵DOM的方式。主要用法是在子组件上绑定一个ref,然后父组件用this.$refs直接访问子组件的方法

父组件代码:子组件上用ref="refChild"绑定一个ref,然后用this.$refs.refChild获取到子组件实例,能获取到子组件属性和操纵子组件方法。

<template><div><child ref="refChild" /></div>
</template><script>import child from './child.vue';export default {components: {child,},mounted() {let childObj = this.$refs.refChild;console.log(childObj.name); // 直接获取到子组件的属性内容 打印出来:天天鸭childObj.childMethod('参数'); // 触发子组件的方法},};
</script>

子组件代码:

<template><div></div>
</template><script>export default {data() {return {name: '天天鸭',};},methods: {childMethod(val) {console.log(val);},},};
</script>

七、$children$parent

简述: $children 和 $parent 是Vue用于访问子组件实例和父组件实例的特殊属性。其中$children能获取所有子组件实例但不能获取孙子的,而$parent获取当前组件的父组件实例。

父组件代码: 直接使用this.$children即可获取。

注意: 获取到的实例可能为空,因此需要判空。并且如果有多个子组件时返回的是一个数组,所以需要通过下标确认对应的子组件数据。

<template><div><child /><button @click="getChildMethod">调用子组件方法</button></div>
</template><script>import child from './child.vue';export default {components: {child,},methods: {getChildMethod() {// 判空,然后用下标获取if (this.$children.length > 0) {this.$children[0].childMethod();  // 使用子组件方法this.$children[0].name;    // 使用子组件属性}},},};
</script>

子组件代码: 类似地,父组件也是同样用法,但区别是返回的不是数组而且一个对象,能直接使用。

<template><div></div>
</template><script>export default {mounted(){this.$parent.parMethod()this.$parent.name}};
</script>

八、$attrs$listeners (爷孙双向)

简述: $attrs和 $listeners相当于是使用在父亲组件上的一个中转站。 $attrs用于将props外的数据从爷组件传递给孙组件的,而$listeners用于从孙组件中触发爷组件中事件达到传参效果。

下面把$attrs$listeners分开讲解更易于理解。

$attrs使用流程代码:

(1)爷组件代码: 类似父传子,正常用冒号绑定属性传参。

<GrandParent :name=name></GrandParent>

(2)父组件代码$attrs作用在父组件,意思是把props之外属性全部传递给到孙子。

注意:如果这里父组件用 props接收了 name属性,那么用 $attrs无法传递到孙子组件,因为只能传递 props之外属性。
<Parent v-bind="$attrs"></Parent>

(3)孙组件代码:类似父传子,正常用popos接收爷组件传过来的参数。

<template><div> 爷组件传来的:{{ name }} </div>
</template>
<script>export default {props: {name: {default: String,},},};
</script>

$listeners使用流程代码:

(1)孙组件代码 直接this.$emit类似子传父

<template><div><el-button @click="update">点击孙传爷</el-button></div>
</template><script>export default {methods: {update() {this.$emit('my-event', '孙传给爷的数据');},},};
</script>

(2)父组件代码:$listeners作用在父组件。

<Parent v-bind="$listeners"></Parent>

(3)爷组件代码: 类似子传父中的父组件,触发对应孙子组件this.$emit中的my-event事件接收到参数。

<template><div><Parent @my-event="getMyEvent" /></div>
</template><script>import Parent from './Parent.vue';export default {components: {Parent,},methods: {getMyEvent(val) {console.log('爷组件接收到的数据:', val);},},};
</script>

这里感觉算两种(爷传孙与孙传爷)传参方式了,但由于都是类似中转站效果,所以放一起说比较好理解。

九、provideinject (多层传参)

简述: provideinject无论多少层组件都能传参。顶层组件通过provide传参,下面所有组件都能用inject接收,而且子组件也能通过方法给顶层组件传参。

顶层组件代码: 核心代码在第8行的provide()中,可以传递常量、变量和方法。

<template><div> </div>
</template><script>export default {provide() {return {name: '天天鸭',age: this.age,myMethod: this.myMethod,};},data() {return {age: '18',};},methods: {myMethod(data) {console.log('收到来自某个孙子的数据:', data);},},};
</script>

子孙组件代码:核心代码在第10行接收参数, 除了能接收顶层参数外,还能通过参考第13行的用法,通过顶层给到的方法传参给顶层组件。

<template><div><el-button @click="myMethod('我是孙子组件')">我是孙子组件</el-button>这是顶层传下来的参数: {{ name }}</div>
</template><script>export default {inject: ['name', 'age', 'myMethod'],methods: {myMethod(data) {this.myMethod(data); // 传参给顶层祖先组件},},};
</script>

十、Vuex (全局)

有针对性写过对应的文章,可以直接跳转细看:对比学习vuex和pinia用法

十一、Vue.prototype (全局)

简述:能用Vue.prototype把任何属性和方法挂载在Vue实例了,让所有Vue实例共用。

(1)挂载属性 直接往Vue.prototype挂载即可

Vue.prototype.$testName = '天天鸭';

(2)挂载方法直接往Vue.prototype挂载即可

Vue.prototype.$testMethod = function(val) {console.log(val);
};

调用:直接在任何页面用this调用

this.$appName;this.$testMethod('参数');

十二、浏览器缓存

简述: localStorage 和sessionStorage:主要是浏览器用来持久化存储的,这算是用的不多,但也是必用的一种通信方式。两者区别如下

sessionStorage(临时存储):最大空间 5M,为每一个数据源维持一个存储区域,但只在浏览器打开期间存在,关闭后数据会不会消失,包括页面重新加载。
localStorage(长期存储):最大空间 5M,与 sessionStorage 一样,但是哪怕浏览器关闭后,数据依然会一直存在,除非手动删除。

具体用法如下所示:

// 存储
sessionStorage.setItem('key', 'value');
localStorage.setItem('key', 'value');// 获取
let valueFromSessionStorage = sessionStorage.getItem('key');
let valueFromLocalStorage = localStorage.getItem('key');// 删除
sessionStorage.removeItem('key');
localStorage.removeItem('key');// 清空所有
sessionStorage.clear();
localStorage.clear();

注意:存储的数据只能是字符串形式,因此如果要存储对象或者数组,则需要使用JSON.stringify来转换后再存储,读取后用JSON.parse还原。

十三、window (全局)

简述: 直接用语法 window.age = '18' 定义然后全局通用即可。(此方式是存放在内存刷新会清空)

注意:在 Vue 应用中,虽然可以直接将属性挂载到 window 对象上实现全局通用,但并推荐,因为这可能会出现命名冲突、导致代码难以维护

添加属性和方法:直接定义,可以是属性也可以是对象

window.Obj = { test: '挂载对象' }
window.name = '天天鸭'

使用:

console.log( window.Obj); 
console.log( window.name);  

十四、路由

简述: Vue在路由跳转时携带参数其实也很常用的方式,下面汇总一下三种路由传参。

(1)通过 params 传参 跳转页面用法:

this.$router.push({name:"index", params:{id}})

目标页面接收参数:

this.$route.params.id 

(2)通过 query 传参

跳转页面用法:有几种方式

this.$router.push({ name:"index", query:{id}})this.$router.push({ path:"/index", query:{id}}) this.$router.push('/index?name='+obj.name+'&age='+obj.age)

目标页面接收参数:

this.$route.query.id

(3)通过动态路由传参

注意: 如果用动态路由传参需要对路由进行配置;并且参数会在 url 中显示。 如下所示,在path后面要配置:name/:age.

{ path: '/about/:name/:age' ,  name: 'About', component() => import('@/views/About.vue') 
}

跳转页面用法:

this.$router.push('/about/'+obj.name+'/'+obj.age) 

目标页面接收参数:

this.$route.params

十五、$root (顶层)

简述: 可以通过 $root 访问到整个 Vue 树的根实例,也就是可以使用 $root 来访问全局的属性或者修改全局的属性。

示例:在main.js文件中定义一个globalName属性,可以全局使用。

import App from './App.vue';
import Vue from 'vue';new Vue({el: '#app',render: h => h(App),data: {globalName: '天天鸭'}
});

在下层任意组件使用或者修改内容

<template><div>{{ globalName }}</div>
</template><script>
export default {mounted() {this.$root.globalName = '修改数据';},
};
</script>

十六、slot(父传子)

简述: 通过插槽也是可以传递参数,这也是很多人忽略的一种方式。父组件可以通过插槽向子组件传递参数,然后子组件拿到参数进行渲染。

下面主要讲解具名插槽和默认插槽两种使用方式。

(1)具名插槽用法

子组件代码: 用slot定义一个名叫header的插槽。

<template><div><slot name="header"></slot></div>
</template><script>
export default {
};
</script>

父组件代码:v-slot:header向子组件的header插槽传递内容。这边传递什么那边就会在对应区域显示什么。

<template><div><child><template v-slot:header><h1>这是插槽的内容</h1></template></child></div>
</template><script>
import child from './child.vue';export default {components: {child}
};
</script>

(2)无参数传递的默认插槽

子组件代码: 用slot定义插槽时不需要指定name名称。

<template><div><slot></slot></div>
</template><script>
export default {
};
</script>

父组件代码:不需要指定插槽名称,只要在组件中间填写内容就会渲染在默认插槽中。

<template><div><child><p>默认插槽中的内容。</p></child></div>
</template><script>
import child from './child.vue';export default {components: {child}
};
</script>

http://www.ppmy.cn/embedded/100598.html

相关文章

【ORACLE】 ORA-01691: Lob 段无法通过 8192 (在表空间 XXX_SPACE 中) 扩展

ORA-01691错误通常表示Oracle数据库在尝试扩展LOB段时无法为表空间分配更多的空间。这个问题通常由表空间容量不足引起。根据搜索结果&#xff0c;以下是几种可能的解决方案&#xff1a; 检查并扩大表空间&#xff1a;首先&#xff0c;确认表空间是否已经达到其最大容量。可以使…

JS 和 ES6 补充学习

1、JS对象-自定义对象 let 对象名 {属性名1&#xff1a;属性值1&#xff0c;属性名2&#xff1a;属性值2&#xff0c;属性名3&#xff1a;属性值3&#xff0c;函数名称&#xff1a;function&#xff08;形参列表&#xff09;{}&#xff0c;函数名称&#xff08;形参列表&…

Docker 存储空间不足无法导入加载镜像

问题&#xff1a;在载入镜像时&#xff0c;发现docker没有空间了 解决办法&#xff1a; 更改docker的存储路径 1.添加新的硬盘 docker info #查看docker的存储位置 df -Th #查看占用以及挂载情况 发现没有可用的剩余空间&#xff0c;我们可以添加一个新的硬盘 在linu…

逻辑判断2-论证类(非归因论证)

目录 一、数量论证1.比例类论证2.抽样类论证3.盐水类论证4.其他数学模型二、严谨逻辑关系1.一般质疑2.支持与前提假设三、一般质疑1.无论据有结论2.有论据有结论四、支持、前提、解释1.支持方式2.前提假设3.解释说明一、数量论证 1.比例类论证 题目特征:题干的错误逻辑是用“…

MySQL系统性的学习--基础

学习资料是黑马的mysql课程 Mysql概述 相关概念 数据模型 关系型数据库 数据模型 SQL SQL通用语法 SQL分类 DDL 数据库操作 表操作 查询 创建 数据类型 修改/删除 DML 添加数据INSERT 修改数据UPDATE 删除数据DELETE DQL 基础查询 条件查询 聚合函数 分组查询 排序查询 分…

中国数据库的崛起:从本土化挑战到全球化机遇

引言 谈起中国的崛起&#xff0c;大家第一反应可能是“中国制造”“高铁奇迹”“电商帝国”&#xff0c;但今天我们要聊的&#xff0c;是一个比这些还要神秘的存在——中国的数据库技术。或许你平时并不会经常关注它&#xff0c;但这个隐身在你手机、电脑、服务器背后的无形力…

ubuntu20.04源码编译安装qemu(qemu8.2)

ubuntu20.04源码安装qemu8.2 本文用于记录在ubuntu20中源码编译安装qemu8.2&#xff0c;同时也希望能够对你有所帮助。 一、download qemu 根据自己的需求下载对应版本的qemu源码压缩包。 https://github.com/qemu/qemu/tags二、build qemu 解压缩后&#xff0c;执行下述命令。…

【vue运行报错】无法加载文件 D:\nodejs\node_global\webpack.ps1,因为在此系统上禁止运行脚本。

根据这篇博客安装nodejs和vue&#xff0c;执行webpack -v 和vue -v 报错。 Vue安装与配置教程&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了-CSDN博客 【解决方法】 &#xff08;1&#xff09;以管理员身份运行终端/命令提示符&#xff…