尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Uni-app + SUMER UI3.0:一套代码快速搭建多端行业模板的完整实践

Uni-app + SUMER UI3.0:一套代码快速搭建多端行业模板的完整实践 简介这是一套面向Uni-app开发者、前端工程师及跨端应用快速搭建需求者的开源UI组件库基于uView生态升级而来深度兼容Vue3语法专为解决多端H5、微信/支付宝小程序、iOS/Android App统一开发效率低、UI适配成本高等痛点而设计。资源包共571个文件涵盖262个可复用Vue组件、191个工具与逻辑JS脚本、76个nvue原生渲染页面、16个SCSS样式主题文件等结构清晰、职责分明压缩包仅1.42MB轻量易集成。已有1481人学习下载社区活跃度高。使用者可直接在HBuilderX中导入使用无代码加密、无后端依赖配套提供精仿微信、支付宝的完整界面源码参考以及商城、直播、地图、出行等20行业模板的组件支撑能力扫码即可预览全端效果是二次开发高还原度商业级应用的理想底座。 去年我接手一个项目的时候需求列了三页纸微信小程序要一版H5要一版App还要一版年底前全部上线。当时团队里前端只有三个人如果按传统方式各自维护一套代码光联调就能把人耗死。后来我把技术方向定在Uni-app上并基于SUMER UI3.0组件库做底层封装整个项目才从三套代码变成一条流水线一套代码写业务编译产物分别发给小程序、浏览器和App端。这篇文章我想把完整链路拆开讲一遍。它不只是一篇组件库的使用说明更多的是一套方法论——为什么选择Uni-app作为前端框架底座、SUMER UI3.0组件库的层级设计逻辑、怎么用它快速拼出不同行业的模板页面以及我在vue3版本和subnvue渲染上踩过的真实坑。如果你正在选型多端框架或者想让团队从“一套业务三套实现”的泥潭里跳出来这篇文章应该能给你一个可落地的参考。1. Uni-app的多端编译机制以及为什么组件库要建立在它之上1.1 一套代码怎么变成三套产物先说最核心的问题Uni-app到底凭什么能做到“一端开发多端运行”它不是把代码翻译成各端原生语言也不是搞个WebView套壳。它是通过一套编译管线把基于Vue语法写的组件和页面分别编译成各个目标平台能识别的工程结构。写业务的时候你用的是view、text、image这类跨端标签编译到微信小程序时编译器会把它们映射成wx-view、wx-text、wx-image编译到H5时映射成标准DOM标签编译到App端时则通过内置的webview渲染或subnvue原生渲染来处理。这么做的好处是业务代码可以尽可能多地复用但代价也很明显你永远不可能在所有端都拿到百分百的原生体验。所以Uni-app提供了条件编译这种机制允许你在同一份代码里写差异逻辑// #ifdef MP-WEIXIN console.log(这一段只在微信小程序端编译) // #endif // #ifdef H5 console.log(这一段只在H5端编译) // #endif // #ifdef APP-PLUS console.log(这一段只在App端编译) // #endif组件库的定位就在这里。SUMER UI3.0这类组件库本质上就是把跨端差异尽可能封装在组件内部。业务侧用一个su-button不需要关心它在微信小程序里是button标签、在H5里是原生button、在App里走什么渲染路径组件内部已经把条件编译处理好了。1.2 Vue3 Vite版本的Uni-app和旧版有什么不一样如果你现在才起步我建议直接上Vue3版本。这不只是Vue版本升级的问题整个工程的构建链路都变了。我最早接触Uni-app还是Vue2 webpack4的时代那时候编辑一个页面热更新慢得让人怀疑人生。切换到Vue3 Vite之后启动速度提升非常明显开发状态下的响应几乎是即时的。还有一个重要变化是组合式API的支持setup语法让逻辑复用比Vue2时代的mixin清晰得多这在组件库的二次开发里特别关键。举一个实际例子。SUMER UI3.0如果本身基于Vue3组合式API重构过那么你派生一个自定义组件的时候可以直接把原组件的核心逻辑抽出来通过useCustomComponent这类组合函数复用而不是靠改源码、复制代码。这点在后文的“二次开发三种改法”里会展开讲。1.3 “微前端框架”“uni-app x”这些新概念和组件库是什么关系社区里讨论的时候容易把几个概念混在一起我尽量用大白话把边界捋清楚。先说微前端。微前端主要解决的是Web端大应用拆分的问题让多个团队独立开发、独立部署最后在同一个页面里组合起来。但uni-app的典型应用场景是小程序和App小程序端的运行环境不允许你在运行时动态加载另一个团队的代码所以“组件库 SubPackages分包”才是这个小程序微前端的务实替代方案。SUMER UI3.0提供的模板和页面片段本质上就是让你在分包维度做业务隔离而不是玩运行时微前端那套。再说uni-app x。这个名字很容易让人以为是Uni-app的某个版本实际上它是uni-app的一条独立技术路线目标是让App端用更接近原生的语言能力来渲染。热搜词里那个“蒸汽模式”我理解是社区对uni-app x某种新编译策略的俗称。我的建议是不要被新名词带跑先判断你的业务到底需不需要那种极致的原生渲染能力。如果只是常规列表、表单、信息展示标准Uni-app 组件库已经足够如果需要非常复杂的动画、高性能Canvas、3D渲染再考虑把个别页面切到uni-app x或原生subnvue方案。组件库在这类新形态下依然不会过时因为无论底层渲染机制怎么变“业务组件复用”这件事永远是刚需。2. SUMER UI3.0组件库的层级设计基础组件、业务组件与模板层2.1 可二次开发组件库的核心设计原则市面上的通用UI组件库很多但拿到手就知道直接用在项目里要么风格对不上要么交互细节不满足业务需求最后还是要改。SUMER UI3.0这个组件库的设计出发点比较务实它不追求提供无穷无尽的API而是把“可二次开发”当作第一原则。什么样的组件库适合二次开发我总结三个标准。第一组件边界清晰。一个组件只做一件事按钮只负责点击反馈弹窗只负责内容承载列表只负责数据渲染。这样你改一个组件的某部分不会牵动其他功能。第二样式和逻辑分离到位。样式全部由CSS变量和主题配置驱动业务逻辑通过props和插槽暴露出来。你在不碰源码的情况下就能通过外层配置覆盖默认行为。第三源码结构足够直白。组件库的源码不应该过分“魔法化”需要让人能读懂、能进去改。SUMER UI3.0的组件目录普遍是扁平清晰的每个组件一个文件夹里面包含主文件、样式文件和类型声明。2.2 三层架构基础组件、业务组件与模板页如果只有一堆基础组件离“快速制作各行业模板”还有距离。SUMER UI3.0把组件划分成三层基础组件层su-button、su-cell、su-icon、su-image、su-badge这类原子化组件负责最基础的UI表达。业务组件层su-search-bar、su-tabs、su-list、su-form、su-product-card这类面向具体场景的组合组件通常由多个基础组件组合而成封装了常见交互逻辑。模板层这不是传统意义上的组件而是一整套页面骨架比如“个人中心模板”“商品列表模板”“审批流程模板”由业务组件按行业惯例组合而成。这个分层带来的一个直接好处是模板的复用维度不再局限于“复制页面再改”而是可以像搭积木一样把业务组件搬来搬去。比如做一个电商项目首页需要搜索、轮播、金刚区、商品瀑布流做一个内容社区可能只需要Tab切换、列表卡片、发布按钮。不同的排列组合就能快速产出风格完全不同的行业模板。2.3 样式定制的实现路径纯业务团队做二次开发时最头疼的往往是“怎么改颜色”。SUMER UI3.0的做法是定义一套主题变量贯穿所有组件。常见的变量定义方式有两种。一种是SCSS变量在编译期处理适合定制整体风格另一种是CSS自定义属性CSS Variables在运行期处理适合动态换肤。// 主题配置文件 theme.scss $su-color-primary: #4f7bff; $su-color-success: #34c27c; $su-color-warning: #f0883a; $su-color-danger: #f3544c; $su-radius-md: 16rpx;如果你只是想让某个页面颜色不一样或者希望在运行时根据用户选择切换主题可以在组件根节点覆盖CSS变量.page-theme-dark { --su-color-primary: #9e7bff; --su-color-bg: #1f1f1f; --su-text-color: #ffffff; }这样组件内部的文本、背景、边框都会自动响应不需要逐个覆盖每个组件的样式。我在实际项目里把这两套机制结合着用全局主题用SCSS变量固定局部章节投放运营活动页时用CSS变量做动态换肤。2.4 组件内部怎么处理多端差异一个跨端组件库的难度不在于写功能而在于让同一个功能在所有端表现一致。举一个最经典的例子按钮的:hover样式。H5端天然支持悬停态但微信小程序端没有鼠标悬停的概念App端根据渲染模式不同表现也不一样。所以组件内部必须区分对待template view classsu-button :class[hoverClass, disabledClass] clickhandleClick touchstarthandleTouchStart touchendhandleTouchEnd slot / /view /template script setup // #ifdef H5 const hoverClass is-hover // #endif // #ifdef MP-WEIXIN || APP-PLUS const hoverClass is-active // #endif /script除了交互差异还有单位差异。rpx是uni-app推荐的响应式尺寸单位在H5端需要编译成px。组件库内部统一使用rpx设计为的就是保证一套token多端不变形。3. 把SUMER UI3.0装进项目从初始化到三端联调3.1 环境准备如果你还没开始接触uni-app我建议先搞定环境再谈组件库。第一步是Node环境。Vue3 Vite版本建议Node 18以上太老的Node版本跑Vite会直接报错这问题我见过不止一次。第二步是编辑器。用HBuilderX最省事它预置了uni-app的编译环境和真机调试能力也可以用VSCode配合cli工程适合习惯原生前端开发的团队。我自己的选择是cli工程 VSCode理由很现实团队里有人写Vue有人写小程序VSCode的生态和通用性更强而且工程化配置eslint、prettier、git hooks能做到和Web项目完全一致。3.2 通过npm安装和uni_modules插件导入SUMER UI3.0的引入有两种常见路径。第一种是npm安装。如果你用cli创建的项目直接npm install sumer-ui3 --save然后在main.js注册import { createSSRApp } from vue import App from ./App.vue import SumerUI from sumer-ui3 import sumer-ui3/dist/style.css export function createApp() { const app createSSRApp(App) app.use(SumerUI) return { app } }第二种是通过uni_modules目录导入。如果组件库在uni-app插件市场有发布可以直接在项目的uni_modules目录下引用好处是可以跟随插件市场做增量更新而且复用easycom自动引入机制页面里直接用组件标签不需要显式import。easycom是uni-app里一个非常方便的特性。开启后你只要在pages.json里配置规则就可以在任意页面中直接使用组件标签编译器会自动按规则引入{ easycom: { autoscan: true, custom: { ^su-(.*): sumer-ui3/components/su-$1/su-$1.vue } } }3.3 全量引入还是按需引入全量引入的优点是省脑缺点是想都不用想的——打包体积变大。小程序有2MB主包大小限制全量引一个完整组件库可能直接击穿包体预算。按需引入的落地方式有两个方向。一个靠easycom机制页面用到了就会自动include对应组件文件类似按需加载另一个靠ES Module的tree-shaking但前提是组件库本身要提供ESM格式的模块产物并且你在写代码时不要用app.use(SumerUI)这种全量注册。我实测下来最可控的方案是首选easycom自动引入让编译器决定加载哪些组件如果某个组件只在后台管理端使用、不在小程序端出现就把它放在分包里通过分包内路径单独引用。这样主包体积能保持在可接受范围。3.4 浏览器提前看效果真机再验差异开发过程中有个高频问题怎么快速看到运行效果尤其是“在浏览器看真机上运行的页面效果”。方法并不神秘。HBuilderX里选择“运行到浏览器”就能直接打开H5版本用于快速核对样式和交互如果想在微信小程序环境看效果需要在微信开发者工具里打开编译产物如果想在手机上看真实效果就用HBuilderX连接真机运行App端会通过基座安装到手机。我的个人习惯是“浏览器起步、开发者工具调差异、真机做最终验收”。先用浏览器把组件和页面调出大概样子因为H5的调试工具最顺手再切到微信开发者工具检查rpx转换、安全区、下拉交互这些端独有的表现最后真机跑一遍重点看性能和白屏问题。如果跳过浏览器直接频繁真机调试效率会低很多。3.5 跑通第一个多端页面所有环境就绪后我用SUMER UI3.0写了一个最基础的页面用来验证整个链路是否通。页面就三个区块顶部导航、搜索栏、列表。template view classpage-demo su-nav-bar title商品列表 fixed/su-nav-bar su-search-bar placeholder搜索商品名称 confirmonSearch/su-search-bar su-list :dataproducts :loadingloading :finishedfinished loadmoreloadMore template #item{ item } su-card :titleitem.name :descitem.desc :imageitem.cover :priceitem.price / /template /su-list /view /template这个页面分别在微信开发者工具、浏览器和Android真机上跑了一遍。差异确实存在比如安全区在iPhone上需要额外适配小程序里的滚动回弹和H5不一样但组件库把大部分基础表现对齐了我只需要在页面层处理少量端差异。从代码量上看这个页面从零手写大概要300行用组件库压缩到了50行左右而且后续模板复用的时候还能继续省。4. 行业模板快速二次开发从页面拆解到模板组装4.1 一套可复用的行业模板应该由什么组成“快速二次开发各种类别各行业模板”这句话听起来很像一个营销口号但落到工程上是有具体方法的。我的理解是行业模板不只是把页面拼出来它需要包含四样东西页面骨架固定的区块顺序和布局结构。业务组件组合哪些页面用哪些组件彼此之间怎么传参。数据协议页面和接口之间的数据模型模板规定了这种模型之后后端按协议返回即可。交互状态加载中、空数据、错误、下拉刷新、触底加载这些状态的统一处理。举个例子电商商品列表模板的骨架是“搜索栏 分类筛选 商品卡片流”数据协议是“分页返回商品列表”交互状态是“商品卡片加载占位图 触底加载更多”。换到新闻资讯模板骨架变成“频道Tab 资讯卡片流”数据协议是“按频道返回文章列表”交互状态多了“顶部刷新”。两者复用度大概在六成以上。4.2 典型行业页面的组件组合模式我把接触过的业务做了个归纳整理成表格。这个表格的价值在于你在接到一个新行业需求时可以直接按行索引找到切入点。行业场景核心组件组合关键改造点电商零售搜索栏 轮播 金刚区 商品卡片流 购物车抽屉营销活动位、商品标签、库存展示政企OA表单 步骤条 审批卡片 附件上传 消息提醒表单校验、审批流程、权限控制物业/社区公告列表 家政服务入口 缴费卡片 工单进度业主信息绑定、工单状态流转在线教育课程列表 视频卡片 学习进度条 订单记录课程分类、试听权限、学习计划数据看板统计卡片 图表容器 筛选器 数据明细列表指标口径、图表联动、权限过滤模板层的价值不是“一键生成”而是给你一个经过验证的起点。拿到一个行业需求后先按这个表格判断属于哪一类直接在对应模板上改动要比从零搭建页面省很多时间。4.3 props配置、插槽扩展、完全重写三种改法怎么选这是二次开发最核心的问题拿到组件或模板后到底应该怎么改我的经验是遵循一个递进原则——能配置就不改源码能插槽就不重写只有业务逻辑实在不匹配时才动手改源码。第一种是props配置。如果只是文案、颜色、尺寸、显示/隐藏之类的调整优先看组件是否暴露了对应props。比如su-card支持show-tag配置你就不需要为了取消一个标签去改组件内部代码。第二种是插槽扩展。当你需要往组件里嵌入额外的内容时优先用插槽。比如列表卡片需要加一个“立即购买”按钮组件默认只在右下角显示价格这时通过具名插槽#footer填充自定义区域su-card :titleitem.name :priceitem.price template #footer view classbuy-btn clickonBuy(item)立即购买/view /template /su-card第三种才是完全重写。当组件的交互逻辑和目标场景差异非常大比如你要把一个普通列表组件改造成多选批量操作列表涉及的改动包括数据状态、选中逻辑、底部操作栏、全选/反选等此时继续用props和插槽硬套只会把代码改成一团乱麻。正确做法是拆出可复用的部分自己重写一个符合需求的业务组件。这一层判断能力我觉得是二次开发的核心竞争力。它考验的不是你会不会写代码而是你能不能一眼识别出“这个改动应该动在哪一层”。4.4 实例快速搭一个行业列表页我用“物业管理工单列表”来演示一次完整组装过程。需求很简单用户查看自己提交的工单状态有“待处理/处理中/已完成”需要按状态筛选列表支持触底加载。实现思路用su-tabs做状态切换绑定当前状态码。用su-list承接工单数据流开启loading和loadmore。工单卡片直接用su-card改造左侧显示工单标题右侧状态用颜色区分。空状态交给su-empty组件处理避免页面白屏。核心代码大致长这样template view classwork-order-page su-tabs :itemsstatusTabs v-modelactiveStatus changeloadFirstPage / su-list reflistRef :dataorders :loadingloading :finishedfinished loadmoreloadMore template #item{ item } su-card :titleitem.title :descitem.createTime :statusitem.statusText :status-typeitem.statusType / /template /su-list su-empty v-if!loading !orders.length text暂无工单 / /view /template调用接口的时候只需要维护好三个状态当前选中的状态、当前页码、列表数据。const loadList async (reset false) { if (loading.value) return loading.value true const { list, total } await fetchOrders({ status: activeStatus.value, page: reset ? 1 : page.value 1, size: 10 }) if (reset) { orders.value list } else { orders.value orders.value.concat(list) } page.value reset ? 1 : page.value 1 finished.value orders.value.length total loading.value false }整个页面从拿需求到跑通大概用了不到两个小时。这中间最浪费时间的是确认“状态”字段的枚举值而不是写UI。所以一个好的模板除了代码还得把数据协议整理干净这才是“快速二次开发”的真正含义。5. 踩坑实录subnvue、渲染性能与跨端差异5.1 subnvue不是银弹它的适用边界在哪里很多用uni-app做App端的人都会被建议性能不行就上subnvue。subnvue的机制是让某个页面脱离webview渲染直接走原生渲染栈体验接近原生应用。听起来很美好但实际落地的时候有几个问题容易被忽略。第一subnvue页面和普通vue页面的通信成本更高。页面从普通模式切到subnvue后部分uni API的调用方式会受限制比如uni.showToast在某些版本上可能表现不一致你得改用原生弹窗。第二subnvue页面不能使用部分Web端特性。因为它是原生渲染CSS的能力会被裁剪很多H5端没问题的高级布局在subnvue里不支持。如果团队对CSS Grid、复杂动画依赖较深贸然切subnvue等于给自己挖坑。第三组件库的兼容性。基于webview渲染设计的组件库在subnvue页面里不一定能完全复用。SUBME UI3.0虽然做了大量适配但我仍然建议只有那些高频、低复杂度的页面比如首页、列表页才走subnvue方案涉及复杂图表和大量动态交互的页面留在普通webview渲染更稳定。我的落地策略是列表、详情这类信息流页面优先考虑subnvue提升流畅度有复杂表单、图表、富文本展示的页面保持默认渲染。先压测再决定而不是一听说subnvue就整站切换。5.2 白屏和组件不渲染先查引用再查样式最后查生命周期实际开发中组件不渲染或者白屏是最常见的问题。我分享一套自己的排查链路效率高很多。第一步查引用。用easycom自动引入的组件如果出现标签不渲染先看目录结构是否符合命名规则。easycom的默认规则是components/组件名/组件名.vue如果你的文件名和目录名不一致就会静默失败。第二步查样式。很多组件不显示不是没渲染而是被样式盖住了。比如position: fixed的底部按钮如果父容器设置了overflow: hidden或transformfixed就会失效。这种问题在H5端偶尔出现在小程序端更容易被忽略。第三步查生命周期。在Vue3 uni-app的组合式API下有个常见的坑onLoad是uni-app的页面生命周期不是Vue的mounted。很多同学把数据请求放在mounted里但小程序端页面初始化时序和H5并不完全一致容易导致某端不触发。import { onLoad } from dcloudio/uni-app onLoad((query) { // 这里是页面加载时调用的query里可以拿到页面参数 fetchData(query.id) })5.3 长列表渲染的性能优化长列表是移动端性能的重灾区。一个电商商品列表几千条数据不做任何优化直接在App端滑动会掉帧小程序的setData性能也会吃紧。我用SUMER UI3.0的su-list组件做长列表时通常叠加三件事。第一图片懒加载。su-image组件内部支持懒加载机制图片只有进入到可视区域附近才会去请求。只这个优化就能把列表首屏加载时间缩短一截。第二分页渲染 触底加载。不要在页面里一次性拿完所有数据。每页10到20条是一个合理的区间拿到的数据通过concat追加到列表后面并保证列表组件的loadmore机制在接近底部时触发下页请求。第三避免在列表项内写复杂计算。列表项渲染频率极高任何计算函数都会在高频渲染时拖慢性能。可以预先把状态字段变换成展示文本、样式类名都计算好放到数据层完成而不是在template里调用方法。比如工单状态“1、2、3”可以预先映射成“待处理、处理中、已完成”并同时算好对应的statusType模板里只做简单绑定。5.4 Vue3新特性在uni-app里的注意点Vue3带来的新特性很香但在uni-app环境里要注意边界。Teleport可以在Vue3 Web项目里把节点挂载到body下但uni-app的视图层次并不是标准DOM树尤其是小程序端Teleport的挂载目标无法直接指向#app之外的节点使用要非常克制。Fragment多根节点组件在H5端问题不大但在小程序端如果组件根节点有多个渲染可能被导致警告甚至异常。遇到这个问题时最简单的方法是给组件的template包一层view。模板引用ref在Vue3里通过ref(null) 模板内refxxx来获取但在uni-app里如果你要获取的组件实例是跨端的类型上要考虑到不同平台实例方法不一致的问题。最稳妥的方式是只调用组件库公开的实例方法避免直接操作节点。const listRef ref(null) // 调用组件暴露的实例方法 const resetList () { listRef.value?.reset() }6. 长期维护视角组件库升级与团队协作6.1 版本升级的冲突点用第三方组件库最怕的是版本更新带来的破坏性变更。Uni-app本身升级也好SUMER UI3.0发新版也好都可能导致你二次开发的代码失效。我的建议分三层。第一层锁版本。package.json里固定组件库版本不要随便用^和~自动更新尤其是上线前。第二层隔离定制代码。如果确实要改组件源码尽量用“包裹扩展”而不是“直接改源文件”的方式。比如新建一个SuOrderCard.vue在内部引用原组件再套一层这样升级组件库时这些业务派生组件依然稳定。第三层关注更新日志。组件库发布新版本后先在一个测试分支里升级跑一遍全量页面回归重点看样式变量有没有改名、组件props有没有废弃。6.2 组件二次开发时的目录约定与文档沉淀团队协作时最怕的是每个人都有自己的二次开发习惯。有的人直接改组件库源文件有的人复制组件到业务目录里改有的人用props透传最后代码库里的同一套组件就有三四个版本。我目前用的目录约定是src/ components/ business/ # 业务定制组件基于SUMER UI3.0包的封装 SuOrderCard/ SuOrderCard.vue README.md pages/ orders/ index.vue # 页面只引用 business 或组件库组件不直接改库源码每个业务组件目录下都放一个README.md哪怕只有三五句话也要写清楚“基于哪个版本、改了什么、为什么不能直接用原组件”。文档不需要写成正式API文档但一定要能减少后人维护时的时间浪费。6.3 关于组件库使用的一点点心里话最后分享几条我在实际项目中沉淀下来的经验不一定适用所有团队但大概率能帮你在选择和使用组件库的时候少走弯路。第一不要试图用一个组件库解决所有问题。组件库负责的是80%的通用场景剩下20%的差异化需求该自研就自研。强行给组件库加各种复杂配置只会让组件越来越臃肿变得难以维护。第二模板复用是有边界的。跨行业模板的复用率能做到70%已经很好剩下的30%包括特定的数据字段、行业术语、视觉差异化这些是必须投入的设计成本。指望一个模板“百变金刚”最终结果是模板既不适合A行业也不适合B行业。第三多端开发最重要的不是“一套代码跑所有端”这个口号而是把你的精力重新分配只写一遍业务逻辑把省下来的时间投入到真正的细节打磨上。SUMER UI3.0在我这里最大的价值不是省了多少行代码而是它让我有底气承诺产品“三端同步上线”这在以前是想都不敢想的事。如果你正在组件的选型阶段不妨多花点时间看它的源码结构、主题机制和组件的可扩展性这些比文档里写了多少组件更重要的是它能陪你走多远。本文还有配套的精品资源点击获取
返回列表