npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lovelymai/app-router

v1.1.0

Published

A multi-stack route designed for mobile

Readme

@lovelymai/app-router

一个专为移动端应用设计的 Vue 3 多堆栈路由器,致力于提供类原生应用的页面导航体验

核心特性

  • 轻量级 — 零依赖
  • 类原生体验 — 多标签独立路由栈,每个标签拥有自己的页面历史堆栈,切换标签时保留页面状态
  • 无缝切换 — 标签切换不丢失滚动位置或组件状态,消除传统 Web 路由器的页面重绘
  • 全局滑动返回 — 提供全局滑动返回手势动画,带来完全复刻原生应用的体验
  • 组件即用即载 — 只加载当前需要显示的组件,其他标签页的根组件在首次切换到该标签时才加载,首屏更快
  • 全局容量限制 — 可设置 limit 控制整个路由系统同时缓存的最大组件数量,超出时自动淘汰最早入栈的页面
  • 懒加载 — 基于 Vue 3 的组件懒加载,按需加载页面

安装

npm install @lovelymai/app-router

快速开始

1. 创建路由器实例

import createAppRouter from '@lovelymai/app-router'

const tabs = ['recommendation', 'product', 'shopping-bag']

const routes = {
  [tabs[0]]: {
    path: tabs[0],
    component: () => import('./pages/recommendation/index.vue'),
  },
  [tabs[1]]: {
    path: tabs[1],
    component: () => import('./pages/product/index.vue'),
    children: [
      {
        path: 'category/:name',
        component: () => import('./pages/product/category/index.vue'),
      },
      {
        path: 'detail/:name',
        component: () => import('./pages/product/detail/index.vue'),
      },
    ],
  },
  [tabs[2]]: {
    path: tabs[2],
    component: () => import('./pages/shopping-bag/index.vue'),
  },
}

const router = createAppRouter({
  tabs,
  defaultTab: tabs[0],
  routes,
  limit: 10, // 可选,全局最多缓存 10 个页面组件
})

export default router

2. 安装到 Vue 应用

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

// 导入样式
import '@lovelymai/app-router/dist/app-router.css'

createApp(App).use(router).mount('#app')

3. 在组件中使用

<script setup lang="ts">
import router from './router'

const tabs = ['recommendation', 'product', 'shopping-bag']

const onTabClick = (_item: any, index: number) => {
  if (tabs[index] === router.activeTab) {
    router.nav(`/${tabs[index]}`)
  }
  router.switchTab(tabs[index])
}
</script>

<template>
  <router-view />
</template>

工作原理

初始化加载

初始化时只加载 URL 当前路径对应的组件,不预加载所有标签页的根组件:

| URL | 栈内容 | 加载的组件 | |-----|--------|-----------| | /recommendation | [{/recommendation}] | 推荐页组件 | | /product/detail/foo | [{/product}, {/product/detail/foo}] | 商品页 + 详情页组件 |

其他标签页(如 shopping-bag)的栈为空,切换到该标签时才首次加载其根组件。

弹出时预加载

pop() 触发后退动画(300ms)的同时,立即异步加载目标页面的组件。如果已缓存则无缝显示,未缓存则在加载完成后即时渲染。

容量限制

limit 控制所有标签页的栈条目总数。每次新增条目时检查,超出则淘汰全局最早入栈的条目(根页面不例外),确保内存可控。

API

createAppRouter(options)

创建一个路由器实例。

参数

| 参数 | 类型 | 必填 | 说明 | |-----------|------|----------|-------------| | tabs | string[] | 是 | 标签页列表,每个标签对应一个路由堆栈 | | defaultTab | string | 否 | 默认激活的标签页,默认 tabs[0] | | limit | number | 否 | 全局最大组件缓存数量,超出时淘汰最早入栈的页面 | | routes | Record<string, RouteConfig> | 是 | 路由配置,键为标签页名称 |

RouteConfig

| 属性 | 类型 | 必填 | 说明 | |----------|------|----------|-------------| | path | string | 是 | 路由路径 | | component | any \| (() => Promise<any>) | 是 | 路由组件(支持懒加载) | | props | ((route: { params: Record<string, string>, query: Record<string, string> }) => Record<string, any>) \| Record<string, any> | 否 | 路由组件的 Props | | children | RouteConfig[] | 否 | 子路由配置 |

路由器实例方法

| 方法 | 说明 | |--------|-------------| | router.switchTab(tab) | 切换到指定的标签页,首次切换时自动加载根组件 | | router.push(path \| RouteLocation) | 推入新页面(支持懒加载) | | router.pop() | 返回上一页(带动画延迟,其间预加载目标页组件) | | router.nav(path \| RouteLocation) | 在当前标签堆栈中导航到指定路径 | | router.setQuery(query) | 设置当前路由的查询参数 |

路由器实例属性

| 属性 | 类型 | 说明 | |----------|------|-------------| | router.activeTab | string | 当前激活的标签页名称 | | router.currentPath | string | 当前路由路径 | | router.stacks | Record<string, CachedComponent[]> | 所有标签页的组件堆栈 | | router.allComponents | CachedComponent[] | 所有已渲染的组件列表(RouterView 数据源) | | router.currentStack | CachedComponent[] | 当前标签页的组件堆栈 | | router.params | Record<string, string> | 当前路由的路径参数 | | router.query | Record<string, string> | 当前路由的查询参数 |

样式

/* 在 main.ts 中导入 */
import '@lovelymai/app-router/dist/app-router.css'

CSS 变量

| 变量 | 默认值 | 说明 | |------|--------|------| | --router-animating-z-index | 1 | 页面动画期间的 z-index |