【Fantastic-mobile】🌟 给你来点不一样的 H5 框架 🌟

自成一派的 H5 框架

Fantastic-mobile 不是一个新项目,我在 2024 年 6 月的时候就发布了第一个版本,只是一直没正式做过宣传。

经过近一年的陆续迭代,这次正式从 0.x 版本升级到了 1.0 版本,觉得也是时候宣传一波了。

有哪些轮子

如果你有在关注 Vue 生态的 H5 模板,相信你一定见过下面这几个项目:

它们是社区里人气比较高的项目,也包括前几个月刚发布的 MobVue

但它们好像没什么区别?

它们几乎都用到了:

近乎于 100% 相同的技术栈,似乎只是将这些插件/库集成进一个 Vue 工程中,并进行了一些初始化的配置,然后就形成了各自的模板。

这真的有意义么?

毋庸置疑,当然是有意义的。即便是让一个经验丰富的 Vue 开发者从零开始,自行将上述这些插件/库自行集成进一个空白的 Vue 工程,可能也需要花费 2-3 天的时间,更别说新手小白了。

但就只能做这些了么?

为什么重新造轮子(痛点)

在没有开发 Fantastic-mobile 之前,我也用过这些人气模板进行项目开发。

使用过程中,最大的痛点就是,顶部导航栏和底部标签栏需要我自行实现。


虽然有些模板在页面上层提供了一个 Layout 布局组件(也就是二级路由中一级路由的组件,类似于父组件),在 Layout 组件中封装了顶栏和底栏,但依旧很难使用。

比如有个表单页,它的提交按钮是需要放在顶栏右侧的,要如何实现这个按钮?(以掘金发布沸点这个页面做示例)

是在 Layout 组件中实现么?那就会增加很多业务代码。首先需要根据路由判断按钮是否显示;其次按钮有 disabled 状态,这个状态肯定是从子组件里来的,要怎么拿到也是个问题;然后还得处理按钮点击后和子组件的通信。

如果只是一两个页面还好,但如果这样的页面很多,Layout 组件的代码量就会变得很大,而且不利于维护。


也有模板没有二级路由,不存在 Layout 布局组件,它直接封装了两个组件,一个 Header 组件,一个 Footer 组件。需要用到的页面引入这两个组件就行,并且组件提供了一些插槽,方便做一些扩展。

但也带来另外一个问题,比如顶栏通常是 fixed 固定在页面顶部的,那当前页面就需要手动设置 padding-top 或者 margin-top ,不然页面内容就可能会被遮挡。如果顶栏高度是动态的,那可能还得动态去计算 padding-topmargin-top 的值。

再比如顶栏默认是显示的,当向下滑动时需要隐藏,向上滑动时则显示,这就需要在业务页面里手动实现这些逻辑,并且多数情况下会与业务代码耦合在一起。

虽然这些实现起来可能并不复杂,但多少还是会增加开发心智,因为一旦对顶栏或者底栏进行的改动,必须检查下是否对页面会造成影响。

Fantastic-mobile 是怎么做的

针对上面提到的痛点,我做了一些方案尝试,比如通过 <teleport> 组件将子组件里的按钮发送到 Layout 组件中提供的位置,但存在一些边缘情况的bug。

最终确定的方案就是提供一个 FmPageLayout 组件,它并没有采用二级路由那种方案,而是直接应用在具体页面中的一个组件。它的使用方式就是在页面最外层包裹一层 FmPageLayout 组件就行。

html 复制代码
<template>
  <FmPageLayout :navbar="false" tabbar copyright>
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

那这个组件是怎么解决上面提到的痛点呢?我们一个个来看。

顶栏插槽

通过提供预设的插槽,可以很方便的实现顶栏的定制,并且完全不需要考虑组件通信的问题,因为它都在当前页面里。

