Vue3向全局广播数据变化

✅ 功能点

我们要做到:

  • 🧠 ruleForm 仍然是唯一状态源
  • 🔁 formDataToJson 自动跟随 ruleForm
  • ⚡ 子组件 直接拿"已处理好的 params"
  • 🚫 不在每个组件里重复写转换逻辑

一、升级 useFilterState(关键)

✅ 改造点:加入 params(computed)

useFilterState.ts

typescript 复制代码
import { reactive, provide, watch, computed } from "vue";
import { ElMessage } from "element-plus";

export const FILTER_KEY = Symbol("FILTER_STATE");

export function useFilterState() {
  const ruleForm = reactive({
    time_menu: "day",
    timeRange: [] as any[],
    service_info: [] as any[],
  });

  /** ✅ 派生:接口参数 */
  const params = computed(() => {
    if (ruleForm.time_menu === "custom") {
      if (ruleForm.timeRange.length === 2) {
        const [start_time, end_time] = ruleForm.timeRange;
        return {
          start_time,
          end_time,
          service_info: ruleForm.service_info,
          time_menu: ruleForm.time_menu,
        };
      }
      return null;
    }

    return {
      time_menu: ruleForm.time_menu,
      service_info: ruleForm.service_info,
    };
  });

  /** 可扩展的 change hook */
  const onChangeCbs: Function[] = [];

  watch(
    ruleForm,
    () => {
      onChangeCbs.forEach((cb) => cb(ruleForm));
    },
    { deep: true }
  );

  provide(FILTER_KEY, {
    ruleForm,
    params,
    onFilterChange: (cb: Function) => onChangeCbs.push(cb),
  });

  return {
    ruleForm,
    params,
  };
}

useFilterInject.ts

javascript 复制代码
import { inject } from "vue";
import { FILTER_KEY } from "./useFilterState";

export function useFilterInject() {
  const ctx = inject<any>(FILTER_KEY);
  if (!ctx) {
    throw new Error("useFilterInject 必须在 useFilterState 下使用");
  }
  return ctx;
}

二、页面中用法(更干净了)

xml 复制代码
<script setup lang="ts">
import { useFilterState } from "@/composables/useFilterState";

const { ruleForm, params } = useFilterState();
</script>

三、子组件中如何用(重点)

任意子组件

xml 复制代码
<script setup lang="ts">
import { watchEffect } from "vue";
import { useFilterInject } from "@/composables/useFilterInject";
import { getRiskInfo } from "@/api/visualizedOperations";

const { params } = useFilterInject();

async function fetchData() {
  if (!params.value) return; // custom 未选时间
  await getRiskInfo(params.value);
}

watchEffect(fetchData);
</script>

🎯 效果:

  • ruleForm 任意字段变化
  • params 自动重新计算
  • watchEffect 自动触发
  • 所有组件 同步刷新

四、如果你还想保留 ElMessage 提示

不要在 computed 里直接弹消息(副作用)

更优雅的方式是:提交或请求前校验

推荐写法

csharp 复制代码
function validateParams(params: any) {
  if (!params) {
    ElMessage.warning("请选择时间范围");
    return false;
  }
  return true;
}

使用时:

csharp 复制代码
if (!validateParams(params.value)) return;

五、为什么这是「最佳实践」

原来 现在
formDataToJson scattered 单一来源
子组件 自己拼参数 直接用
维护成本
复用
状态一致性 易乱

六、结构总结(你现在的架构)

scss 复制代码
页面
 ├─ useFilterState()
 │   ├─ ruleForm   ✅ 原始状态
 │   ├─ params     ✅ 派生参数
 │
 ├─ AlarmView
 │   └─ watchEffect(params) → 请求
 │
 └─ DataView
     └─ watchEffect(params) → 请求

七、一句话记住这个模式

状态在 ruleForm,逻辑在 computed,请求在组件

这套模式特别适合:

  • 可视化运营页面
  • 多组件联动筛选
  • 不想上 Pinia / URL

相关推荐
AALoveTouch18 分钟前
大麦网协议分析
javascript·python
●VON27 分钟前
React Native for OpenHarmony:2048 小游戏的开发与跨平台适配实践
javascript·学习·react native·react.js·von
晚烛2 小时前
CANN + 物理信息神经网络(PINNs):求解偏微分方程的新范式
javascript·人工智能·flutter·html·零售
小迷糊的学习记录3 小时前
0.1 + 0.2 不等于 0.3
前端·javascript·面试
空&白4 小时前
vue暗黑模式
javascript·vue.js
VT.馒头4 小时前
【力扣】2695. 包装数组
前端·javascript·算法·leetcode·职场和发展·typescript
css趣多多4 小时前
一个UI内置组件el-scrollbar
前端·javascript·vue.js
-凌凌漆-5 小时前
【vue】pinia中的值使用 v-model绑定出现[object Object]
javascript·vue.js·ecmascript
大橙子额7 小时前
【解决报错】Cannot assign to read only property ‘exports‘ of object ‘#<Object>‘
前端·javascript·vue.js
WooaiJava8 小时前
AI 智能助手项目面试技术要点总结(前端部分)
javascript·大模型·html5