You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3中复杂嵌套对象的响应式管理方案咨询

大型Vue3+Google Maps应用的响应式管理问题

项目背景

  • 基于Vue3组合式API、TypeScript、Pinia开发大型Web应用,深度集成Google Maps
  • UI仅包含少量按钮、滑块、开关,以及展示状态属性的表格
  • 采用状态模式,Pinia中存储单个Context类实例,用于管理应用不同状态与Google Maps相关元素(覆盖层、Marker、Polyline等)
  • Context内置复杂网络系统(节点、路径等),嵌套层级较深(例如context.network.lanes[].setpoints[].marker),Context类及关联自定义模块共约20个,代码量达数千行

核心响应式需求

实现表格展示选中Setpoint的坐标、类型、标签等属性(对应context.network.selected_lane.selected_setpoint),并在用户切换选中的Setpoint或Lane时自动更新表格内容

当前遇到的问题

  • Google Maps标记在响应式地图中重复渲染
  • 本地Point实例与响应式属性中的同一实例做全等判断时返回false
  • DOM元素未随响应式值变化自动更新

已尝试方案的痛点

全量响应式(使用reactive)

  • 增加不必要的性能开销
  • 第三方对象必须显式调用markRaw处理,繁琐易漏
  • 响应式实例内新创建的对象默认不具备响应式,调试排查困难

选择性响应式(使用shallowReactive)

  • 难以清晰区分哪些对象是响应式的,代码维护易出错
  • Vue官方不推荐此用法,存在潜在风险

完全弃用Vue响应式系统

  • 需手动处理DOM与数据的双向同步,开发效率大幅降低

理想诉求

自定义模块中无需导入Vue相关库,保持业务逻辑与框架解耦

代码结构概览

// Pinia store
export const useContextStore = defineStore('context', {
    state: () => {
        return { context: reactive(new Context()) }
    },
    getters: {
        state_label: (state) => state.context.state.constructor.name,
        node_selected: (state) => state.context.network?.selected_node ? "selected" : "",
        lane_selected: (state) => state.context.network?.selected_lane ? "selected" : "",
    },
    actions: {
        set_map(map: google.maps.Map): void { this.context.set_map(map); },
        keypress_delete(): void { this.context.keypress_delete(); },
        node_on_click_callback(node: network.NetworkNode): void { this.context.node_on_click_callback(node); },
        // More user actions including keypresses, mouse-clicks, etc.
    }
});

// Context class
export class Context implements ContextInterface
{
    state: State;
    map_manager: MapManager;
    network: network.Network | null;
    draft_straight: network.DraftStraight | null;

    constructor()
    {
        this.state = new StateDefault(this);
        this.map_manager = shallowReactive(new MapManager());
        this.network = null;
        this.draft_straight = null;
    }

    public transition(next_state: State): void
    {
        this.state!.on_exit();
        this.state = next_state;
        this.state.on_entry();
    }

    public set_map(map: google.maps.Map): void { this.state.set_map(map); }
    public keypress_delete(): void { this.state!.keypress_delete(); }
    public node_on_click_callback(node: network.NetworkNode): void { this.state!.node_on_click_callback(node); }
    // More user actions including keypresses, mouse-clicks, etc.
}

// Default state. One of multiple concrete states.
export class StateDefault extends State
{
    on_entry(): void { /* ... */ }
    on_exit(): void { /* ... */ }

    set_map(map: google.maps.Map): void { this.context.map_manager.set_map(map); }
    keypress_delete(): void { console.log("Can't delete, nothing selected"); }

    node_on_click_callback(node: network.NetworkNode): void
    {
        this.context.network!.select_node(node);
        this.context.transition(new StateNodeSelected(this.context));
    }

    // More implementations for the user actions in this state.
}

// Network module
export namespace network
{
    export class DraftStraight
    {
        private network_ref: Network;
        private setpoints: math.Point[];
        // Many more properties.

        // Google maps 3rd party library properties.
        private map: google.maps.Map;
        private markers: visualize.Marker[];
        private polyline: visualize.Polyline | null;
        
        // Constructor and methods.
    }

    export class NetworkNode
    {
        network_ref: Network;
        position: math.Point;
        source_lanes: NetworkLane[];
        target_lanes: NetworkLane[];

        // Google maps 3rd party library properties.
        map: google.maps.Map;
        marker: visualize.Marker;

        // Constructor and methods.
    }

    // More similar classes: NetworkLane, Straight, Intersection, Roundabout.

    export class Network
    {
        origin: math.geo.Geodetic;
        nodes: NetworkNode[];
        straights: Straight[];
        intersections: Intersection[];
        roundabouts: Roundabout[];
        selected_node: NetworkNode | null;
        selected_lane: NetworkLane | null;

        map: google.maps.Map;
        origin_marker: visualize.Marker;

        // Constructor and methods.

        public select_node(node: NetworkNode): void
        {
            this.selected_node?.remove_highlight();
            this.selected_node = node;
            this.selected_node.add_highlight();
            // ...
        }

        // More methods.
    }
}

内容的提问来源于stack exchange,提问作者borndeprecated

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:41:00