一、父子组件数据传递
在Vue.js中实现 zPlanId 的传递和监听需要通过父子组件通信机制来完成。
完整工作流程
- 初始化阶段 :父组件将初始的 zPlanId (如'123,true')传递给子组件
- 监听触发 :子组件的watch监听器检测到 zPlanId 的变化并执行处理函数
- 数据解析 :子组件解析 zPlanId ,提取计划ID和刷新标志
- 数据加载 :如果刷新标志为'true',子组件调用API获取相关数据并更新界面
- 更新传递 :当父组件需要更新子组件数据时,修改 zPlanId 的值,触发子组件重新加载数据
步骤1: 子组件定义props接收zPlanId
首先在子组件(child.vue)中定义props来接收父组件传递的 zPlanId :
javascript
// 在child.vue组件中的<script>部分
export default {
name: 'child',
props: {
zPlanId: ''
},
data() {
return {
// 组件其他数据
planId: '',
// ...其他数据
};
},
// ...其他组件选项
};
步骤2: 子组件添加watch监听器
在子组件中添加watch选项来监听 zPlanId 的变化:
javascript
watch: {
zPlanId(val) {
// 解析传入的值,第一部分作为计划ID
this.planId = val.split(',')[0]
// 如果第二部分为'true',则执行数据初始化
if (val.split(',')[1] == 'true') {
this.filter();
}
}
},
步骤3: 父组件向子组件传递zPlanId
在父组件中,通过属性绑定的方式将数据传递给子组件:
javascript
<!-- 父组件的模板中 -->
<template>
<div class="parent-component">
<!-- 通过属性绑定传递zPlanId -->
<!-- 格式为:计划ID,刷新标志 -->
<child :z-plan-id="selectedPlanId + ',' + needRefresh"></child>
<!-- <child :z-plan-id="selectedPlanId + ',' + needRefresh"></child>-->
</div>
</template>
<script>
import child from './child.vue';
export default {
components: {
child
},
data() {
return {
selectedPlanId: '123', // 当前选中的计划ID
needRefresh: 'true' // 是否需要刷新数据的标志
};
}
};
</script>
步骤4: 父组件更新zPlanId触发监听
当父组件需要更新子组件的数据时,只需要修改 selectedPlanId 或 needRefresh 的值即可:
javascript
// 父组件中的方法,用于切换评估计划
changePlan(newPlanId) {
// 更新选中的计划ID,并设置刷新标志为true
this.selectedPlanId = newPlanId;
this.needRefresh = 'true';
// 注意:为了确保Vue能够检测到变化并触发子组件的watch
// 如果只是改变needRefresh的值,需要确保它的变化能被Vue的响应式系统捕获
// 可以使用this.$set或通过一个临时变量中转
}
要点说明
- props命名规则 :在父组件模板中, z-plan-id 是 zPlanId 的kebab-case形式,Vue会自动进行转换
- 复合数据传递 :使用逗号分隔的字符串传递多个数据项是一种简单的方式,也可以考虑使用对象或数组传递更复杂的数据
依据上面的例子,当父组件需要更新子组件的 zPlanId 时,如果只是简单地修改 needRefresh 标志(特别是当它是对象的属性时),可能不会被Vue的响应式系统检测到。这时就需要使用 this.$set 或临时变量中转的方法来确保变化被检测到,从而触发子组件的watch监听器。
如果needRefresh是某个对象的属性
在上面的例子中,"为了确保Vue能够检测到变化并触发子组件的watch",就是指在某些情况下直接修改数据可能不会被Vue的响应式系统捕获。
方法1: 使用this.$set
this.$set 是Vue实例提供的一个方法,用于向响应式对象添加新属性,并确保这个新属性也是响应式的,同时触发视图更新。
语法 : this.$set(target, propertyName/index, value)
javascript
// 在父组件中
changePlan(newPlanId) {
// 直接修改简单数据类型通常不需要$set
this.selectedPlanId = newPlanId;
// 如果needRefresh是某个对象的属性,直接修改可能不会触发响应式更新
// 这时可以使用this.$set
this.$set(this.someObject, 'needRefresh', 'true');
}
方法2: 通过临时变量中转
对于数组或复杂对象的修改,可以先创建一个临时副本,修改后再重新赋值给原变量,这样Vue就能检测到变化。
示例1: 数组修改
javascript
// 直接修改数组索引可能不会触发响应式更新
this.myArray[index] = newValue; // 可能无效
// 使用临时变量中转
const tempArray = [...this.myArray]; // 创建副本
tempArray[index] = newValue; // 修改副本
this.myArray = tempArray; // 重新赋值,触发更新
示例2: 复杂对象修改
javascript
// 在父组件中,针对zPlanId的场景
changePlan(newPlanId) {
this.selectedPlanId = newPlanId;
// 方法1: 使用临时变量重新构建zPlanId字符串
const newZPlanId = newPlanId + ',' + 'true';
this.zPlanId = newZPlanId; // 重新赋值,确保触发更新
// 方法2: 如果zPlanId是对象的属性
const tempObj = {...this.planData};
tempObj.zPlanId = newPlanId + ',' + 'true';
this.planData = tempObj;
}
二、watch两种主要写法
在Vue组件中, watch 选项用于监听数据变化并执行自定义的处理函数。它有两种主要写法:
监听levelId: { handler(newVal, oldVal) {...}
(1)简写形式 :直接指定处理函数
javascript
watch: {
zPlanId(val) {
// 解析传入的值,第一部分作为计划ID
this.planId = val.split(',')[0]
// 如果第二部分为'true',则执行数据初始化
if (val.split(',')[1] == 'true') {
this.filter();
}
},
levelId: function(newVal, oldVal) {
// 处理逻辑
}
}
(2)对象形式 :使用 handler 属性指定处理函数
还可以添加其他配置选项
javascript
watch: {
zPlanId(val) {
// 解析传入的值,第一部分作为计划ID
this.planId = val.split(',')[0]
// 如果第二部分为'true',则执行数据初始化
if (val.split(',')[1] == 'true') {
this.filter();
}
},
levelId: {
handler(newVal, oldVal) {
// 处理逻辑
},
// 可选配置项
deep: true, // 是否深度监听
immediate: true // 是否在初始化时立即执行一次
}
}
handler函数的作用
(1)handler 函数是对象形式监听器的核心,当被监听的数据发生变化时,Vue会自动调用这个函数:
- newVal :变化后的新值
- oldVal :变化前的旧值
(2)在代码中, handler 函数根据 levelId 的不同值执行不同的操作:
- 当 levelId 变为1时,清空上级指标ID和可选列表
- 当 levelId 变为2时,加载一级指标数据
- 当 levelId 变为3时,加载二级指标数据
其他可选配置项
除了 handler ,对象形式的监听器还支持其他配置选项:
(1)deep :布尔值,默认false
- 设置为true时,会深度监听对象内部值的变化
- 用于监听复杂数据类型(如对象、数组)的内部变化
javascript
watch: {
complexObject: {
handler(newVal, oldVal) {
// 处理逻辑
},
deep: true
}
}
(2) mmediate :布尔值,默认false
- 设置为true时,监听器会在组件初始化时立即执行一次handler函数
- 不设置时,只有在数据发生变化时才会执行
javascript
watch: {
someData: {
handler(newVal) {
// 处理逻辑
},
immediate: true
}
}
使用对象形式而非简写形式的主要原因是:
- 需要深度监听 :当监听对象或数组内部变化时
- 需要立即执行 :希望监听器在组件初始化时就执行一次
- 代码组织更清晰 :对于复杂的监听逻辑,使用对象形式可以更好地组织代码和配置