ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

B端官网Demo实战:8+1页面构建与演示故事线设计

B端官网Demo实战:8+1页面构建与演示故事线设计 2. 页面实现的核心细节一说到官网demo很多人第一反应是静态页面而已套个模板快得很。真做起来才发现8个业务页面加1个联动演示场景能暴露出的问题比想象中多得多。我这次做的就是一个偏B端产品的官网demo81用来给销售和客户现场演示也兼着给团队评审用。如果你正在做类似的预览站点、投标演示版、或者是市场团队要的尝鲜版这篇文章里的方法可以直接照着抄。“81”里那8个页面对应的是官网导航上的常规内容首页、产品中心、解决方案、客户案例、关于我们、新闻动态、加入我们、联系我们。剩下那个“1”不是常规的404或搜索页而是一条隐藏在路由里的演示故事线页面。它把所有业务页面串成一条连贯的演示路径现场讲的时候不用手动来回切换客户也不会被零碎操作打断思路。这个项目从定需求到落地一共用了两周技术栈用的是Vite React TypeScript Tailwind CSS。下面我把整个拆解过程、每个页面的实现思路、还有踩过的坑都写出来。文章里的代码和做法都是实际跑过的不是纸上谈兵。1. 需求拆解81页面不是拍脑袋想出来的1.1 先把页面目的写清楚再动手写代码开始写代码之前我先把每个页面在纸上画了一遍信息架构。这一步看着简单恰恰是demo能不能“像官网”的关键。很多demo做出来假就是因为首页堆了一大堆营销话术产品页却连核心功能入口都没有客户看着看着就不知道你在讲什么了。我当时的页面划分和演示目标是这样的页面核心演示任务页面形态首页30秒内讲清产品定位和差异化首屏三大产品入口客户Logo数据指标产品中心让客户找到自己关心的功能模块产品列表筛选器详情页锚点解决方案按行业/角色讲故事而不是罗列功能场景卡片流程示意案例跳转客户案例用数据证明效果案例列表详情侧滑层关于我们建立信任感发展历程核心团队新闻动态展示产品持续迭代文章列表摘要加入我们顺手满足招聘场景职位列表简单筛选联系我们引导留资或预约演示表单联系方式1演示故事线把上述页面串成一条完整Demo流程演示导览页路由联动这样一列就发现所谓“81”不过是最小可用官网集合。如果你正在做的是一个更成熟的产品可能还会拆出“定价页”“文档中心”“开发者社区”等等。但作为demo9个页面已经足够覆盖一次产品演示的主线了。1.2 选型为什么我不先用全家桶做demo我见过最亏钱的做法是还没想清楚就拉一个Next.js全栈项目再配上一个重型后台框架光初始化就折腾半天。对这种预览性质的官网我的原则是能静态就静态能轻就轻。这次选的是Vite 5 React 18 TypeScript 5。理由很简单Vite冷启动快热更新顺手构建出来的产物是纯静态文件扔到任意一台能装Nginx的机器上就能跑。React Router v6做多页面路由Tailwind CSS负责样式。没有引入状态管理库直接用一个React Context URL参数处理跨页面的演示状态demo规模下完全够用。注意如果这个官网之后要长期迭代、做SEO那需要考虑迁移到Next.js。但那改造成本其实不低所以我建议一开始就明确这是demo/预览版正式版另起炉灶。别让demo背负多余的复杂度。1.3 那个“1”到底是什么“1”是一个独立于导航的演示导览页路由我设为/story。它不显示在顶栏和页脚里只能通过特殊入口或直接输入URL访问。页面上放着“产品演示”“解决方案演示”“案例数据演示”三张卡每张卡对应一段演示脚本。点击其中一张卡页面会携带一个参数跳到目标页比如/products?storycore-features。目标页在加载时读取参数自动高亮预设的功能模块并在页面角落显示一个“返回导览”的悬浮按钮。客户在现场看的时候整个演示像看PPT翻页一样顺畅不会出现“等一下我找一下那个页面”的尴尬。这个设计我当时完全是即兴加的结果意外成了整个项目里最有存在感的功能。它解决的其实不是技术问题而是一个很现实的问题demo人员在现场会紧张一紧张就手忙脚乱与其依赖临时发挥不如让页面替你把节奏安排好。2. 核心细节解析每个页面我到底做了什么2.1 顶部导航和路由过渡统一是安全感的来源导航我没有单独用前端框架组件库而是自己写的一个固定顶栏。B端官网的导航通常层级不深用下拉菜单反而制造混乱所以我把导航设计成纯平铺产品中心和解决方案动效上有点小交互但内容不藏导航层级。这里有个我每次都要强调的细节导航的高亮状态一定不能高亮错。比如产品详情页/products/detail/1导航“产品中心”必须保持高亮。这个逻辑用React Router的useLocation和路由规则匹配就能做不要用字符串startsWith硬匹配否则以后加二级路径容易踩坑。路由过渡我用了最轻量的方式页面切换时加一个透明度 位移的纯CSS动画利用View Transition API或简单的key变化重置动画。很多团队会引入framer-motion做全屏页面过渡但在这种需要快速加载的演示站点里动画库的包体负担有点不划算。现场演示时客户不需要那种夸张的转场干净利落反而是专业感的来源。2.2 首页把首屏当成产品发布现场首页是整个demo的门面。我的首页结构是首屏大标题写明行业产品一句话价值- 三条核心产品线卡片 - 数字化指标数据墙 - 客户Logo墙 - FAQ最后一屏是联系我们。首屏我特意压缩成了一个高度正好占满一屏的半屏Banner加半屏产品入口预览。客户第一次打开不用滚屏就能看到“你是谁、你解决什么问题、你有哪些产品”。这三件事在前3秒讲不清楚后面再精致都是白搭。产品入口卡片我用了大图标 一句话描述 “查看详情”链接。排布上没有做成对称三列而是中间略大、两边略小制造层级感。这个方案最初拿UI稿给团队看的时候有人嫌不对称、太冒险但演示现场用户的视线会在三个产品之间自然移动反而达到了引导探索的目的。数据指标墙用的是客户现场就能看懂的大数字不是那些“平台智能率”之类的自嗨词。2.3 产品中心用mock数据统一管理替换成本降到底产品中心这个页面demo阶段没有真实API所以我用了本地mock数据。但这里的mock不是随便硬编码在组件里而是单独维护了一个mocks/product.json并且定义了完整的TypeScript类型export interface ProductCategory { id: string; name: string; description: string; icon: string; features: ProductFeature[]; } export interface ProductFeature { id: string; title: string; subtitle: string; desc: string; icon: string; screenshots?: string[]; }页面里所有筛选、详情、锚点跳转都基于这份数据。产品列表左侧是分类筛选右侧是卡片流。点击卡片后在当前页面打开一个侧滑详情层里面包含功能特性、适用场景、几张示意截图。侧滑层的好处是切换产品不用跳转页面演示时连续看两三个产品不会因为浏览器前进后退而显得乱。我当时特意不把产品详情做成独立路由页面而是做成抽屉背后有个很实际的原因客户在demo现场经常是“对比着看”选完A产品马上想看B产品。如果做独立页面来回切换容易出现白屏、滚动位置丢失这些小问题。侧滑层天然规避了这个麻烦。这个方案有个代价产品详情无法通过链接直接分享。所以我在每个侧滑层右上角放了一个“复制详情链接”按钮生成类似/products?detailcore-system的URL。其他设备打开时路由读取参数自动打开对应详情层。这样既保留了单页切换的流畅又不丢失链接直达能力。2.4 解决方案页按角色讲场景按行业配故事解决方案页最忌讳的是单纯把产品功能罗列一遍。B端客户关心的不是你有多少功能而是你的方案能不能解决他遇到的痛点。所以我把解决方案拆成两层一层按角色比如决策者、业务负责人、一线执行一层按行业比如制造、零售、金融。角色方案用的是卡片式布局每张卡片配一个“该角色每天会遇到的三个问题”然后才是方案概要。行业方案则用更轻的横向tab切换进入某个行业后展示一句行业洞察 典型应用场景 对应客户案例链接。这样观众可以从两个维度切入demo人员也可以根据现场观众身份快速选择合适的演示路径。这里的实现细节横向tab切换时我保留了每个tab独立的滚动位置和筛选项状态切换回来不会丢内容。原理是把各tab的内容区分别做成独立的列表组件不共用全局筛选状态。这个细节听起来小但现场演示时非常加分。2.5 案例页、关于页、新闻页、招聘页、联系页简单页面反而考验耐心这五个页面在整个demo里功能占比不大但恰恰最容易露怯。我见过很多demo项目首页和产品页做得花团锦簇一到关于我们页就崩了排版错位、图片加载失败、联系方式甚至还是“110example.com”这种占位内容。页面越简单越不能糊弄。案例页我做得相对重一些列表带行业筛选和关键词搜索数据同样来自mocks/cases.json。案例详情用的也是侧滑层里面包含客户背景、痛点、方案、效果数据和客户证言。数据地方我刻意把“效果提升XX%”放在卡片表面的右上角观众扫一眼就能看到收益——B端案例的冲击力就靠这一眼。关于我们页走的是简洁路线公司简介 一组发展历程时间轴 核心团队卡片。这里团队卡片用了占位头像我是用随机头像服务生成的但要提醒大家demo可以上线前必须换成自己的素材。新闻动态页就是文章列表加筛选标签文章内容我用几段真实感的样例文本充数标题写得专业一点不然客户一眼就看出是虚拟内容。加入我们页没有做完整的招聘系统只做了职位列表筛选申请按钮点击后就跳出“提交成功”的toast提示因为demo阶段没必要接真实表单。联系页是我唯一下功夫做交互的页面表单做了前置校验、成功态动画和演示预约入口电话、邮箱、地址全部放真实可用的占位数据。关于页面这批内容的统一性我组了一个PageHeader公共组件统一控制所有内页的标题区、面包屑和简介文案。不然九个页面各自写一套头部视觉上会很散。3. 实操过程多页面协同、交互细节和视觉体系是怎么落的3.1 页面间数据联动一个Context让整个demo活起来官网demo的页面之间本应该是弱耦合的但为了实现“1演示故事线”的效果我需要跨页面共享一部分状态。我没有引入Redux而是写了一个小组件DemoProvider挂在路由根节点上const DemoContext createContextDemoContextType | null(null); export function DemoProvider({ children }: { children: React.ReactNode }) { const [storyMode, setStoryMode] useState(false); const [activeGuide, setActiveGuide] useStatestring | null(null); const startStory (step: string) { setStoryMode(true); setActiveGuide(step); window.sessionStorage.setItem(story_step, step); }; const endStory () { setStoryMode(false); setActiveGuide(null); window.sessionStorage.removeItem(story_step); }; return ( DemoContext.Provider value{{ storyMode, activeGuide, startStory, endStory }} {children} /DemoContext.Provider ); }为什么用sessionStorage而不是直接只在内存里存因为现场演示随时可能刷新浏览器一旦刷新内存状态就丢了。存到sessionStorage后刷新页面仍然保留当前演示步骤可以无缝继续讲下去。这个细节我调试了几次才发现需要加不然演示到一半手滑按了个F5整个导览状态就重置了非常尴尬。具体联动逻辑是/story导览页点击某一步写入sessionStorage目标页面加载时读取并高亮对应区域同时页面右上角常驻“回导览”悬浮按钮。如果用户在演示路径上点了导航去别的页面悬浮按钮不会自动消失得点一下结束导览才会清除状态保证“逃逸”后也能拉回来。3.2 动效入场动画、数字滚动哪一些值得做动效这块我给自己定了个规矩能用CSS解决的不碰JS动画库。整个项目里我只写了一个通用Reveal组件用来做元素进入视口时的渐显动画import { useEffect, useRef, useState } from react; export function Reveal({ children, delay 0 }: { children: React.ReactNode; delay?: number }) { const ref useRefHTMLDivElement(null); const [visible, setVisible] useState(false); useEffect(() { const el ref.current; if (!el) return; const observer new IntersectionObserver( ([entry]) { if (entry.isIntersecting) { setVisible(true); observer.disconnect(); } }, { threshold: 0.15 } ); observer.observe(el); return () observer.disconnect(); }, []); return ( div ref{ref} style{{ opacity: visible ? 1 : 0, transform: visible ? translateY(0) : translateY(24px), transition: opacity 0.6s ease ${delay}ms, transform 0.6s ease ${delay}ms, }} {children} /div ); }这里有个经验是Threshold不要设成1那个要求元素完全进入视口才触发首屏下方一点点的内容会迟迟不出现。0.15左右最舒服。此外还有一个细节触发一次后立即断开观察器避免元素来回进出视口时反复播动画显得很廉价。首页数据指标墙的数字滚动动效我写了个useCountUp的Hook在组件进入视口后用requestAnimationFrame驱动数字变化600毫秒内从0增到目标值。为什么不直接做CSS动画因为CSS对数字内容的插值支持有限property这招在老旧浏览器上不兼容。这个Hook大约40行代码常驻在项目里以后做B端营销页还能复用。3.3 视觉语言颜色、圆角、字体、间距统一成变量表格在这个项目里最大的作用不是数据好看而是让九个人看得像同一个系统的。我在tailwind.config里扩展了主题变量把所有核心token集中管理theme: { extend: { colors: { brand: { 50: #f0f9ff, 100: #e0f2fe, 500: #0ea5e9, 600: #0284c7, 700: #0369a1, }, }, borderRadius: { DEFAULT: 10px, lg: 16px, xl: 24px, }, boxShadow: { card: 0 1px 3px rgba(0,0,0,0.06), 0 8px 24px rgba(0,0,0,0.06), }, }, },全套页面只用一个主色体系辅助色控制在三种以内。字体方面我最终选择了最稳妥的方案中文字体不引入任何自定义WebFont直接用系统字体栈。原因是中文在线字库体积动辄几百KB甚至几MB对演示环境不友好而且客户现场网速差时字体加载会严重摧毁首屏体验。用系统字体栈虽然视觉上没那么“品牌感”但换来的是稳定和快这对demo站点是更重要的事。卡片阴影我只定义一个token全站所有卡片都用同一个阴影。按钮高度、圆角、字号也都有变量约束。别小看这些变量它们能让没有专门UI介入的demo阶段保持视觉一致性。实际开发中我见过太多demo项目第一页用大圆角第三页用小圆角首页按钮有阴影案例页按钮没有。这些不一致的观感客户现场一对比就会被放大。3.4 图片资源治理体积、格式、占位策略demo内容里的图片我全部做了一轮压缩处理。原始设计稿导出的截图经常是2~3MB的PNG直接进项目会把页面拖垮。我在项目根目录加了一个简单的脚本用sharp把所有图片统一转成WebP并限制最长边不超过1600px。压缩完之后单张图片基本都控制在80~150KB之间。这里我建议不要偷懒用原图哪怕只是demo现场演示的电脑配置千奇百怪一张大图卡顿会让整场演示变得很难看。占位图统一用一个本地SVG组件生成带品牌色的抽象色块避免第三方占位图服务在客户内网环境下加载失败。我踩过一次这样的坑第一次演示时用了外部图床现场客户公司网络策略比较严格图片全挂了整个页面就像被撕了一大块。从那次以后demo项目所有资源一律本地化不依赖任何外网CDN。4. 性能与部署让demo在任何一台演示机上都能流畅打开4.1 目标不是Lighthouse 100而是“秒开”很多人做demo喜欢盯着Lighthouse跑分我反而觉得关键指标只有一个在一台没有多余优化的普通Windows笔记本上用Chrome开无痕窗口访问能不能在2秒内看到首屏主体内容。Lighthouse分数高但真实环境一塌糊涂的站点你我都见过。我在构建配置上做了三件事第一按路由拆包。React Router v6天然支持懒加载每个页面对应独立的JS chunkconst HomePage lazy(() import(/pages/HomePage)); const ProductsPage lazy(() import(/pages/ProductsPage)); const SolutionsPage lazy(() import(/pages/SolutionsPage));注意懒加载的路由组件切换时会有短暂的白屏。我额外做了一个全局Suspensefallback是一个轻量的页面骨架。骨架屏不用复杂灰色区块 一点淡入动画就够了关键是让用户感觉页面在“加载内容”而不是“卡住了”。第二手工拆分第三方依赖。Vite默认的chunk策略会把所有node_modules里的代码打到独立块里但不一定合理。我的vite.config.ts里手动把React相关、开源的图表库、工具库分别拆了一份。这样首屏只用加载React核心图表库进入对应页面时才拉取。第三关键字体和首屏图片预加载。图片我用了loadinglazy让非首屏图延迟加载但首屏Banner图反而要主动预加载不能等浏览器决定。这个“正向懒加载关键资源预加载”的差异是很多前端容易搞反的地方。我当时实测的一个调优前后对比基础版打包产物体积约1.1MB未gzip首屏加载在演示机上要3秒多。经过上述拆分、压缩、图片处理之后首屏JSgzip约180KB本地环境几乎做到秒开。这个收益在项目早期可能不显眼但在现场演示时能明显感受到胆气壮了不少。4.2 骨架屏和首屏体验骨架屏这件事值得展开讲。很多React SPA在首屏都有一个通病第一个画面是白色然后突然闪现完整内容用户会觉得“网页加载了但刚才那个白色是什么情况”。我写了一个PageSkeleton组件根据每个页面的布局生成对应的骨架结构。首页的骨架是顶部导航栏首屏banner三列卡片的大色块占位产品页则是左侧筛选器右侧卡片网格的骨架。组件不大每个页面几十行代码但它对演示体验的提升非常明显——客户不会在加载的几秒里盯着白屏发呆而是在看一个“正在成形”的页面。懒加载还会带来一个坑同一时刻多个chunk并发请求容易触发浏览器的同域名并发限制。所以我把所有公共依赖全部打进了initial chunk只有页面自身的逻辑才是懒加载。这样切页时只有一个新chunk要拉取延迟会低很多。4.3 部署与发布静态文件扔到任何机器都能跑整个项目构建完成后产物是/dist目录下的静态文件。我用了两种部署方式一个是在团队内网用Nginx起一个静态站点另一个是直接扔到一台便宜的云主机上用serve跑。两种方式都只需要一行命令不需要配数据库、不需要环境变量。这里有一个经验Nginx配置一定要记得解决路由history模式导致的404。React Router默认是BrowserRouter刷新/solutions/manufacturing这个路径时如果Nginx没有做try_files回退会报404。我在部署配置里写了location / { try_files $uri $uri/ /index.html; }很多新手在这儿翻车看起来是“页面能打开”但一刷新就挂。demo现场最怕这种意外所以当时我在检查清单里专门加了一条所有二级路径刷新必须在部署前验证。5. 常见问题与排查技巧demo路上那些坑一次讲完5.1 字体闪烁、样式错乱、图片抖动这类首屏问题怎么定位这套demo做完前后遇到的几个常见问题我整理成了一个速查表现象可能原因排查思路解决办法页面切换后顶部导航样式先乱后正常懒加载chunk的CSS在JS之后注入首帧样式未覆盖完整打开Network面板看CSS加载顺序把全局样式和tailwind样式放进initial chunk不参与按需加载图片加载后周围内容明显抖动图片尺寸未占位高度从0跳到指定值检查img是否有width/height或aspect-ratio统一给图片容器设置宽高比或min-height切页时顶部短暂白条路由懒加载的Suspense fallback没包含导航头观察Suspense包裹范围把导航、页脚放在路由组件外部渲染只有中间内容区域用Suspense锚点跳转后页面位置不对路由hash与锚点冲突或SPA的scrollRestoration未处理用浏览器地址栏手动测试各hash路径用ScrollRestoration或统一封装滚动逻辑浏览器版本太旧导致样式崩演示机是IE或旧版Edge检查兼容性目标demo环境统一用Chrome无痕窗口部署前明确演示浏览器这里面最值得说的就是第三行那个问题当时我把整个页面包括导航框架和路由出口都放在Suspense里结果切页时整个页面都变成骨架屏导航也跟着闪。后来把布局拆出来DemoProvider SiteLayout {/* 导航和页脚固定在这里 */} Suspense fallback{PageSkeleton /} Routes.../Routes /Suspense /SiteLayout /DemoProvider改动只有几行但演示时的“页面整体闪动感”立刻消失了只有中间内容区做加载替换体感上专业了许多。5.2 现场演示的三大风险网络、环境、演示人员手滑网络上踩过的坑前面提到过就是不能依赖任何外部资源。具体来说我把图片、图标、字体全部本地化接口全部打桩整个demo站点在完全断网的情况下也能跑。这不是吹毛求疵而是现场演示高频发生的场景客户的会议室要么WiFi受限要么网速奇差。你要确保打开一级页面时不需要等待任何外部请求结束。环境上的坑更隐蔽。有些客户的公司电脑会弹“360安全卫士”拦截小弹窗或者默认浏览器是某个老旧内核。我当时准备了非常具体的演示清单提前用一个U盘把整个/dist文件夹装进去如果现场没有网络就启动一个本地静态服务用Python的python -m http.server 8000都可以然后开一个无痕窗口访问。无痕窗口的好处是避免浏览器插件比如广告拦截、翻译插件干扰页面样式和渲染。演示人员手滑这个问题我用了前面讲的路由导览来兜底。导览页上每张卡都有预设的URL参数点击后自动进入对应演示步骤。就算某个步骤讲砸了也可以快速按一下顶栏Logo回首页再重新进入导览状态。另外我还在联系方式页做了一个“醒神”细节表单提交按钮hover时有一个轻微的动效现场讲到这里可以活跃一下气氛投资人听完一堆严肃内容后往往就在这个环节放松下来。5.3 第三方组件库的授权与“水印”问题这次demo我几乎没引入重型第三方组件。唯一用到了一个图表库的开源版本Apache 2.0协议一个模拟数据的小工具还有一个渲染Markdown的库。但很多团队做可视化官网demo时会直接试装商业组件库的评估版。这里要特别提醒商用图表库的试用版通常会在图表角落打上水印而且官方协议明确禁止移除、遮挡或用CSS隐藏水印。有人动过“把水印裁掉”的歪脑筋隐患很大一旦上线被扫描到或用图被抓包法律风险会落到产品头上。我的建议是demo阶段就选开源协议放心的库Apache 2.0、MIT协议的中后台图表和组件都很丰富。假如一定要用某个商用库解决方案要么是购买正式授权要么跟厂商申请一个专门给演示的、无限制的评估许可。切忌通过破解、“去水印”脚本这类手段投机取巧这对团队和客户都是负资产。另外就是组件库的版本锁定。当时我同事在安装依赖时不小心把某个库从v2升到了v3demo页面立刻出现几处样式不一致。排查了很久才发现是版本差异。从那以后我在项目中把依赖锁定精确到补丁版本并在构建流水线里加了npm ci而不是npm install保证团队任何人的本机构建产物一致。这也算是在demo实战中得来的教训。6. 最后再分享一点个人心得这个项目做完后我最明显的一个感受是demo的最终价值不在页面多精美而在整个演示节奏是否连得起来。8个页面做得再好看如果现场叙事断掉了效果立刻打折。那条“1”的演示故事线之所以重要是因为它把一堆静态页面变成了一个有引导、有节奏的叙事工具。再往后做类似项目我会考虑加两件事一是把案例详情也做成可通过URL参数直达的形式方便把具体案例链接发给客户后他们直接点开二是用一个简单的数据层比如MSW这个库模拟真实接口让demo后期接真实API时不需要改前端代码结构。这两个扩展方向成本都不高但收益很实在。如果只留一条经验给你那就是demo项目的每一行代码都要有“会被现场演示放大”的自觉。那些平时看着无所谓的小瑕疵——图片没占位、刷新404、样式错乱、外部资源加载慢——在客户面前会被放得非常大。提前把所有资源本地化、按路由拆包、加上骨架屏、做一条演示故事线这四件事做完你的官网demo至少不会在关键时候掉链子。
返回列表