当前位置: 首页 > news >正文

vue 组件之间传递参数

1. props 父向子传递

1. 父组件发送数据

<!-- 父组件 -->
<template>
  <div>
    <child-component :message="parentMessage"></child-component>
  </div>
</template>
 
<script>
import ChildComponent from './ChildComponent.vue';
 
export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: '这是来自父组件的消息'
    };
  }
};
</script>

2. 子组件用 props 属性接收数据

<!-- 子组件 -->
<template>
  <div>{{ message }}</div>
</template>
 
<script>
export default {
  props: ['message']
};
</script>

props 接收可以校验。类型校验、非空校验、默认值、自定义校验

props: {
    校验的属性名: {

        type: 类型,   // String , Number, Boolean
        required: true,  // 是否必填
        default: 默认值,  //默认值
        validator (value) {
            // 自定义校验逻辑
            return 是否通过校验
        }
    }
}

2. $emit 子向父传递

子组件可以通过emit方法触发一个自定义事件,并将数据传递给父组件。父组件可以通过在子组件标签上监听这个自定义事件来接收数据。

1. 子组件通过 $emit 定义触发事件,并传递数据

<!-- 子组件 -->
<template>
  <button @click="sendMessage">发送消息给父组件</button>
</template>
 
<script>
export default {
  methods: {
    sendMessage() {
      this.$emit('childMessage', '这是来自子组件的消息'); // $emit(事件名, 消息数据)
    }
  }
};
</script>

2. 父组件通过监听子组件事件名监听该事件,并定义方法接收数据

<!-- 父组件 -->
<template>
  <div>
    <!-- @子组件事件名="父组件定义的方法名" -->
    <child-component @childMessage="handleChildMessage"></child-component>
  </div>
</template>
 
<script>
import ChildComponent from './ChildComponent.vue';
 
export default {
  components: {
    ChildComponent
  },
  methods: {
    handleChildMessage(message) {
      console.log(message);
    }
  }
};
</script>

3. Vuex

通过在Vuex中定义全局的状态,并在组件中使用getter和mutation来访问和修改状态,实现多组件之间数据通信。

1. 安装Vuex并创建store 仓库

现在默认是vue3版本的,如果是vue2 项目要指定下载3版本

npm i Vuex@3

2. 在store中定义状态、mutation、action等。

<!-- Vuex Store(store.js) -->
import Vue from 'vue';
import Vuex from 'vuex';
 
Vue.use(Vuex);
 
export default new Vuex.Store({
  state: {
    counter: 0
  },
  mutations: {
    increment(state) {
      state.counter++;
    }
  }
});

3. 在组件中通过this.$store访问store,并使用getter获取状态,使用mutation或action修改状态。

父组件


<!-- 父组件(Parent.vue) -->
<template>
  <div>
    <h1>父组件</h1>
    <ChildComponent />
  </div>
</template>
 
<script>
import { mapState, mapMutations } from 'vuex';
import ChildComponent from './ChildComponent.vue';
export default {
  components: { ChildComponent },
  computed: {
    ...mapState(['counter'])
  },
  methods: {
    ...mapMutations(['increment'])
  }
};
</script>

子组件

<!-- 子组件(ChildComponent.vue) -->
<template>
  <div>
    <h2>子组件</h2>
    <p>计数器:{{ counter }}</p>
    <button @click="increment">增加</button>
  </div>
</template>
 
<script>
import { mapState, mapMutations } from 'vuex';
export default {
  computed: {
    ...mapState(['counter'])
  },
  methods: {
    ...mapMutations(['increment'])
  }
};
</script>

4. 插槽

通过插槽,父组件可以将自己的模板内容传递给子组件,并在子组件的指定位置渲染出来。

1. 在子组件中定义插槽

2. 父组件使用子组件时,通过插槽向子组件传递数据

方式一:默认插槽

默认插槽是最基本的插槽类型,用于在组件内传递和显示任意内容。如果没有给插槽命名,Vue会将内容传递到默认插槽中。

//子组件
<template>
  <div class="my-component">
    <slot></slot> <!-- 默认插槽 -->
  </div>
</template>
//父组件
<template>
  <MyComponent>
    <p>This is some default slot content!</p>
  </MyComponent>
</template>

方式二:具名插槽

具名插槽允许我们在组件中定义多个插槽,每个插槽都有一个唯一的名称。这样可以在组件中更精确地控制内容的显示位置。 

 子组件

//子组件(MyComponent.vue)
<template>
  <div class="my-component">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot> <!-- 默认插槽 -->
    </main>
    <footer>
      <slot name="footer"></slot><!--具名插槽-->
    </footer>
  </div>
</template>

父组件

