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

相关推荐
Penge66615 小时前
《Go 后端开发者学 TypeScript:数组和元组》
javascript
Penge66616 小时前
《Go 后端开发者学 TypeScript:export关键字大全》
javascript
Penge66616 小时前
《Go 后端开发者学 TypeScript:从零理解 async、await 与 Promise》
javascript
Penge66616 小时前
typescript 中const用法
javascript
usdoc文档预览1 天前
USDOC系列之PPT文件在线编辑-VUE前端实现在线浏览器在线编辑PPT文档
前端·vue.js·编辑器·office365·ppt在线编辑·office文件在线编辑·文件在线编辑
Java小卷1 天前
面向 schema 编程,轻松搞定 Element 虚拟化表格复杂应用场景
vue.js·低代码·element
仨孩子的爹1 天前
Lodop、hiprint 与 vue-print-designer:打印控件选型对比
vue.js
程序员大阳1 天前
HTML+CSS+JS对话式实战(3)-活动管理页实现查询、新增、删除API后端接口
javascript·css·html·实战·删除·查询·新增
炫酷的大高个1 天前
6 亿播放的闪身步,我用前端算出 15 倍重心差
前端·javascript
林小帅1 天前
【笔记】Prisma v7 + SQLite TS2305 及连锁 TS7006 问题
前端·javascript·后端