【Vue自学笔记】组件间数据传递

概念了解:值类型与引用类型

在vue中乃至很多门语言中,值类型与引用类型的概念是通用的。基本类型也称为值类型,字符串(Sring)、布尔值(Boolean)和数字(Number)这些都是基本类型(primitive type)。
非基本类型也可以理解为引用类型,数组(Array)和对象(Object)都属于引用类型(reference type)。
区别大致如下:

基本类型:
基本类型/值类型(primitive type / value type)的变量直接保存的就是数据。

引用类型:
引用类型(reference type)存放的值是指向数据的引用(reference),而不是数据本身。

Vue单向数据流特性

刚开始看这个名词,可能会认为是:数据只能够从父组件传到子组件,而不能从子组件传到父组件。其实这是不对的!
从父组件传到子组件很简单,可以通过参数传递对吧,但子组件传到父组件呢?其实是可以通过事件进行传递,或者通过数据绑定的方式,将数据传到父组件上。

那什么是单向数据流呢?引用自网上

Vue的单向数据流指的是,数据在父组件中被定义和更新,然后通过props的形式传递给子组件,子组件可以读取这些props,但不能直接修改它们。

概括:子组件只能读取父组件传来的数据,而不能修改,因为这些数据是read-only。父组件可以改,并且父组件改了之后所有子组件的这个值都会跟着改,单向传递。

为什么要有单向数据流机制

简单而言,就是为了保护数据。
如果父组件的数据在子组件中能够被更改,那子组件再传给子子组件,如果子子组件再做更改,那是不是每个拿到这个数据的组件都要去更新这个值呢…
这样下去会造成很多不必要的问题,如果出问题了调试也是很难调试出来的,为了便于结果预测以及提供更好的性能,Vue 就有了单向数据流机制。

实操比较

用上篇文章的代码来分析:

<script setup>
let {url} = defineProps({
  url: {
    required: true
  },
});
url+=' changed'
console.log(url)
</script>

控制台输出如下:
在这里插入图片描述
好像跟上面说的不太一样,可以修改啊?
其实不然,这涉及到解构赋值
let {url} = defineProps(...)这行代码其实等价于以下代码:

const props = defineProps({
  // ...
});
const url = props.url;

创建新变量: 解构赋值会创建一个新的变量 url,并将 defineProps 返回的对象中的 url 属性的值赋给这个新变量。

原来是这样~

那,我这样拿的数据总不能修改了吧:

let props = defineProps({
  url: {
    required: true
  },
});
props.url+=' changed'
console.log(props.url)

还真是,又学到一点东西了!
在这里插入图片描述

父组件数据更新

既然是单向传递,那父组件数据更新是不是就能直接影响子组件呢?试一下:
子组件新定义参数 a,数字类型,希望在父组件中点击一次图片 a 就加一,用 <span> 将值显示数来查看。代码如下:

// 子组件
<script setup>
let props = defineProps({
  url: {
    required: true
  },
  a:{
    type: Number
  }
});
</script>

<template>
  <img class="size" :src="url" :alt="url"/>
  <span>{{props.a}}</span>
</template>
// 父组件
<script setup>
<script setup>
import swpier from './components/swiper.vue'
import url from '@/assets/logo.svg'
let num = 1
function onClick(){
  num ++
  console.log('父组件:',num)
}
</script>

<template>
  <swpier :url="url" :a="num"></swpier>
  <button @click="onClick">click</button>
</template>

在页面中,尝试点击,父组件监听到的 num 是更新了,但是子组件里 a 的值没变!咋回事?
在这里插入图片描述

这是因为 a 只是个变量,但不是响应式对象
把在父组件中把 num 修改为响应式对象就行了!
父组件更新代码如下:

<script setup>
import swpier from './components/swiper.vue'
import url from '@/assets/logo.svg'
import {ref} from "vue";   // 在 vite 中使用这种方式引用静态资源
let num = ref(1)
function onClick(){
  num.value ++
  console.log('父组件:',num.value)
}
</script>

实操!
在这里插入图片描述
可以看到,子组件父组件的数据都实现了更新,完事!

引用数据类型修改

上面实验了基本数据类型,那引用数据类型呢?如果传递的是对象呢,子组件能否修改?
更新子组件代码,新增 obj 参数,接收对象,并尝试对 obj 对象进行修改:

<script setup>
let props = defineProps({
  url: {
    required: true
  },
  a:{
    type: Number
  },
  obj:{
    type: Object
  }
});
props.obj = {name:'new name'}
console.log(props.obj)
</script>

父组件传递参数,传入 obj对象,并带有一个属性 name

<swpier :url="url" :a="num" :obj="{name:'test'}"></swpier>

结果查看:
在这里插入图片描述
显然修改失败,这依旧符合单向数据传递原则。
那如果不是修改 obj,而是修改 obj 的属性呢?

子组件修改对象的代码改成如下:

props.obj.name = 'new name'
console.log(props.obj.name)

再看结果:
在这里插入图片描述
可以了?为什么?
这是因为直接修改 obj 是修改了 obj的指向,Vue 是监测到的,按照单向数据传递原则是不给的,保护数据!你修改了obj下的属性,obj还是同个对象,只不过里面的数据被你修改了,Vue 管不到,所以才能够修改。
但是,这并不意味着修改对象的属性这种行为是推荐的,还是按规范来,可以避免很多问题!

补充

响应式对象是用来做双向数据绑定的。基本数据类型用 ref()封装响应式对象,引用数据类型使用reactive()封装响应式对象!这个是 vue 的基础知识,可以去官方文档查看。

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js 2中,有几种常见的组件数据传递方式: 1. Props(属性传递):父组件可以通过在子组件上绑定属性,将数据传递给子组件。在子组件中,可以使用props属性来接收和使用这些数据。父组件可以通过v-bind指令绑定动态的值到子组件的props上。例如: ```html <!-- 父组件 --> <template> <div> <child-component :message="parentMessage"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { parentMessage: 'Hello from parent!' }; } }; </script> <!-- 子组件 --> <template> <div> <p>{{ message }}</p> </div> </template> <script> export default { props: ['message'] }; </script> ``` 2. 自定义事件:子组件可以通过$emit方法触发自定义事件,并将数据传递给父组件。父组件可以在子组件上使用v-on指令监听这些自定义事件,并在触发时执行相应的方法。例如: ```html <!-- 父组件 --> <template> <div> <child-component @custom-event="handleCustomEvent"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, methods: { handleCustomEvent(data) { console.log('Received data from child:', data); } } }; </script> <!-- 子组件 --> <template> <div> <button @click="emitCustomEvent">Send Event to Parent</button> </div> </template> <script> export default { methods: { emitCustomEvent() { const eventData = 'Data from child'; this.$emit('custom-event', eventData); } } }; </script> ``` 这些是Vue.js 2中常用的组件数据传递方式。除了上述方式之外,还可以使用Vuex进行状态管理,或者通过provide/inject在父子组件共享数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值