//父组件
<template>
  <MyComponent>
    <template v-slot:header>
      <h1>Header Content</h1>
    </template>
    <p>This is some default slot content!</p>
    <template v-slot:footer>
      <p>Footer Content</p>
    </template>
  </MyComponent>
</template>

在这个例子中,<h1>Header Content</h1>将会显示在<slot name="header"></slot>位置,<p>Footer Content</p>将会显示在<slot name="footer"></slot>位置,而默认插槽中的内容仍会显示在<slot></slot>位置。

方式三:作用域插槽

作用域插槽是一种特殊类型的插槽,允许我们在父组件中访问子组件的数据。这在需要动态渲染内容时特别有用。在插槽中,是使用插槽的地方传递数据到定义的插槽中,但在作用域插槽中,有种逆流而上的感觉,数据是定义的插槽返回给插槽的使用者的。

子组件存放一个带数据的插槽

<template>
  <div class="child">

    <h3>这里是子组件</h3>
    <slot  :data="nameList"></slot>
  </div>
</template>

 export default {
    data: function(){
      return {
        nameList: ['张三','李四','王五','赵六']
      }
    }
}

父组件通过 “slot-scope” 来接收子组件传过来的插槽数据,再根据插槽数据来填充插槽的内容

<template>
  <div class="father">
    <h3>这里是父组件</h3>
    <!--第一次使用:用flex展示数据:  class="tmpl"-->
    <child>
      <template slot-scope="userInfo">
        <div class="tmpl">
          <span v-for="item in userInfo.nameList">{
  
  {item}}</span>
        </div>
      </template>

    </child>

    <!--第二次使用:用列表展示数据-->
    <child>
      <template slot-scope="userInfo">
        <ul>
          <li v-for="item in userInfo.nameList">{
  
  {item}}</li>
        </ul>
      </template>

    </child>

    <!--第三次使用:直接显示数据-->
    <child>
      <template slot-scope="userInfo">
       {
  
  {userInfo.nameList}}
      </template>

    </child>

    <!--第四次使用:不使用其提供的数据, 作用域插槽退变成匿名插槽-->
    <child>
      我就是模板
    </child>
  </div>
</template>

总结 

父组件

  • 默认插槽的话直接在子组件的标签内写入内容即可
  • 具名插槽是在默认插槽的基础上加上slot属性,值为子组件插槽name属性值
  • 作用域插槽则是通过slot-scope获取子组件的信息,在内容中使用。这里可以用解构语法去直接获取想要的属性

子组件

  • 插槽用 <slot> 标签来确定渲染的位置,里面放如果父组件没传内容时的后备内容
  • 具名插槽name属性来表示插槽的名字,不传为默认插槽
  • 作用域插槽在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件slot-scope接收的对象上

 

5. 事件总线

兄弟组件传递数据,事件总线提供了$emit$on$off方法,分别用于触发事件、监听事件和移除事件监听。

  • $emit:用于触发事件,并传递相关数据。
  • $on:用于监听事件,并定义事件触发时的回调函数。
  • $off:用于移除事件监听,防止内存泄漏。

使用步骤

1. 创建事件总线:单独的.js文件中创建一个新的Vue实例,并将其导出为事件总线。或者,在Vue项目的入口文件(如main.js)中,将事件总线挂载到Vue的原型上,使其成为全局可用的。

import Vue from 'vue';
export const EventBus = new Vue();

2. 引入事件总线:使用import语句将事件总线引入到你需要使用它的组件中。

<template>
  <button @click="sendMessage">Send Message to ComponentB</button>
</template>
 
<script>
import { EventBus } from '../event-bus.js';
 
export default {
  methods: {
    sendMessage() {
      EventBus.$emit('message-from-a', 'Hello from Component A!');
    }
  }
};
</script>

3. 监听和触发事件: $emit() 触发并传送数据,$on() 监听并接收数据

4. 解绑事件:$off() 解绑,防止内存泄漏

<template>
  <div>
    <p>Message from ComponentA: {{ message }}</p>
  </div>
</template>
 
<script>
import { EventBus } from '../event-bus.js';
 
export default {
  data() {
    return {
      message: ''
    };
  },
  created() {
    EventBus.$on('message-from-a', (msg) => {
      this.message = msg;
    });
  },
  beforeDestroy() {
    EventBus.$off('message-from-a');
  }
};
</script>

6.  provide 和 inject

适用于祖先向子孙传递数据。祖先组件通过 provide 提供数据,子孙组件用 jnject 接收数据。provide \ inject 主要解决了跨级组件之间通信问题。

祖先组件

// 祖先组件
export default {
    provide: {
        name:'张三'
    }
}

子孙组件

