欢迎大家来到IT世界,在知识的湖畔探索吧!
前言
先直入主题列出有哪些传参方式,下面再通过事例一一讲解。
props(父传子)
$emit与v-on (子传父)
EventBus (兄弟传参)
.sync与update: (父子双向)
v-model (父子双向)
ref
$children与$parent
$attrs与$listeners (爷孙双向)
provide与inject (多层传参)
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>
欢迎大家来到IT世界,在知识的湖畔探索吧!
子组件代码: 用props接收消息后可以直接使用,如下第3行和第16行中直接使用
注意: props有两种接收方法,如下第9行注释的就是简写用法,此用法不能设置默认值。
欢迎大家来到IT世界,在知识的湖畔探索吧!<template> <div> <p>接收到的消息: {{ message }}</p> </div> </template> <script> export default { //props:['message'], props: { message: { type: String, default: '', // 这里能设置默认值,如果父组件没有传参,默认值会生效 }, }, mounted() { console.log(this.message); }, }; </script>
注意: 此传参方式是单向的,即子组件接收到父组件的数据后,是不能直接修改props接收的数据,否则会直接报错。
二、$emit与v-on(子传父)
思路简述: 子组件通过$emit触发父组件的指定方法并且在此方法中携带任意参数,父组件通过在被触发的方法中拿到携带的参数完成子传父。
语法:$emit(方法名,参数)
子组件代码:核心代码在第11行,触发方法并且携带参数。
<template> <div> <button @click="sendParent">点击发送数据给父组件</button> </div> </template> <script> export default { methods: { sendParent() { this.$emit('my-event', '这是传递的参数'); }, }, }; </script>
父组件代码:核心代码在第3行触发事件,获取到子组件的传参。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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.js或main.ts)创建全局事件Bus并且挂载在Vue.prototype*
import Vue from 'vue'; const Bus = new Vue(); Vue.prototype.$Bus = Bus;
兄弟组件A代码:通过this.$Bus.$emit(方法名,参数)发送参数。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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(可以自由命名)
欢迎大家来到IT世界,在知识的湖畔探索吧!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销毁事件监听。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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>
四、.sync与update:(父子双向)
思路简述:.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同步修改父组件内容。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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同步修改父组件的值
欢迎大家来到IT世界,在知识的湖畔探索吧!<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>
子组件代码:
欢迎大家来到IT世界,在知识的湖畔探索吧!<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>
子组件代码: 类似地,父组件也是同样用法,但区别是返回的不是数组而且一个对象,能直接使用。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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之外属性。
欢迎大家来到IT世界,在知识的湖畔探索吧!<Parent v-bind="$attrs"></Parent>
(3)孙组件代码:类似父传子,正常用popos接收爷组件传过来的参数。
<template> <div> 爷组件传来的:{{ name }} </div> </template> <script> export default { props: { name: { default: String, }, }, }; </script>
$listeners使用流程代码:
(1)孙组件代码 直接this.$emit类似子传父
欢迎大家来到IT世界,在知识的湖畔探索吧!<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事件接收到参数。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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>
这里感觉算两种(爷传孙与孙传爷)传参方式了,但由于都是类似中转站效果,所以放一起说比较好理解。
九、provide与inject(多层传参)
简述: provide与inject无论多少层组件都能传参。顶层组件通过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行的用法,通过顶层给到的方法传参给顶层组件。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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挂载即可
欢迎大家来到IT世界,在知识的湖畔探索吧!Vue.prototype.$testMethod = function(val) { console.log(val); };
调用:直接在任何页面用this调用
this.$appName; this.$testMethod('参数');
十二、浏览器缓存
简述: localStorage 和sessionStorage:主要是浏览器用来持久化存储的,这算是用的不多,但也是必用的一种通信方式。两者区别如下
sessionStorage(临时存储):最大空间5M,为每一个数据源维持一个存储区域,但只在浏览器打开期间存在,关闭后数据会不会消失,包括页面重新加载。
localStorage(长期存储):最大空间5M,与 sessionStorage 一样,但是哪怕浏览器关闭后,数据依然会一直存在,除非手动删除。
具体用法如下所示:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 存储 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 = '天天鸭'
使用:
欢迎大家来到IT世界,在知识的湖畔探索吧!console.log( window.Obj); console.log( window.name);
十四、路由
简述: Vue在路由跳转时携带参数其实也很常用的方式,下面汇总一下三种路由传参。
(1)通过 params 传参 跳转页面用法:
this.$router.push({name:"index", params:{id}})
目标页面接收参数:
欢迎大家来到IT世界,在知识的湖畔探索吧!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)
目标页面接收参数:
欢迎大家来到IT世界,在知识的湖畔探索吧!this.$route.query.id
(3)通过动态路由传参
注意: 如果用动态路由传参需要对路由进行配置;并且参数会在 url 中显示。 如下所示,在path后面要配置:name/:age.
{ path: '/about/:name/:age' , name: 'About', component() => import('@/views/About.vue') }
跳转页面用法:
欢迎大家来到IT世界,在知识的湖畔探索吧!this.$router.push('/about/'+obj.name+'/'+obj.age)
目标页面接收参数:
this.$route.params
十五、$root(顶层)
简述: 可以通过 $root 访问到整个 Vue 树的根实例,也就是可以使用 $root 来访问全局的属性或者修改全局的属性。
示例:在main.js文件中定义一个globalName属性,可以全局使用。
欢迎大家来到IT世界,在知识的湖畔探索吧!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的插槽。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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名称。
欢迎大家来到IT世界,在知识的湖畔探索吧!<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>
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/132412.html