微信扫码
添加专属顾问
我要投稿
AI时代前端开发新范式:从代码复用转向规范复用,让AI按需生成定制化组件,告别复杂维护难题。 核心内容: 1. 传统前端组件复用面临的三大困境:逻辑复杂、维护成本高、生命周期短 2. AI驱动的规范复用新模式:通过标准化文档指导AI生成场景化专用组件 3. 实践案例展示:以Bottom组件为例的AI协同开发全流程
前端组件复用的现状与挑战
基于规范驱动的AI协同开发模式
# Bottom组件开发规范## 概述本文档规范了IP互动项目中Bottom组件的设计模式、实现方式和最佳实践。Bottom组件作为主舞台的底部操作区域,承载着核心功能入口、积分显示、主要交互等关键作用,是用户参与游戏的主要接触点。## 设计原则### 1. 功能聚焦- 承载项目的核心操作功能(如抽奖、开盒、任务等)- 提供重要信息展示(如积分、奖励状态等)- 确保主要功能的易访问性和可见性### 2. 布局一致性- 遵循固定的底部位置布局模式- 🎯 **主操作按钮必须始终绝对居中**,不受左右功能区域内容变化影响- 保持合理的元素间距和视觉层级- 适配不同屏幕尺寸和安全区域### 3. 交互友好- 提供清晰的按钮状态反馈- 支持动画效果和视觉引导- 合理处理加载和禁用状态## 组件结构### 基础布局模式Bottom组件通常采用以下基础布局结构:```tsxinterface BottomProps { className?: string; mainStore: MainStore; // 核心功能回调 onMainActionBtnClick?: () => Promise<boolean>; onMainActionBtnSuccess?: (ret: any) => Promise<void>; onMainActionBtnError?: (error: any) => Promise<void>; // 状态控制 isProcessingLockRef?: React.MutableRefObject<boolean>; loading?: boolean; // 功能开关 showPointDisplay?: boolean; showLotteryTrigger?: boolean; showTaskTrigger?: boolean; // 动画控制 palyBoxOpenTriggerClickAnimation?: boolean; showActionMotivateTipsBubble?: boolean;}export function Bottom(props: BottomProps) { return ( <div className={`w-full absolute bottom-8 ${props.className}`}> {/* 积分显示区域 - 居中上部 */} {props.showPointDisplay && ( <div className="w-full flex justify-center mb-4"> {/* 积分显示组件 */} </div> )} {/* 功能按钮区域 */} <div className="w-full box-border relative flex items-center px-7"> {/* 左侧功能区 */} <div className="flex items-center"> {/* 抽奖/盲盒等功能按钮 */} </div> {/* 中央主操作区 - 绝对居中 */} <div className="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2"> {/* 主要操作按钮(开盒、任务等)- 始终居中显示 */} </div> {/* 右侧功能区 */} <div className="flex items-center ml-auto"> {/* 其他功能按钮 */} </div> </div> </div> );}```## 核心功能区域### 1. 容器布局规范#### **标准容器样式**```tsx// 基础容器 - 固定底部位置<div className={`w-full absolute bottom-8 ${props.className}`}> {/* 内容区域 - 水平布局 */} <div className="w-full box-border flex items-center justify-between px-7"> {/* 功能区域分布 */} </div></div>```#### **布局模式变体**```tsx// 居中布局<div className="w-full box-border flex items-center justify-center px-7">// 两端分布<div className="w-full box-border flex items-end justify-between px-7">// 简单居中布局<div className="flex justify-center items-center p-4 space-x-4">```**标准规范**:- **容器定位**: `absolute bottom-8` 距离底部32px- **水平内边距**: `px-7` (28px) 确保按钮不贴边- **Flexbox布局**: 使用`flex`进行水平分布- **对齐方式**: `items-center` 或 `items-end` 根据设计需求- **Z-index**: 通过外部className控制,通常为`z-[20]`### 2. 左侧功能区域主要承载次要功能入口,如抽奖、盲盒等。#### **抽奖功能按钮**```tsx{/* 抽奖按钮 - 使用统一的LotteryTrigger组件 */}<LotteryTrigger mainStageStore={props.mainStore} onPopClose={() => { // 抽奖弹窗关闭后的处理逻辑 endCurrentGuideStep?.(); }} renderContent={() => ( <ExposureTracker onExposure={() => { }}> <div className="flex-col flex items-center justify-center" onClick={() => { }}> <img data-id="mainstage-bottom-lottery-btn" src="[抽奖按钮图片URL]" className={`w-[80px] h-[105px] ${props.showLotteryTrigger ? 'opacity-100' : 'opacity-0'}`} alt="抽奖" /> </div> </ExposureTracker> )}/>```#### **盲盒功能按钮**```tsx{/* 盲盒按钮 - 条件显示 */}{isBlindBoxAvailable && ( <BlindBoxPopTrigger lotteryParam={lotteryParam} className="flex-col flex items-center justify-center" onClick={() => { }} renderContent={() => ( <img data-id="mainstage-bottom-blindbox-btn" src="[盲盒按钮图片URL]" className="w-[104px] h-[104px]" alt="盲盒" /> )} />)}```**功能区规范**:- **统一使用Shared组件**: `LotteryTrigger`、`BlindBoxPopTrigger`- **条件显示**: 使用props控制功能按钮的显示/隐藏- **埋点集成**: 必须包含曝光和点击埋点- **状态动画**: 支持opacity过渡效果- **图标尺寸**: 通常为80-104px正方形或特定比例### 3. 中央主操作区域承载项目的核心交互功能,通常是最重要的操作按钮。#### **主操作按钮(开盒类)**```tsx{/* 主操作按钮 - 核心功能 */}<div className="flex-1 flex justify-center"> <BoxOpenTrigger mainStageStore={props.mainStore} isProcessingLockRef={props.isProcessingLockRef} loading={props.loading} palyBoxOpenTriggerClickAnimation={props.palyBoxOpenTriggerClickAnimation} onMainActionBtnClick={props.onMainActionBtnClick} onMainActionBtnSuccess={props.onMainActionBtnSuccess} onMainActionBtnError={props.onMainActionBtnError} renderContent={renderMainActionBtnContent} showActionMotivateTipsBubble={props.showActionMotivateTipsBubble} /></div>```#### **主操作按钮内容渲染**```tsxconst renderMainActionBtnContent = () => ( <img data-id="mainstage-bottom-main-action-btn" src="[主操作按钮图片URL]" className="w-[200px] h-[80px]" alt="主要操作" />);```#### **简化版主操作(如刷新按钮)**```tsx{/* 简单操作按钮 */}<button data-id="bottom-refresh-btn" onClick={handleRefreshData} className="bg-gray-700 hover:bg-gray-600 text-white p-2 rounded-lg border border-gray-500 transform transition-all duration-200 hover:scale-105 active:scale-95" disabled={!isInitialized} title="刷新数据"> <span className="text-lg">🔄</span></button>```**主操作区规范**:- **居中布局**: 使用`flex-1 flex justify-center`确保居中- **统一组件**: 优先使用`BoxOpenTrigger`等shared组件- **状态管理**: 支持loading、disabled等状态- **回调处理**: 提供完整的成功、失败回调- **动画支持**: 集成点击动画和状态过渡### 4. 积分显示区域(上部居中)积分显示应放置在按钮区域上方,居中显示,作为重要信息的突出展示。#### **标准积分显示组件(推荐)**```tsx{/* 积分显示区域 - 上部居中 */}{props.showPointDisplay && ( <div className="w-full flex justify-center mb-4"> <PointsDisplay mainStageStore={props.mainStore} onPointsClick={() => { }} /> </div>)}```#### **自定义积分显示(仅在特殊需求时使用)**```tsx{/* 自定义积分显示 - 上部居中布局 */}{props.showPointDisplay && ( <div className="w-full flex justify-center mb-4"> <div data-id="bottom-points-display" className="bg-black/70 px-6 py-3 rounded-lg border border-yellow-400 min-w-[140px] cursor-pointer transform transition-all duration-200 hover:scale-105" onClick={handlePointsClick} > <div className="text-yellow-300 text-center"> <div className="text-xs">积分</div> <div className="text-lg font-bold">{pointsAmount || 0}</div> </div> </div> </div>)}```> **⚠️ 重要提醒**: 优先使用 `PointsDisplay` 组件,它提供了统一的样式、交互逻辑和埋点功能。仅在有特殊定制需求时才考虑自定义实现。### 5. 右侧功能区域承载次要功能按钮,如任务、设置等。## 核心组件集成### 必需组件导入Bottom组件需要导入以下共享组件:```tsximport { PointsDisplay } from '@/ace/shared/component/pointsDisplay';import { BoxOpenTrigger } from '@/ace/shared/component/boxOpenTrigger';import { BlindBoxPopTrigger } from '@/ace/shared/component/blindBoxPopTrigger';import { LotteryTrigger } from '@/ace/shared/component/lotteryTrigger';import { TaskPopTrigger } from '@/ace/shared/component/taskPopTrigger';import ExposureTracker from '@/ace/shared/component/exposureTracker';```### PointsDisplay 组件特性- **Headless UI 设计**: 支持完全自定义样式和布局- **模板占位符**: 使用 `$(points)` 作为积分数值占位符- **自动数据绑定**: 自动从 `mainStageStore.data.subStorePointsData.pointsAmount` 获取积分- **Render Props 支持**: 可通过 `render` prop 完全自定义渲染逻辑#### **任务入口按钮**```tsx{/* 任务按钮 */}{props.showTaskTrigger && ( <TaskPopTrigger mainStageStore={props.mainStore} renderContent={() => ( <div className="flex items-center justify-center"> <img data-id="mainstage-bottom-task-btn" src="[任务按钮图片URL]" className="w-[60px] h-[60px]" alt="任务" /> </div> )} />)}```**信息区规范**:- **统一组件**: 优先使用`PointsDisplay`、`TaskPopTrigger`- **视觉层级**: 使用适当的背景和边框突出重要信息- **交互反馈**: 点击时提供视觉反馈和埋点- **条件显示**: 通过props控制显示状态- **信息更新**: 响应式更新数据变化## 响应式设计与适配### 1. 屏幕尺寸适配```tsx// 标准布局<div className="w-full box-border flex items-center justify-between px-7"> {/* 统一使用px-7间距 */}</div>// 按钮尺寸规范<img className="w-[60px] h-[60px]" /> {/* 小型功能按钮 */}<img className="w-[80px] h-[105px]" /> {/* 标准功能按钮 */}<img className="w-[104px] h-[104px]" /> {/* 大型功能按钮 */}```### 2. 环境适配```tsximport { isPhaH5 } from '@/bus/tinyAppUtil';// 根据环境调整样式<div className={`${isPhaH5 ? 'bottom-6' : 'bottom-8'}`}> {/* 小程序环境使用不同的底部间距 */}</div>```## 状态管理与数据流### 1. Store数据集成```tsx// 响应式数据绑定const openBox = useOnReactionInClient(props.mainStore, () => { return props.mainStore.data.openBox;}, true);const pointsAmount = useOnReactionInClient(props.mainStore, () => { return props.mainStore.subStorePoints.data.pointsAmount;}, 0);const userInfo = useOnReactionInClient(props.mainStore, () => { return props.mainStore.data.userInfo;}, null);```### 2. 状态控制```tsx// 处理状态锁定const handleMainAction = async () => { if (props.isProcessingLockRef?.current) { return false; } try { props.isProcessingLockRef && (props.isProcessingLockRef.current = true); const result = await props.onMainActionBtnClick?.(); return result; } finally { props.isProcessingLockRef && (props.isProcessingLockRef.current = false); }};```### 3. 配置驱动```tsx// 从配置获取资源const lotteryButtonUrl = props.mainStore.data?.staticConfigData?.globalMaterials?.BottomMaterial?.lotteryButtonUrl;const mainActionUrl = props.mainStore.data?.staticConfigData?.globalMaterials?.BottomMaterial?.mainActionUrl;// 功能开关const enableLottery = props.mainStore.data?.staticConfigData?.EnableLottery ?? true;const enableTask = props.mainStore.data?.staticConfigData?.EnableTask ?? true;```## 动画与交互效果### 1. 点击动画```tsx// 按钮点击缩放效果<button className="transform transition-all duration-200 hover:scale-105 active:scale-95"> {/* 按钮内容 */}</button>// 自定义动画类<div className={`transition-transform duration-300 ${isActive ? 'scale-110' : 'scale-100'}`}> {/* 内容 */}</div>```### 2. 状态过渡```tsx// 透明度过渡<img className={`transition-opacity duration-300 ${visible ? 'opacity-100' : 'opacity-0'}`} />// 位置动画<div className={`transform transition-transform duration-500 ${show ? 'translate-y-0' : 'translate-y-full'}`}> {/* 内容 */}</div>```### 3. 加载状态```tsx// 加载动画{props.loading && ( <div className="absolute inset-0 flex items-center justify-center bg-black/50 rounded-lg"> <div className="animate-spin w-6 h-6 border-2 border-white border-t-transparent rounded-full" /> </div>)}// 禁用状态<button disabled={props.loading || !isInitialized} className="disabled:opacity-50 disabled:cursor-not-allowed"> {/* 按钮内容 */}</button>```## 埋点规范### 1. 曝光埋点```tsx// 组件挂载时埋点useEffect(() => { Logger.ins.reportBiz('[业务标识]_home_bottom_exp', { from: props.mainStore.data.from, scene_code: props.mainStore.data.sceneCode, }, { spmC: 'main_area', });}, []);```### 2. 点击埋点```tsx// 功能按钮点击埋点const handleLotteryClick = () => { Logger.ins.reportBiz('[业务标识]_home_lottery_clk', { from: props.mainStore.data.from, scene_code: props.mainStore.data.sceneCode, }, { spmC: 'main_area', });};```### 3. ExposureTracker使用```tsx// 精确曝光追踪<ExposureTracker onExposure={() => { Logger.ins.reportBiz('[业务标识]_main_action_exp', { action_type: 'open_box', from: props.mainStore.data.from, }, { spmC: 'main_area', });}}> <MainActionButton /></ExposureTracker>```## 样式规范### 1. 布局样式```css/* 容器布局 */.w-full.absolute.bottom-8 /* 标准底部容器 */.box-border.relative.flex.px-7 /* 内容区域布局 - 使用relative定位 */.items-center /* 垂直居中对齐 *//* 积分显示区域 */.w-full.flex.justify-center /* 积分区域居中布局 */.mb-4 /* 积分区域下间距 *//* 功能区域 */.absolute.left-1/2.top-1/2 /* 主按钮绝对居中定位 */.transform.-translate-x-1/2.-translate-y-1/2 /* 居中偏移调整 */.flex.items-center /* 侧边功能区 */.ml-auto /* 右侧功能区自动右对齐 */```### 2. 尺寸规范```css/* 按钮尺寸 */.w-[60px].h-[60px] /* 小型功能按钮 */.w-[80px].h-[105px] /* 标准功能按钮 */.w-[104px].h-[104px] /* 大型功能按钮 */.w-[200px].h-[80px] /* 主操作按钮 *//* 积分显示尺寸 */.min-w-[140px] /* 积分容器最小宽度 */.px-6.py-3 /* 积分区域内边距 *//* 容器高度规范 */.h-[80px] /* 简单布局容器高度 */.h-[120px] /* 标准布局容器高度 */.h-[160px] /* 大型按钮布局容器高度 *//* 间距规范 */.px-7 /* 水平内边距 28px */.mb-4 /* 积分区域下间距 16px */.ml-4 /* 元素间距 16px */.space-x-4 /* 子元素间距 16px */.space-x-8 /* 较大子元素间距 32px */.bottom-8 /* 底部距离 32px */```### 3. 视觉效果```css/* 背景效果 */.bg-black/70 /* 半透明黑色背景 */.bg-gradient-to-t.from-black/50.to-transparent /* 渐变背景 */.rounded-lg /* 圆角 */.border.border-yellow-400 /* 边框 *//* 交互效果 */.hover:scale-105 /* 悬停放大 */.active:scale-95 /* 点击缩小 */.transition-all.duration-200 /* 过渡动画 */.disabled:opacity-50 /* 禁用状态 */```### 4. Z-index层级```css.z-[20] /* Bottom组件基础层级 */.z-[25] /* 弹出内容层级 */.z-[30] /* 引导提示层级 */```## 高级功能### 1. 新用户引导集成```tsx// 引导步骤控制import { showGuideStep, endCurrentGuideStep } from '../newPlayerGuide';const handleGuideComplete = () => { endCurrentGuideStep(); // 继续下一步引导或完成引导};// 引导气泡显示{props.showActionMotivateTipsBubble && ( <div className="absolute -top-16 left-1/2 transform -translate-x-1/2 bg-orange-100 text-orange-800 px-4 py-2 rounded-lg text-sm whitespace-nowrap shadow-lg z-10"> 点击开始游戏 <div className="absolute bottom-[-6px] left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-[6px] border-r-[6px] border-t-[6px] border-l-transparent border-r-transparent border-t-orange-100"></div> </div>)}```### 2. 条件渲染逻辑```tsx// 基于用户状态的条件渲染const newUser = useOnReactionInClient(props.mainStore, () => { return props.mainStore.data.userInfo?.isNewUser;}, false);// 基于业务逻辑的功能显示const isBlindBoxAvailable = useOnReactionInClient(props.mainStore, () => { return [true, 'true'].includes(props.mainStore.data.blindBox?.isAvailable);}, false);return ( <div> {/* 新用户不显示高级功能 */} {!newUser && <LotteryTrigger />} {/* 根据业务配置显示功能 */} {isBlindBoxAvailable && <BlindBoxPopTrigger />} </div>);```### 3. 错误处理```tsxconst handleActionWithErrorHandling = async () => { try { const result = await props.onMainActionBtnClick?.(); if (result) { await props.onMainActionBtnSuccess?.(result); } } catch (error) { console.error('Bottom action failed:', error); await props.onMainActionBtnError?.(error); // 用户友好的错误提示 showToastText('操作失败,请重试'); }};```## 最佳实践### 1. 组件复用- **优先使用Shared组件**: `LotteryTrigger`、`BoxOpenTrigger`、`TaskPopTrigger`、`PointsDisplay`- **统一组件接口**: 保持相似功能组件的接口一致性- **配置化驱动**: 通过props和配置控制组件行为### 2. 状态管理```tsx// 集中处理异步状态const [bottomState, setBottomState] = useState({ loading: false, error: null, data: null});// 统一的状态更新方法const updateBottomState = (updates: Partial<typeof bottomState>) => { setBottomState(prev => ({ ...prev, ...updates }));};```## 重要注意事项### ⚠️ **开发要求**1. **统一组件使用**: 必须优先使用`LotteryTrigger`、`BoxOpenTrigger`、`TaskPopTrigger`、`PointsDisplay`等shared组件2. **响应式数据绑定**: 使用`useOnReactionInClient`进行数据监听,避免直接访问store数据3. **埋点完整性**: 所有用户交互都必须包含完整的埋点(曝光和点击)4. **错误处理**: 提供完善的错误处理和用户反馈机制5. **性能优化**: 合理使用React.memo、useCallback、useMemo等优化手段### 🔧 **技术规范**1. **样式规范**: 使用Tailwind CSS类名,保持样式的一致性和可维护性2. **状态管理**: 通过props传递状态控制,避免组件内部复杂状态逻辑3. **组件解耦**: 保持Bottom组件的纯展示性,业务逻辑通过回调函数处理4. **类型安全**: 使用TypeScript接口定义明确的props类型5. **安全区域**: 适配不同设备的安全区域,确保按钮可点击### 📐 **布局约束**1. **底部定位**: 统一使用`absolute bottom-8`进行底部定位2. **水平间距**: 使用`px-7`确保按钮不贴边显示3. **元素分布**: 根据功能需求选择`justify-between`、`justify-center`等分布方式4. **Z-index层级**: 通过外部className控制,避免层级冲突5. **响应式适配**: 考虑不同屏幕尺寸的布局适配### 🎯 **功能要求**1. **核心功能**: 必须包含项目的核心交互功能入口2. **信息展示**: 提供重要的用户信息显示(积分、状态等)3. **视觉反馈**: 所有交互都要有明确的视觉反馈4. **状态同步**: 及时响应数据变化,更新UI状态5. **引导支持**: 支持新用户引导和功能提示### 🚫 **禁止事项**1. **不得直接操作DOM**: 使用React的声明式方式进行UI更新2. **不得跳过埋点**: 所有用户交互必须包含对应的埋点代码3. **不得硬编码样式**: 使用Tailwind类名而非内联样式4. **不得忽略错误处理**: 必须为异步操作提供错误处理5. **不得破坏响应式**: 确保组件在不同设备上的正常显示面向全生命周期的智能开发框架
"Code is cheap, Spec is valuable" —— 代码可以快速生成,但好的规范和设计模式才是真正的价值所在。
“检测到‘社交分享’未指定具体路径。当前项目常用方式包括微信唤端、复制链接、二维码海报,请确认是否支持多渠道?是否包含奖励激励?”
复用 SharePanel → 注入“二维码面板”类型和参数 → 调用 useRewardTrigger 控制曝光 → 适配活动主题样式
## 3 模块详细设计### 3.1 二维码分享功能(QR Code Sharing)| 字段 | 内容 || --- | --- || 职责边界 | 实现基于二维码的分享能力,支持内容生成、容器注入与激励联动 || 目录位置 | `src/modules/share/qrcode/` || 关键依赖 | `@utils/qrcode@^1.2`, `vue@3.x`, `pinia@2.x`, `useRewardTrigger` |#### 3.1.1 外部接口* API```typescript// 无独立接口,复用通用分享服务POST /api/v1/shareinterface SharePayload { type: 'qrcode'; content: string; timestamp: number }```#### 3.2.1 关键算法##### 流程图```mermaidflowchart TD A[用户点击分享按钮] --> B{选择渠道为二维码?} B -->|是| C["调用 qrcode.generate(content)"] C --> D{生成成功?} D -->|是| E["将图像注入 SharePanel"] D -->|否| F["展示占位图并记录错误"] E --> G{配置了激励策略?} G -->|是| H["调用 useRewardTrigger.show()"] G -->|否| I[结束] H --> I```* 说明:本流程描述从用户操作到最终反馈的完整路径。`qrcode.generate` 为异步方法,需处理加载与失败状态。激励触发仅在业务规则允许时执行。 ##### 代码片段```typescriptconst handleQrShare = async (content: string) => { try { const imageUrl = await qrCodeUtil.generate(content) sharePanel.open({ type: 'qrcode', image: imageUrl }) if (shouldShowReward()) { useRewardTrigger().show() } } catch (err) { logger.warn('QR generate failed', err) sharePanel.open({ type: 'qrcode', fallback: true }) }}```#### 3.1.3 状态机(如有)| **状态** | **迁移条件** | **副作用** || --- | --- | --- || `idle` → `generating` | 用户选择二维码分享 | 显示加载指示器 || `generating` → `success` | 图像生成完成 | 注入容器并隐藏骨架屏 || `generating` → `error` | 超时或网络异常 | 展示默认占位图,降级提示 |#### 3.1.4 视图结构```html<template> <SharePanel :type="qrcode" :image="qrImage" :loading="loading"> <FallbackMessage v-if="error" text="图片加载失败" /> <LoadingSkeleton v-else-if="loading" /> </SharePanel></template>```#### 3.1.5 动画 & 手势* 进入动画:`opacity 0 → 1`,持续 150ms,ease-in-out* 退出动画:点击遮罩后 `scale(1) → scale(0.95)`,透明度同步下降* 可访问性:支持键盘 `Esc` 关闭,符合 `prefers-reduced-motion` 用户偏好#### 3.1.6 异常与降级| **错误码 / 场景** | **用户提示** | **重试策略** | **监控指标** || --- | --- | --- | --- || 网络异常导致生成失败 | “二维码加载失败” | 不自动重试,提供“重新生成”按钮 | `qrcode_generate_error_total` || 超时(>5s) | “生成较慢,已切换备用方式” | 自动降级为“复制链接”选项 | `qrcode_timeout_count` || 容器不支持该类型 | (静默)回退至默认分享页 | 无 | `qrcode_unsupported_fallback` |## 4 跨模块通信总览### 4.1 A 表:事件总线| **事件名** | **触发时机** | **触发方** | **负载结构(TypeScript)** | **监听方** | **消费时机** | **幂等 / 异常处理** | **备注** || --- | --- | --- | --- | --- | --- | --- | --- || `mx:share:triggered` | 用户完成分享动作 | QrShareHandler.ts | `{ type: 'qrcode', id: string, timestamp: number }` | AnalyticsService.ts | 立即上报埋点 | 同一 ID 10s 内去重 | 用于行为分析与转化统计 |### 4.2 B 表:响应式 Store| **Store 片段** | **导出方式** | **数据类型** | **触发时机** | **监听方** | **计算 / 派生规则** | **异常兜底** || --- | --- | --- | --- | --- | --- | --- || `useShareConfig().channels` | `const { channels } = useShareConfig()` | `Ref<ShareChannel[]>` | 应用初始化时加载配置 | SharePanel.vue | 从远端配置中心拉取,本地缓存 | 解析失败时使用默认渠道列表 |### 4.3 C 表:路由 & URL| **Query 参数** | **出现页面** | **数据类型** | **触发时机** | **消费时机** | **校验规则(zod)** | **同步副作用** || --- | --- | --- | --- | --- | --- | --- || `share_mode` | /activity/detail | `'qrcode' \| 'link' \| 'poster'` | 用户从外部链接进入 | `onMounted` 阶段读取 | `z.enum(['qrcode', 'link', 'poster'])` | 自动打开对应面板,若无效则默认 'link' |### 4.4 D 表:跨上下文通道| **通道名** | **上下文** | **数据类型** | **触发时机** | **接收方** | **冲突解决** | **降级策略** || --- | --- | --- | --- | --- | --- | --- || `share:sync` | BroadcastChannel | `{ type: 'qrcode'; content: string }` | 用户在其他 Tab 触发分享 | 当前活跃 Tab | 时间戳最新者优先 | 无广播支持时使用 `localStorage` + `storage` 事件同步 |未来展望
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-12-07
扒了20家大厂的底裤,我发现99%的AI Agent都在“假装智能”
2025-12-05
Gemini Prompt:我构建了一个 Ilya 的AI 分身,他告诉我 AI 正在产生自我
2025-12-04
像水一样编程:我的 Vibe Coding 进化史与实战心法
2025-12-03
n8n一键生成验收文档和表格(excel读取任务写入word,excel)
2025-12-03
如何在Cursor、Trae等工具中使用Skills?
2025-12-03
Gemini Prompt:我把全身照发给了AI,它用“物理学”治好了我的穿搭焦虑
2025-12-02
Gemini Prompt:小红书变现达人-流量的尽头是变现
2025-12-02
如何写出完美的Prompt(提示词)?
2025-10-09
2025-11-14
2025-09-12
2025-10-21
2025-09-23
2025-10-13
2025-09-26
2025-09-23
2025-10-30
2025-09-15