// 子孙组件
export default {
    inject: ['name'],
    mounted () {
    console.log(this.name); // 张三
    }
}

值得一提的是,provide 和 inject 并不是响应式的。也就是说,如果祖先组件数据发生了变化,比如数据由张三变成里李四,那么在子孙组件中的数据不会改变,依然是张三。

如果将其变成响应式数据呢?需要使用 Vue.observable

祖先组件

<div>
    A组件
    <button @click="() => changeColor()">改变color</button>
    <ChildrenB />
    <ChildrenC />
</div>

// 使用 2.6 最新 API Vue.observable 优化响应式 provide
provide() {
    this.theme = Vue.observable({
        color: 'blue'
    });
    return {
        theme: this.theme
    }
},
methods: {
    channgeColor(color) {
        if(color) {
            this.theme.color = color;
        } else {
            this.theme.color = this.theme.color === 'blur' ? 'red' : 'blur'
        }
    }
}

 子孙组件

<template functional>
    <div class="border2">
        <h3 id="h3" :style="{ color: this.theme.color }">F 组件</h3>
    </div>
</template>

<script>
export default {
    inject: ["theme"]
}

7. attrs 和 listeners

$attrs是一个对象,它包含了父作用域中没有被prop接收的所有属性(不包含class和style属性)。可以通过v-bind="$attrs"直接将这些属性传入内部组件,实现父组件隔代向孙组件传值。

父组件将nameage属性传递给子组件,子组件通过v-bind="$attrs"将这些属性(以及可能的其他未声明的属性)传递给孙组件。孙组件通过props接收这些属性。

<!-- 父组件(Parent.vue) -->
<template>
  <div>
    <h1>父组件</h1>
    <ChildComponent :name="parentName" :age="parentAge" />
  </div>
</template>
 
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: { ChildComponent },
  data() {
    return {
      parentName: 'Tom',
      parentAge: 30
    };
  }
};
</script>
 
<!-- 子组件(ChildComponent.vue) -->
<template>
  <div>
    <h2>子组件</h2>
    <GrandChildComponent v-bind="$attrs" />
  </div>
</template>
 
<script>
import GrandChildComponent from './GrandChildComponent.vue';
export default {
  components: { GrandChildComponent }
};
</script>
 
<!-- 孙组件(GrandChildComponent.vue) -->
<template>
  <div>
    <h3>孙组件</h3>
    <p>父组件传递的名字:{{ name }}</p>
    <p>父组件传递的年龄:{{ age }}</p>
  </div>
</template>
 
<script>
export default {
  props: ['name', 'age']
};
</script>

$listeners是一个对象,它包含了父组件中所有的v-on事件监听器(不包含.native修饰器的)。可以通过v-on="$listeners"将这些事件监听器传入内部组件,实现孙组件隔代向父组件传值。

如果孙组件需要向父组件发送事件,可以通过$emit触发事件,并在子组件中使用v-on="$listeners"将这些事件传递给父组件。然而,需要注意的是,$listeners通常用于孙组件向隔代的父组件发送事件,而不是直接用于父子组件间的通信。在实际应用中,父子组件间的通信更多地使用$emit和v-on。

相关文章:

  • 齐次线性方程组及python求解
  • 主成分分析(PCA)学习介绍及其高阶应用,金融风险分析
  • Sentinel实战(二)、流控规则之流控阈值类型、流控模式
  • 重建二叉树(C++)
  • Pycharm(八):字符串切片
  • python数据结构——基础、顺序表
  • UE5学习笔记 FPS游戏制作34 触发器切换关卡
  • js坐标的相关属性
  • 表格数据导出为Excel
  • 将 PyTorch Model 用可视化方法浏览 torchview,onxx, netron, summary | 撰写论文 paper
  • 漏洞预警 | Windows 文件资源管理器欺骗漏洞(CVE-2025-24071、CVE-2025-24054)
  • 《SRv6 网络编程:开启IP网络新时代》第2章、第3章:SRv6基本原理和基础协议
  • mybatis里in关键字拼接id问题
  • Java 时间处理:轻松掌握 java.time 包
  • 05-031-自考数据结构(20331)- 哈希表 - 例题分析
  • UE5学习记录part12
  • WebForms 事件
  • stm32第十天外部中断和NVIC讲解
  • 力扣刷题——排序链表
  • Lua语言脚本环境配置
  • c2c代表性企业网站/如何优化关键词的方法
  • 利用小说网站做本站优化/seo排名赚app靠谱吗
  • 石家庄哪里有做外贸网站的公司/企业网站seo优化
  • vs2015网站开发/大片网站推广
  • 企业网站建设应该注意什么事项问题/品牌宣传策略
  • 网站流量统计实现/微信上如何投放广告