html 复制代码
<template>
  <FmPageLayout navbar>
    <template #navbar-start>
      <FmSwitch v-model="checked" />
    </template>
    <template #navbar-end>
      <FmButton size="sm" @click="show = true">
        操作按钮
      </FmButton>
      <van-action-sheet v-model:show="show" :actions="actions" @select="onSelect" />
    </template>
    <div class="flex flex-col gap-4 p-4">
      <div>
        Switch: {{ checked }}
      </div>
      <FmButton @click="router.back()">
        返回
      </FmButton>
    </div>
  </FmPageLayout>
</template>

顶栏模式

提供了多种顶栏展示模式。

html 复制代码
<template>
  <FmPageLayout navbar navbar-mode="static">
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

<template>
  <FmPageLayout navbar navbar-mode="fixed">
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

<template>
  <FmPageLayout navbar navbar-mode="show-hide-fixed">
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

<template>
  <FmPageLayout navbar navbar-mode="sticky">
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

更多玩法

因为有了 FmPageLayout 组件,就可以扩展出很多玩法特性。

导航栏预设按钮

提供了一些常用的按钮,比如"主页"、"返回"、"多语言切换"等。并且可以根据业务需要,自行增加这些预设按钮。

html 复制代码
<template>
  <FmPageLayout navbar :navbar-start-side="['home']" :navbar-end-side="['i18n']">
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

导航栏样式

自定义导航栏

可以完全自定义导航栏,比如导航栏的背景色、导航栏的高度、导航栏的标题等。并且当高度变化时,不再需要手动计算 padding-topmargin-top 的值。

html 复制代码
<template>
  <FmPageLayout navbar @scroll="onScroll">
    <template #navbar>
      <div
        class="h-[80px] flex flex-center gap-2 bg-([url('https://picsum.photos/375/60')] cover center no-repeat) text-light text-shadow text-shadow-color-dark shadow transition-all transition-all-500" :class="{
          'h-[60px]!': scrollTop > 50,
        }"
      >
        头部导航
      </div>
    </template>
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

底部标签栏

我提供了一个全局的配置文件,可以将底部标签栏提前配置好。

它很像小程序在 pages.json 中配置的 tabBar 选项,没错,这块就是借鉴了小程序的设计。

ts 复制代码
const globalSettings: Settings.all = {
  tabbar: {
    list: [
      {
        path: '/feature/',
        icon: 'i-ic:sharp-auto-awesome',
        activeIcon: 'i-ic:twotone-auto-awesome',
        text: '特色',
      },
      {
        path: '/',
        icon: 'i-ic:sharp-home',
        activeIcon: 'i-ic:twotone-home',
        text: '主页',
      },
      {
        path: '/user/',
        icon: 'i-ic:baseline-person',
        activeIcon: 'i-ic:twotone-person',
        text: '我的',
      },
    ],
  },
}

然后在需要启用底栏的页面开启即可。

html 复制代码
<template>
  <FmPageLayout tabbar>
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

多套底部标签栏

与小程序设计不同的是,我提供了多套底部标签栏的配置,可以为不同的页面设置不同的底部标签栏。

ts 复制代码
const globalSettings: Settings.all = {
  tabbar: {
    list: [
      {
        name: 'default',
        list: [
          {
            path: '/feature/',
            icon: 'i-ic:sharp-auto-awesome',
            activeIcon: 'i-ic:twotone-auto-awesome',
            text: $t('tabbar.default.feature'),
          },
          {
            path: '/',
            icon: 'i-ic:sharp-home',
            activeIcon: 'i-ic:twotone-home',
            text: $t('tabbar.default.index'),
          },
          {
            path: '/user/',
            icon: 'i-ic:baseline-person',
            activeIcon: 'i-ic:twotone-person',
            text: $t('tabbar.default.user'),
          },
        ],
      },
      {
        name: 'second',
        list: [
          {
            path: '/',
            icon: 'i-mdi:flower',
            text: $t('tabbar.second.flower'),
          },
          {
            path: '/',
            icon: 'i-mdi:grass',
            text: $t('tabbar.second.grass'),
          },
        ],
      },
    ],
  },
}

然后在页面指定使用哪套即可。

html 复制代码
<template>
  <FmPageLayout tabbar tabbar-name="second">
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

