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

venus-common

v0.0.7

Published

> 目录:`packages/venus-common` | npm 包名:`venus-common`

Readme

venus-common

目录:packages/venus-common | npm 包名:venus-common

与框架无关的通用工具库:树结构操作、数组分组、函数修饰器(单例/节流/防抖/一次性)、颜色转换、SVG 水印、设备环境判断、阿里云 Aplus 埋点上报。无运行时外部依赖。

安装

pnpm add venus-common

API 详解

一、树结构(utils.ts

flattenTree(treeArray, childKey?)

树展开为带 level 的平铺数组(深度优先,迭代实现,去掉 children 字段)。

function flattenTree<T = any>(
  treeArray: TreeNode<T>[],
  childKey?: string            // 子节点字段名,默认 'children'
): FlattenedNode<T>[]

interface TreeNode<T = any> { [key: string]: any; children?: T[] }
interface FlattenedNode<T = any> extends Omit<TreeNode<T>, 'children'> { level: number }
const flat = flattenTree(tree)            // [{ ...node, level: 0 }, { ...child, level: 1 }, ...]
const flat2 = flattenTree(tree, 'subs')   // 自定义子节点字段名

buildTree(nodes, parentId, idKey?, pidKey?, childrenKey?)

扁平列表构建为树(递归;用 == 比较兼容字符串/数字 id)。

function buildTree<T extends Record<string, any>>(
  nodes: readonly T[],
  parentId: string | number | null | undefined,  // 根通常传 null
  idKey?: keyof T,                                // 默认 'id'
  pidKey?: keyof T,                               // 默认 'pid'
  childrenKey?: keyof T & string                  // 默认 'children'
): T[]

| 参数 | 类型 | 默认 | 说明 | |---|---|---|---| | nodes | readonly T[] | — | 扁平节点数组 | | parentId | string\|number\|null | — | 当前层父 id,根传 null | | idKey | keyof T | 'id' | 节点唯一标识字段 | | pidKey | keyof T | 'pid' | 父节点标识字段 | | childrenKey | string | 'children' | 输出子节点字段名 |

const tree = buildTree(flat, null, 'id', 'pid')

getAncestorIds(targetId, list, idKey?, pidKey?)

获取目标节点到根的祖先 id 链(含目标自身,从根到目标顺序)。若最顶层节点 pidnull(非合法根链),返回 []

function getAncestorIds<T extends Record<string, any>>(
  targetId: string | number,
  list: T[],
  idKey?: keyof T,             // 默认 'funId'
  pidKey?: keyof T             // 默认 'pid'
): (string | number)[]
const ids = getAncestorIds(targetId, flatList, 'id', 'pid')

二、数组分组(utils.ts

groupBy(arr, format)

function groupBy<T, K>(
  arr: readonly T[],
  format: string | ((item: T, index?: number, array?: readonly T[]) => K)
): Map<K, T[]>

format 为字符串时按对象属性分组,为函数时按返回值分组。返回 Map<分组键, 元素数组>

groupBy(users, 'role')                          // Map<role, User[]>
groupBy(nums, (n) => (n % 2 ? 'odd' : 'even'))  // Map<'odd'|'even', number[]>

三、数字格式化(utils.ts

computedCount(count)

function computedCount(count: string): string | number

入参为字符串,按区间向下取整加后缀(不保留小数);非整数或负数返回 0

| 区间 | 处理 | 示例 | |---|---|---| | > 999999 | /1e6 + 'M+' | computedCount('2000000') → '2M+' | | > 9999 | /1e4 + 'w+' | computedCount('15000') → '1w+' | | > 999 | /1e3 + 'k+' | computedCount('1200') → '1k+' | | 其余 | 原值 | computedCount('500') → '500' |


四、颜色转换(utils.ts

colorToRgba(color, alpha?)

function colorToRgba(color: string, alpha?: number): string // alpha 默认 1

将颜色统一转为 rgba(r, g, b, a)。支持:颜色名称、HEX(3/6/8 位,8 位 alpha 被忽略)、RGB(A)、HSL(A)(逗号或空格分隔均可)。输入自带的 alpha 一律被第二参覆盖alpha 会被夹到 [0,1];格式非法或数值越界时抛出 Error

colorToRgba('#ff0000', 0.5)            // 'rgba(255, 0, 0, 0.5)'
colorToRgba('rgb(0 255 0)', 0.8)       // 'rgba(0, 255, 0, 0.8)'
colorToRgba('hsl(120, 100%, 50%)', 1)  // 'rgba(0, 255, 0, 1)'
colorToRgba('red')                     // 'rgba(255, 0, 0, 1)'

五、函数修饰器(index.ts

executeOnce(fn)

function executeOnce<TArgs extends any[], TReturn = void>(
  fn: (...args: TArgs) => TReturn
): (...args: TArgs) => void

返回只在首次调用时执行 fn 的函数,后续调用无效。

throttle(fn, delay)

function throttle<TArgs extends any[], TReturn = void>(
  fn: (...args: TArgs) => TReturn,
  delay: number
): (...args: TArgs) => void

节流:首次立即执行,delay(ms) 间隔内只执行一次。

debounce(fn, delay?)

function debounce<TArgs extends any[], TReturn = void>(
  fn: (...args: TArgs) => TReturn,
  delay?: number            // 默认 100
): (...args: TArgs) => void

防抖:末次触发后延迟 delay(ms) 执行。

singleton(TargetClass)

function singleton<T extends new (...args: any[]) => any>(
  TargetClass: T
): ((...args: ConstructorParameters<T>) => InstanceType<T>) & { clear?: () => void }

单例工厂(懒汉式,保留首次参数):包装类后无论 new 多少次都返回首个实例;附带 clear() 可重置(测试用)。

const getInst = singleton(MyClass)
const a = getInst(arg1)
const b = getInst(arg2)   // a === b(arg2 被忽略)
getInst.clear?.()         // 重置单例

六、设备环境(utils.ts

getEnvByUa() / isWeb

function getEnvByUa(): string   // 'isTaurusApp' | 'h5',结果缓存在 sessionStorage('curUaEnv')
const isWeb: boolean            // 等价于 getEnvByUa() === 'h5'

scrollToTopByDom(scrollDom)

function scrollToTopByDom(scrollDom: Element): void

平滑滚动到顶部;元素无 scrollTo 时回退为设置 scrollTop = 0


七、SVG 水印(utils.ts

renderWaterMark(options)

function renderWaterMark(options: {
  txt?: string          // 水印文字
  angle?: number        // 旋转角度,默认 -45
  width?: number        // 画布宽,默认 250
  height?: number       // 画布高,默认 250
  fontSize?: number     // 字号,默认 16
  font?: string         // 字体族,默认 'sans-serif'
  fontWeight?: string | number  // 默认 'normal'
  x?: number            // 文字 x(默认按是否 iOS 取 0 / 125)
  y?: number            // 文字 y(默认按是否 iOS 取 125 / 100)
  color?: string        // 默认 'rgba(24, 56, 132, 0.12)'
}): string              // 返回 data:image/svg+xml;base64,...

返回 base64 编码的 SVG Data URL,可直接作为 background-image 平铺。

const url = renderWaterMark({ txt: '内部文件', angle: -30, fontSize: 14 })
el.style.backgroundImage = `url(${url})`

八、埋点上报(阿里云 Aplus,report-log.ts

依赖全局 window.aplus_queue(由页面引入的阿里云 Aplus SDK 提供);src/types/aplus.d.ts 补全了相关全局类型声明。

initLog()

function initLog(): void

初始化 aplus 元信息(设置 rhost),并按 UA 区分平台设置 appId(Android 28302650 / iOS 28328447 / 其他 47130293)。

reportLog(userName, accountId, config?)

function reportLog(
  userName: string,
  accountId: number,
  config?: { appId: string; appName: string }   // 默认 { appId: '', appName: '' }
): void

上报页面访问 PV(aplus.sendPV),携带 userId / userName / sapp_id / sapp_name

reportUserLog(userName, accountId)

function reportUserLog(userName: string, accountId: number): void

设置用户昵称(_user_nick)与用户 ID(_user_id)。

initLog()
reportLog('张三', 10086, { appId: 'app_x', appName: '示范应用' })
reportUserLog('张三', 10086)

导出一览

isWebinitLoggroupBybuildTreegetEnvByUacolorToRgbaflattenTreereportLogreportUserLogcomputedCountgetAncestorIdsrenderWaterMarkscrollToTopByDomexecuteOncethrottledebouncesingleton,以及 TreeNode / FlattenedNode 类型。

构建

pnpm --dir packages/venus-common build   # tsup 产出 esm + cjs + d.ts
pnpm --dir packages/venus-common dev

依赖

无运行时外部依赖。