@melt-js/demo-vue2
v2026.11.9
Published
Vue 2 的 hel 宿主(消费方)示例:`preFetchLib` 从 unpkg 加载 [`@melt-js/comps-vue2`](../comps-vue2),页面里同时直接复用 `tpl-vue2-admin-ele` 的本地源码,并用 `preFetchLib` 演示 [`@melt-js/libs-utils`](../libs-utils) / [`@melt-js/libs-lodash`](../libs-lodash) 两个远程库的方法。
Readme
@melt-js/demo-vue2
Vue 2 的 hel 宿主(消费方)示例:preFetchLib 从 unpkg 加载 @melt-js/comps-vue2,页面里同时直接复用 tpl-vue2-admin-ele 的本地源码,并用 preFetchLib 演示 @melt-js/libs-utils / @melt-js/libs-lodash 两个远程库的方法。
本包由 demo-vue2-ele 拷贝而来,只把消费的远程组件换成 comps-vue2、端口改为 30040,页面结构与示例保持不变。
页面使用 vue-router(hash 模式) 把示例拆成十一个可切换的页面,顶部导航栏同时显示当前示例的简介,示例区右上角有全屏按钮(只放大当前示例的组件预览区,基于 vue-fullscreen 的 pageOnly + teleport 模式)。
| 项 | 值 |
| --- | --- |
| npm 包名 | @melt-js/demo-vue2 |
| unpkg 入口 | https://unpkg.com/@melt-js/demo-vue2/dist/index.html |
| 端口 | 30040 |
| 消费的远程组件 | comps-vue2(https://unpkg.com/@melt-js/comps-vue2/hel_dist/hel-meta.json) |
| 消费的远程库 | libs-utils、libs-lodash(线上同样指向 unpkg 的 hel-meta.json) |
| 路由 | [email protected],hash 模式 |
| 全屏 | [email protected](legacy),pageOnly + teleport(不调用浏览器原生全屏) |
示例路由
| 路由 | 导航文案 | 内容 |
| --- | --- | --- |
| #/ | 简介 | demo 概览:远程依赖、端口、远端地址与示例入口 |
| #/remote-comp | 远程组件 | comps-vue2 的 App(内部再依赖 HelloWorld),红色边框区域内渲染 |
| #/ranking | 排行榜 | comps-vue2 的 TierRanking 排行榜:拖拽排序、上传图片、评级编辑、IndexedDB 持久化、导出图片 |
| #/butterfly | 蝴蝶 3D | comps-vue2 的 Butterflies3d:CSS 3D 天空盒 + 七只蝴蝶的扇翅 / 飘动 / 绕圈动画,paused / speed 可控制 |
| #/cat-face | 小猫笑脸 | comps-vue2 的 CatFace:纯 CSS 绘制的卡通猫脸,悬停 / active 时耳朵、瞳孔、腮红与笑嘴变化 |
| #/bird | 小鸟 | comps-vue2 的 BirdSvg:SVG 卡通小鸟,扇翅、浮动、眼珠张望与影子缩放,支持 paused / speed |
| #/frog | 青蛙表情 | comps-vue2 的 FrogExpressions:12 个纯 CSS 青蛙表情,可整体暂停 |
| #/whale | 鲸鱼跟随 | comps-vue2 的 WhaleFollow:44 片 SVG 切片带 z 延迟跟随鼠标,可暂停 / 回到中央 |
| #/binding | v-model 联动 | 本地 ModelSelect 下拉框 + 公共属性面板:组件 input 写回面板,面板改值写回组件 |
| #/libs | 远程 libs | libs-utils / libs-lodash 的调用结果 |
| #/tpl-comp | tpl 源码 | 通过 workspace 链接直接复用 tpl-vue2-admin-ele 的 Hamburger |
约定:
- hash 模式:demo 的构建产物会通过 unpkg 上的
dist/index.html打开,history 模式在那种静态文件路径下会 404。 - 路由清单在
src/router/index.js,每条路由的meta.title/meta.description同时驱动导航栏 tab 与下方那行简介;新增示例只要加一条路由。 - 全屏按钮只把当前示例标记为
data-demo-preview的组件预览区送进全屏,页面标题、简介、说明与页脚都留在屏幕外;全屏借用vue-fullscreen4.x legacy 的pageOnly + teleport模式:预览区临时挂到 body、用 fixed 铺满视口,退出时还原到页面原位置,不调用浏览器原生 Fullscreen API(iframe 内也可用)。预览区右下角提供「退出全屏」浮层按钮,Esc 也可退出;切换路由时会自动退出并还原。 - 需要全屏的示例在组件预览区外包一层
<demo-preview>;简介页没有预览区,在路由meta里标记fullscreen: false,工具栏不显示全屏按钮。
文件结构
demo-vue2/src
├── App.vue # demo 外壳:导航栏 + 示例舞台(含全屏按钮)+ router-view
├── components/
│ ├── DemoNavbar.vue # 顶部导航栏:示例 tab + 当前示例简介
│ ├── DemoPreview.vue # 组件预览区:全屏目标 + 「退出全屏」浮层按钮
│ ├── LevaPlayground.vue # 单个示例的 leva 实验台:组件 + schema → PropsPlayground
│ ├── ModelSelect.vue # v-model 示例组件:value prop + input 事件,组件内也能改值
│ └── ScreenfullButton.vue # 示例区全屏按钮(无 UI 组件库依赖)
├── configs/app.js # demo 展示信息(名称 / 端口 / 远端地址 / 仓库链接)
├── configs/modelSelect.js # v-model 示例的 schema / presets / 舞台样式
├── router/index.js # 示例路由(hash 模式)
├── styles/ # base.css(变量与重置)+ demo-shell.css(外壳样式)
├── views/ # OverviewView / RemoteCompView / RankingView / ButterflyView / CatFaceView / BirdView / FrogView / WhaleView / BindingView / LibsView / TplCompView
└── libs/remoteLibs.js # 两个远程 libs 的预加载(Promise 复用)关键流程
src/main.js:bindVueRuntime({ Vue })把宿主 vue 挂到window.Vue,远程组件 external 的vue会复用这一份。src/main.js:preFetchLib('comps-vue2', { custom: { host } })预加载远程组件;hel 组名(comps-vue2)与 scoped npm 包名(@melt-js/comps-vue2)解耦,因此用custom.host指向 unpkg 上的hel_dist/hel-meta.json。host按process.env.NODE_ENV分支:生产走 unpkg,开发走http://localhost:20040。src/main.js+src/libs/remoteLibs.js:入口处和远程组件一起并行预加载两个远程库(loadRemoteLibs()内部是Promise.all+preFetchLib,重复调用复用同一个 Promise)。页面里直接调用它们的方法展示结果:libs-utils:num.canBeNum/num.random、regs.en/regs.enSnake、myMod.sayHelloToHellibs-lodash:chunk/uniq/camelCase/orderBy、myUtils.regs.enOrNum、VERSION
两个库都不在宿主的
package.json依赖里(lodash 也没有安装),全部来自远程产物。host 同样按环境切换:生产指向 unpkg 的hel-meta.json,开发指向各自 dev server(http://localhost:10010/http://localhost:10020),并用skipFetchHelMeta跳过 dev server 上不存在的hel-meta.json、直接解析index.html里的入口脚本。src/router/index.js:#/libs路由的组件工厂先await loadRemoteLibs()(复用入口预加载的同一个 Promise,通常已 resolve),再动态import示例组件,组件内直接读getRemoteLibs()的已加载结果;其余示例同样按路由懒加载。src/App.vue:导航栏 + 示例舞台;示例舞台持有router-view与全屏按钮,ScreenfullButton的目标是当前页面DemoPreview渲染的[data-demo-preview]。src/views/RemoteCompView.vue/RankingView.vue/ButterflyView.vue/CatFaceView.vue/BirdView.vue/FrogView.vue/WhaleView.vue:每个页面用<LevaPlayground>把远程组件和它的propsSchema.json包进PropsPlayground(左侧组件预览 + 右侧属性面板);渲染的组件是comps.App/comps.TierRanking/comps.Butterflies3d/comps.CatFace/comps.BirdSvg/comps.FrogExpressions/comps.WhaleFollow(静态导入只拿到 hel-lib-proxy 的空壳代理,真正的组件代码由入口的preFetchLib载入)。
属性面板(PropsPlayground)
- 每个组件示例 tab 都通过公共组件
LevaPlayground.vue包一层 leva 实验台:左侧渲染组件,右侧是libs-vue2-leva的PropsPanel,面板值通过v-bind实时写回组件;不再有单独的「属性面板」tab。 - 组件自己的
v-model/value也会反向同步:PropsPlayground自动识别组件的model选项(默认为value+input,也支持modelValue/update:modelValue),监听模型事件并把新值写回同一份values,PropsPanel再refresh()控件;值相同时跳过,不会形成回环。自定义契约可用models(如{ prop: 'selectValue', event: 'change' })或 schema 里的model/modelEvent显式声明。 - 面板来自远程包
libs-vue2-leva(Vue 2 专用,和libs-vue3-leva各自维护),提供PropsPanel(schema → tweakpane 控件)和PropsPlayground(components + schemas 实验台),本身不内置任何组件或 schema。 - 入口
main.js里preFetchLib('libs-vue2-leva', ...)预加载;LevaPlayground再用import('@melt-js/libs-vue2-leva')取PropsPlayground,schema 从comps-vue2源码里 deep import。 LevaPlayground支持presets(数组 / 对象等面板不生成控件的 props,也用于覆盖初始值)、listeners(组件事件)、slotHtml(插槽用 HTML 填充)和stage-style(预览舞台尺寸 / 背景)。- 面板包在 workspace 里(真实路径不在 node_modules 下),所以
vue.config.js把libs-vue(2|3)?-?leva从 eslint 规则中排除。 - 本地联调:
pnpm comps-vue2:dev(20040)+pnpm libs-vue2-leva:dev(10030)后打开 http://localhost:30040;boolean是复选框、number是数字框 / 滑杆、颜色字符串是取色器,改动实时写回v-bind。 - 新增组件时在 comps-vue2 里给 props 补
/** @description ... */注释并在playground.config.mjs里登记;生成组件目录下的 schema 后,在对应页面 import 它并传给<LevaPlayground>即可。 array/object这类复杂 props 暂不生成控件,组件继续使用默认值(需要时用presets传入);只在mounted读取的 props(如storageKey)改完点「重新挂载」。
v-model 双向联动(#/binding)
- 页面左侧是本地示例组件
ModelSelect.vue:普通valueprop +input事件,选中值也可以由组件内部的「组件内切到下一个」按钮改掉,完全不感知属性面板。 - 右侧仍由公共
PropsPlayground渲染:它从组件的model选项 / props 推断出value+input,把input的参数写进面板共用的values;面板的value控件通过refresh()显示新值。反过来,面板改值仍走v-bind写回组件。两边是同一份状态,所以不会出现「左侧选了 React,右侧还停在 Vue 3」。 - 页面顶部的状态条通过
PropsPlayground的change事件显示最近一次改动来源(source: 'component' | 'panel')和改动的字段;该事件和update:values由LevaPlayground继续向上转发,宿主可用来做日志或持久化。 - 不需要为联动写
@input:LevaPlayground会把组件、schema、presets 直接交给PropsPlayground,模型识别与回写都在公共组件层完成。遇到selectValue/change这类自定义模型,传:models="{ prop: 'selectValue', event: 'change' }"或给 schema 加model: true, modelEvent: 'change'即可。
排行榜远程组件(TierRanking)
- 组件源码在
comps-vue2/src/components/TierRanking,由src/components/index.js与libProperties一起导出,宿主只需preFetchLib后挂载,不打包它的代码与样式。 - 组件能力:拖拽排序 / 跨评级拖动 / 拖到删除区删除、上传图片(自动压缩)、评级改名 / 改色 / 增删、显示图片名、固定评级高度、导出图片(按需加载 html2canvas)、IndexedDB 持久化(
persist/storageKey可关可换)。 - 本地联调:
pnpm comps-vue2:dev(20040)的产物直接可用,打开 http://localhost:30040/#/ranking。 - 线上:远端
hel-meta.json会同时下发排行榜所在的 chunk(webpack 把组件拆成了独立 chunk),因此生产构建(远端走 unpkg)同样能渲染#/ranking;只有远端版本早于排行榜组件时,页面才会显示「远端产物没有导出 TierRanking」的提示。 - 排行榜状态存在 IndexedDB(库名
tier-ranking-db,storageKey=demo-vue2-ranking),用组件自带的「重置排行榜」即可恢复默认评级。
3D 蝴蝶远程组件(Butterflies3d)
- 组件源码在
comps-vue2/src/components/Butterflies3d,抽取自一个 CodePen 的 SVG 3D 蝴蝶 demo;原始 HTML / CSS 放在该目录的source/。 - 组件能力:CSS 3D 天空盒 + 七只蝴蝶的公转 / 飘动 / 扇翅动画,纯 CSS 关键帧驱动;
paused暂停、speed倍速、butterflies逐只调整参数、wingTexture换翅膀纹理。组件不修改宿主body,自己裁剪场景,放在任意高度的容器里即可。 - 本地联调:
pnpm comps-vue2:dev(20040)直接可用,打开 http://localhost:30040/#/butterfly;页面上的「暂停动画」「0.5× / 1× / 2×」分别演示paused与speed两个 prop。 - 线上:远端
hel-meta.json会带上蝴蝶组件所在的 JS / CSS 产物,生产构建(远端走 unpkg)同样可渲染;只有远端版本早于该组件时,页面才显示「远端产物没有导出 Butterflies3d」的提示。 - 全屏按钮只放大
Butterflies3d的舞台(<demo-preview>内),暂停 / 倍速控件和说明文字留在舞台外。
纯 CSS 猫脸远程组件(CatFace)
- 组件源码在
comps-vue2/src/components/CatFace,抽取自同一 CodePen 合集的 cat-face;原始 HTML / LESS 放在该目录的source/。 - 组件能力:纯 CSS 绘制(圆角、旋转、边框、径向渐变),没有图片 / SVG / canvas;hover 时耳朵立起、瞳孔放大、眼皮抬起、腮红浮现、嘴角上扬,
activeprop 可把表情锁定。 - 本地联调:
pnpm comps-vue2:dev(20040)直接可用,打开 http://localhost:30040/#/cat-face;页面上的「摸一摸小猫」按钮演示activeprop,鼠标悬停演示原生 hover 效果。 - 线上:远端
hel-meta.json会带上猫脸组件所在的 JS / CSS 产物,生产构建(远端走 unpkg)同样可渲染;只有远端版本早于该组件时,页面才显示「远端产物没有导出 CatFace」的提示。
其余动物组件(BirdSvg / FrogExpressions / WhaleFollow)
#/bird(BirdSvg):SVG 小鸟,扇翅 / 浮动 / 眼珠张望 / 影子缩放全部是 CSS 关键帧;paused暂停、speed倍速。#/frog(FrogExpressions):12 个纯 CSS 青蛙表情,画廊在窄屏自动 2~3 列;paused可整体暂停。#/whale(WhaleFollow):44 片 SVG 切片带 z 延迟跟随鼠标,paused暂停,「回到中央」调用组件暴露的reset()。- 三个组件的源码都在
comps-vue2/src/components下,原始 HTML / CSS / JS 与许可证保留在各自source/;本地联调同样是先pnpm comps-vue2:dev(20040)。 - 线上渲染规则与前面的组件一致:远端版本包含组件即可用,版本较旧时页面显示「远端产物没有导出 …」的提示。
本地开发
# 终端 1:起远程组件(20040)
pnpm comps-vue2:dev
# 终端 2、3:起两个远程库(10010 / 10020,页面上的 libs 演示区需要)
pnpm libs-utils:dev
pnpm libs-lodash:dev
# 终端 4:起宿主(30040)
pnpm demo-vue2:dev打开 http://localhost:30040 。libs 的预加载在入口处 Promise.all 里,和远程组件一起完成,所以三个 dev server 都要先起好;缺任意一个都会在控制台打印 loadApp err,页面不会挂载。
构建 / 发布
pnpm demo-vue2:build # 产出 dist/
pnpm --filter @melt-js/demo-vue2 run publish:stage # build → npm stage 暂存,等待 2FA 审批vue.config.js在生产构建时使用相对publicPath,发布后 unpkg 上的dist/index.html可直接加载同目录资源;hash 路由同样可用。process.env.NODE_ENV由 vue-cli 静态注入,生产包里只会保留 unpkg 的地址;线上从 unpkg 加载 libs 的前提是@melt-js/libs-utils/@melt-js/libs-lodash已发布。files白名单只发布dist/与 README。
下载示例
示例区工具栏(全屏按钮左侧)的「下载示例」会按当前页面下载一份单文件「HTML + CDN」示例:
Vue 与 hel-micro 走 CDN,组件由 preFetchLib 在运行时从 unpkg 拉取,双击即可打开,用于演示 / 推广 hel 的接法。
- 模板:
src/configs/downloadExampleTemplate.js - 拼装:
src/configs/downloadPage.js(替换组件名 / 参数 / 背景,生成hel-micro-<组件名>.html) - 数据:
src/configs/downloadExamples.js(路由 →comps-vue2的组件与参数,新增示例页在这里补一条) - 没有远程组件的页面(简介 / libs / 模板源码等)下载
FALLBACK_EXAMPLE