自定义标签栏

甚至可以完全自定义顶部标签栏,比如控制按钮显示、设置毛玻璃效果等。

html 复制代码
<template>
  <FmPageLayout tabbar tabbar-class="bg-[hsl(var(--background))]/80 backdrop-blur-sm">
    <template #tabbar>
      <div class="flex-center flex-1">
        <FmIcon name="https://fantastic-admin.hurui.me/logo.svg" class="text-8" />
      </div>
      <div v-show="checked" class="flex-center flex-1">
        <FmIcon name="https://fantastic-mobile.hurui.me/logo.png" class="text-8" />
      </div>
      <div class="flex-center flex-1">
        <FmIcon name="https://one-step-admin.hurui.me/logo.png" class="text-8" />
      </div>
    </template>
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

除此之外

除了顶栏和底栏,FmPageLayout 组件还提供了返回顶部、版权信息、记忆当前滚动位置等特性。

也是可以通过 props 传入一键开启。

html 复制代码
<template>
  <FmPageLayout back-top copyright saved-position>
    <!-- 页面内容 -->
  </FmPageLayout>
</template>

无限可能

最重要的一点是,FmPageLayout 这个组件并非三方插件,所以完全可以直接修改源码实现二次扩展,满足开发者更多场景需求。

锦上添花的特性

介绍完了 Fantastic-mobile 最核心的特性,来介绍一些锦上添花的特性。

技术栈统一

与文章开头提到的那些模板,保持了基本一致的技术栈,如果你使用过那些模板,那么上手 Fantastic-mobile 会非常容易。

或者说,迁移到 Fantastic-mobile 也会变得很容易🤣

可替换三方组件库

Fantastic-mobile 默认集成了 Vant ,但并不强制要求必须使用 Vant ,你可以轻松替换为其他组件库。例如 Varlet 或 NutUI 。

该特性得益于 shadcn-vue ,框架封装了部分 shadcn-vue 组件,以便满足框架自身的需要。

大量内建组件

除了封装 shadcn-vue 组件,还提供了一些业务中常用的组件,比如数字动画、跑马灯、弹簧抽屉等。

篇幅有限

还有更多特性无法一一介绍,感兴趣的可以前往 Fantastic-mobile 并访问演示站点自行体验。

最后

引用官网里的一句话:

是模板,更是框架

Fantastic-mobile 与市面上大部分移动端 H5 模板不同之处在于,它针对通用场景提供了一套标准且易于扩展设计,通过简单的配置即可轻松完成页面的设计和布局。同时也提供了一些常用的组件和工具函数,让开发者可以更加专注于业务逻辑的开发。

这也是为什么我自称为「框架」,而不仅仅是「模板」的原因。

当然如果你在使用过 Fantastic-mobile 后,认为它还达不到你心中框架的标准,也请告诉我有哪些可改进的地方,因为最终的目标是希望 Fantastic-mobile 能够成为你的得力助手,让你的开发工作高效且愉快

相关推荐
CF14年老兵4 分钟前
为什么停止在小型项目中使用 TypeScript?
前端·typescript
Walk Me Home4 分钟前
开源语音合成模型SparkTTS使用
开发语言·前端·javascript
Java陈序员8 分钟前
一个面向中小企业快速开发平台框架!
vue.js·spring boot·mysql
2501_915373888 分钟前
Vue.js 入门教程
前端·javascript·vue.js
WindrunnerMax10 分钟前
从零实现富文本编辑器#3-基于Delta的线性数据结构模型
前端·javascript·github
前端李白10 分钟前
🛫历经一个月,免费图片压缩工具站上线了!
前端·后端
掘金安东尼13 分钟前
🧭 前端周刊第410期(2025年4月14日–20日)
前端·面试·github
夜羽rancho21 分钟前
二分查找,其实就这些了
前端·算法
Face21 分钟前
JavaScript基础
前端·javascript
宇宙的有趣22 分钟前
Codegen 加速开发:从数据结构到模版代码
前端