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 🙏

© 2024 – Pkg Stats / Ryan Hefner

weuse

v0.6.0

Published

Wechat miniprogram utilities

Downloads

20

Readme

WeUse

微信小程序 API 助手

Features

安装

使用 npm 依赖(原生或 mpvue)

npm i weuse

使用本地依赖项

如无法使用 npm 依赖, 可下载 latest release, 放至项目目录中进行相对路径引用.

使用

使用 npm 依赖

const weuse = require('weuse')

TypeScript

import * as weuse from 'weuse'

Promise

weuse.promise

Promise 相关封装

weuse.promise.promisify(func: Function): Function

将一个小程序方法 Promise 化

e.g.

const res = await weuse.promisify(wx.getUserInfo)()
const { confirm, cancel } = await weuse.promisify(wx.showModal)({
  title: 'Test',
  content: 'This is a test'
})

weuse.promise.map(values: any[], mapper: Function): Promise<any[]>

对一个数组进行 map 操作并行执行每个返回的 Promise. 返回按传入顺序排序的执行结果

e.g.

const urls = ['https://...', 'https://...', 'https://...']
const results = await weuse.promise.map(urls, url => weuse.request.get(url))

weuse.promise.serial(values: any[]): Promise<any[]>

顺序执行 Promise. 返回按传入顺序排序的执行结果

e.g.

const results = await weuse.promise.serial([
  weuse.wx.login(),
  weuse.request.post({ url, data }),
  weuse.wx.setStorage({ key, data })
])

weuse.wx

包含全部已Promisify处理的 wx 方法对象. 调用签名同 wx 中的方法, 无需设置success,fail回调. 若设置回调, 则不会返回Promise.

e.g.

原调用

wx.getUserInfo({
  success(res) {
    console.log(res.userInfo)
  }
})

wx.showModal({
  title: 'Test',
  content: 'This is a test',
  success({ confirm, cancel }) {
    //
  }
})

异步调用

weuse.wx.getUserInfo().then(res => {
  console.log(res.userInfo)
})

// 使用await
const res = await weuse.wx.getUserInfo()
console.log(res.userInfo)

const { confirm, cancel } = await weuse.wx.showModal({ title: 'Test', content: 'This is a test' })

兼容调用

weuse.wx.getUserInfo({
  success(res) {
    console.log(res.userInfo)
  }
})

weuse.wx.showModal({
  title: 'Test',
  content: 'This is a test',
  success({ confirm, cancel }) {
    //
  }
})

缓存

weuse.storage

支持 TTL 的缓存封装

注意 get/del/touch/exists/ttl/expire/persist/flush 只能针对由 set 添加的缓存

weuse.storage.get(key: string): Promise<any>

从本地缓存中获取指定 key 的内容. Date 类型会被反序列化. key 不存在返回 undefined

e.g.

const token = await weuse.storage.get('token')

weuse.storage.set(opts: Options): Promise<void>

将数据存储在本地缓存中指定的 key 中

Options:

  • key: string 本地缓存中指定的 key
  • data: any 需要存储的内容
  • ttl?: number 有效时间(秒). 为空或 0 则不会过期

e.g.

await weuse.storage.set({ key: 'token', data: token, ttl: 3600 })

weuse.storage.del(key: string): Promise<void>

从本地缓存中移除指定 key

e.g.

await weuse.storage.del('token')

weuse.storage.touch(...keys: string[]): Promise<number>

检查指定的 key 是否已过期, 是则移除. key 不存在则忽略. 返回移除掉的 key 数量

e.g.

const count = await weuse.storage.touch('token', 'name', 'key2')

weuse.storage.exists(key: string): Promise<boolean>

检查 key 是否存在

e.g.

const exists = await weuse.storage.exists('token')

weuse.storage.ttl(key: string): Promise<number>

获取指定 key 的剩余有效时间(秒). 若 key 不存在返回-1; 若 key 不会过期返回-2

e.g.

const ttl = await weuse.storage.ttl('token')

weuse.storage.expire(key: string, ttl: number): Promise<boolean>

更新指定 key 的有效时间. key 存在且设置成功则返回 true

e.g.

const success = await weuse.storage.expire('token', 3600)

weuse.storage.persist(key: string): Promise<boolean>

移除指定 key 的有效时间让其不会过期. key 存在且设置成功则返回 true

e.g.

const success = await weuse.storage.persist('token')

weuse.storage.flush()

移除所有已过期的缓存

e.g.

await weuse.storage.flush()

网络请求

weuse.request

网络请求封装

weuse.request(options: Options): Promise<Response>

发起网络请求

Options:

  • url: string
  • query?: string|object
  • method?: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT'
  • data?: string | object | ArrayBuffer
  • header?: object
  • dataType?: string
  • responseType?: 'text' | 'arraybuffer'

Response:

  • data: string | object | ArrayBuffer
  • statusCode: number
  • header: object

e.g.

const res = await weuse.request({ url: 'https://myapi.com/api/v1/items', method: 'GET' })

或者直接使用 http verb 小写名称当方法名

e.g.

const res = await weuse.request.get('https://myapi.com/api/v1/items')

const { data, statusCode, header } = await weuse.request.get({
  url: 'https://myapi.com/api/v1/items',
  query: {
    name: 'abc',
    key: '12345'
  }
})

await weuse.request.post({
  url: 'https://myapi.com/api/v1/items',
  data: {
    type: 'Book',
    id: 1
  }
})

注意当 status code 不为 2xx/3xx 时, Promise 会被自动 reject 掉, 抛出 HttpError(包含 code, message 内容)

weuse.request.defaults(opts: Options): Request

返回一个包含默认设置的 request 对象. 可用来设置baseUrl, header等默认值

e.g.

const request = weuse.request.defaults({
  baseUrl: 'https://myapi.com/api/v1',
  header: { 'x-uuid': '12345' },
  query: {
    token: '123456'
  }
})

const res = await request.get({
  url: '/items',
  header: { 'x-key': 'abcd' },
  query: {
    page: 3
  }
})

相当于

const res = await weuse.request.get({
  url: 'https://myapi.com/api/v1/items',
  header: {
    'x-uuid': '12345',
    'x-key': 'abcd'
  },
  query: {
    token: '123456',
    page: 3
  }
})

weuse.request.download(opts: Options): Promise<Result>

分段下载文件

Options:

  • url: string 下载地址
  • filePath?: string 保存路径
  • parts?: number 分段数 1~10
  • header?: object 请求头
  • query?: string|object querystring

Result:

  • filePath?: string 下载文件保存路径
  • buffer?: ArrayBuffer 下载文件的二进制流

e.g.

const { filePath } = await weuse.request.download({
  url: 'https://some/large/file.jpg',
  parts: 3,
  filePath: wx.env.USER_DATA_PATH + '/file.jpg'
})

const { buffer } = await weuse.request.download({
  url: 'https://some/large/file.jpg',
  parts: 3
})

Canvas

weuse.canvas

绘制 Canvas 封装

weuse.canvas.draw(canvasId: string, options: Options): Promise<void|string>

绘制 Canvas

Options:

  • layers: Layer[] 图层. 从下到上绘制
  • default?: Style 默认样式. 可以在图层中覆盖
  • export?: Export 导出 canvas 到文件的设置
  • downloader?: Downloader 图片下载方法(不设置则使用 wx.getImageInfo)

Style:

  • stroke?: Stroke 描边
  • fill?: Fill 填充
  • font?: Font 文字

Stroke: 描边样式

  • color?: Color
  • lineWidth?: number
  • lineDash?: Stroke.LineDash
  • lineCap?: 'butt' | 'round' | 'square'
  • lineJoin?: 'bevel' | 'round' | 'miter'
  • miterLimit?: number

Fill: 填充样式

  • color?: Color
  • shadow?: Fill.Shadow

Color: 颜色, 可以为字符串#fff, rgb(0,0,0)等

  • type: 'linear' | 'circular' | 'pattern' 渐变方式

Font: 字体样式

  • family?: string 字体
  • size: number 字号
  • align?: 'left' | 'center' | 'right' 水平对齐
  • baseline?: 'top' | 'bottom' | 'middle' | 'normal' 垂直对齐

Export:

  • x?: number 指定的画布区域的左上角横坐标
  • y?: number 指定的画布区域的左上角纵坐标
  • width?: number 指定的画布区域的宽度
  • height?: number 指定的画布区域的高度
  • destWidth?: number 输出的图片的宽度
  • destHeight?: number 输出的图片的高度
  • fileType?: 'jpg' | 'png' 目标文件的类型
  • quality?: number 图片的质量

Layer:

  • type: 'rect' | 'arc' | 'image' | 'text' | 'path' 图层类型
  • x?: number 绘制起点 X
  • y?: number 绘制起点 Y
  • fill?: Fill | true 填充样式. 为 true 进行默认填充
  • stroke?: Stroke | true 描边样式. 为 true 进行默认描边
  • clip?: Clip 图层遮罩
  • transform?: Transform 图层变换

Layer.Rect: 矩形

  • width: number
  • height: number
  • anchor?: Vector2 轴心点{x: [0, 1], y: [0, 1]}, 默认{x: 0, y: 0}

Layer.Arc: 弧形

  • radius: number 半径
  • startAngle?: number 起始弧度(0 为三点钟方向)
  • endAngle?: number 结束弧度
  • counterClockwise?: boolean 逆时针

Layer.Image: 图片

  • src: string 资源,可为网络链接或本地地址
  • width?: number
  • height?: number
  • crop?: Image.Crop 裁剪
  • anchor?: Vector2 轴心点{x: [0, 1], y: [0, 1]}, 默认{x: 0, y: 0}

Layer.Path: 文本

  • text: string 内容
  • font?: Font 字体样式
  • maxWidth?: number 最大宽度

Layer.Path: 路径

  • points: Point[] 路径点
  • close?: boolean 路径关闭

e.g.

<view style='width:0px;height:0px;overflow:hidden;'>
  <canvas canvas-id='poster' style="width:750px;height:750px;"></canvas>
</view>
const filePath = await weuse.canvas.draw('poster', {
  export: {
    width: 375,
    height: 500,
    fileType: 'jpg',
    quality: 0.8
  },
  default: {
    stroke: {
      color: 'black',
      lineWidth: 2
    },
    fill: {
      color: 'red'
    },
    font: {
      size: 22,
      align: 'center',
      baseline: 'middle'
    }
  },
  layers: [
    {
      type: 'rect',
      width: 100,
      height: 100,
      fill: true,
      stroke: {
        lineWidth: 1,
        color: 'green',
        lineDash: {
          pattern: [10, 20],
          offset: 5
        }
      }
    },
    {
      type: 'arc',
      x: 100,
      y: 100,
      radius: 50,
      fill: {
        color: 'purple'
      }
    },
    {
      type: 'path',
      x: 200,
      y: 200,
      points: [
        {
          type: 'linear',
          x: 220,
          y: 200
        },
        {
          type: 'arc',
          x: 250,
          y: 220,
          radius: 30
        },
        {
          type: 'quadratic',
          x: 300,
          y: 250,
          cpx: 260,
          cpy: 300
        },
        {
          type: 'cubic',
          x: 280,
          y: 180,
          cpx0: 260,
          cpy0: 250,
          cpx1: 270,
          cpy1: 220
        }
      ],
      stroke: true,
      fill: true,
      close: true
    },
    {
      type: 'text',
      text: 'Hello World!',
      x: 300,
      y: 300,
      fill: true
    },
    {
      type: 'image',
      src: 'https://placeimg.com/100/100/animals',
      x: 100,
      y: 300,
      clip: {
        // 圆角遮罩效果
        type: 'rect',
        x: 100,
        y: 300,
        width: 100,
        height: 100,
        radius: 4
      }
    },
    {
      type: 'image',
      src: 'https://placeimg.com/100/100/animals',
      x: 100,
      y: 400,
      clip: {
        // 圆形遮罩效果
        type: 'circular',
        x: 150,
        y: 450,
        radius: 50
      }
    }
  ]
})
await weuse.utils.saveImageToPhotosAlbum({ filePath })

效果如图:

Imgur

其他

weuse.utils

帮助方法封装

weuse.utils.encodeQuery(query: object): string

object 创建 querystring

e.g.

const query = weuse.utils.encodeQuery({
  name: 'admin',
  size: 50,
  key: null,
  index: undefined
})
// 结果: name=admin&size=50

weuse.utils.decodeQuery(query: object): object

解析小程序页面传递的 querystring 对象. 兼容小程序码、二维码、普通链接

weuse.utils.joinUrl(...urls: string[]): string

连接 url. 会移除重复的 / 符号. url 开头跟结尾均可包含或缺省 / 符号. 返回结果结尾不含 / (除非整体仅为 /)

e.g.

const url = weuse.utils.joinUrl('http://myapi.com/', '/api/v1', 'items/', '1')
// 结果: http://myapi.com/api/v1/items/1

weuse.utils.authorize(scope: string): Promise<void>

查询授权, 如果未授权则进行请求

weuse.utils.getLocation(opts: Options): Promise<Location>

检查权限并获取地理定位

weuse.utils.chooseLocation(opts: Options): Promise<Location>

检查权限并请求地理定位

weuse.utils.saveImageToPhotosAlbum(opts: Options): Promise<void>

检查权限并写入相册

weuse.utils.clone(source: any): any

深克隆

weuse.utils.merge(source: any, target: any): any

递归合并

Redux

weuse.redux

redux 风格的状态管理

weuse.redux.createStore(reducer: Reducer): Store

创建一个 Store

weuse.redux.combineReducers(reducers: object): Reducer

合并多个 Reducers

weuse.redux.createProvider(store: Store, options: object): Provider

创建一个 Provider

e.g.

App(
  weuse.redux.createProvider(store, {
    onLaunch() {
      //...
      const state = this.$store.getState()
    }
  })
)

weuse.redux.createConsumer(options: object, stateMapper?: StateMapper): Consumer

创建一个 Consumer

e.g.

Page(
  weuse.redux.createConsumer({
    onLoad() {
      //...
      this.$dispatch({ type: 'FETCH_DATA' })
    }
  })
)
// 注入state
Page(
  weuse.redux.createConsumer(
    {
      onLoad() {
        //...
        console.log(this.data.items)
        console.log(this.data.count)
      }
    },
    state => ({
      items: state.items,
      count: state.count,
      name: state.app.name
    })
  )
)

weuse.redux.Provider(store: Store): ClassDecorator

Provider 装饰器

e.g.

@Provider(store)
class MyApp {
  onLaunch() {
    //...
    const state = this.$store.getState()
  }
}
App(new MyApp())

weuse.redux.Consumer(stateMapper?: StateMapper): ClassDecorator

Consumer 装饰器

e.g.

@Consumer()
class MyPage {
  onLoad() {
    //...
    this.$dispatch({ type: 'FETCH_DATA' })
  }
}
Page(new MyPage())

// 注入state
@Consumer(state => ({
  items: state.items,
  count: state.count
}))
class MyPage {
  onLoad() {
    //...
    console.log(this.data.items)
    console.log(this.data.count)
  }
}

weuse.redux.Consumer.State(name?: string): PropertyDecorator

State 绑定装饰器

e.g.

@Consumer()
class MyPage {
  @Consumer.State
  items: any[]

  @Consumer.State('count')
  size: number

  onLoad() {
    //...
    console.log(this.data.items)
    console.log(this.data.size)
  }
}

注: State 绑定可与 Consumer 装饰器中的 StateMapper 参数共存, 若存在同名属性, 前者会覆盖后者

weuse.redux.Consumer.namespace(name?: string): Namespace

子 State 绑定对象

weuse.redux.Consumer.Namespace.State(name?: string): PropertyDecorator

子 State 绑定装饰器

e.g.

const app = Consumer.namespace('app')
const
@Consumer()
class MyPage {
  @app.State
  items: any[]

  @app.State('count')
  size: number

  onLoad() {
    //...
    console.log(this.data.items)
    console.log(this.data.size)
  }
}

Vuex

weuse.vuex

vuex 风格的状态管理

weuse.vuex.createStore(options: StoreOptions): Store

创建一个 Store

weuse.vuex.createProvider(store: Store, options: object): Provider

创建一个 Provider

e.g.

App(
  weuse.vuex.createProvider(store, {
    onLaunch() {
      //...
      const state = this.$store.state
    }
  })
)

weuse.vuex.createConsumer(options: object, ...mappers: Mapper[]): Consumer

e.g.

Page(
  weuse.vuex.createConsumer({
    onLoad() {
      //...
    }
  })
)
// 注入state/getters/mutations/actions
Page(
  weuse.vuex.createConsumer(
    {
      async onLoad() {
        //...
        console.log(this.data.items)
        console.log(this.data.count)
        await this.login()
        console.log(this.data.user)
        this.setName('admin')
      }
    },
    {
      state: {
        items: 'items',
        count: state => state.count
      },
      getters: ['name'],
      mutations: {
        setUser: 'setName'
      }
    },
    {
      namespace: 'account',
      getters: ['user'],
      actions: ['login']
    }
  )
)

创建一个 Consumer

weuse.vuex.Provider(store: Store): ClassDecorator

Provider 装饰器

e.g.

@Provider(store)
class MyApp {
  onLaunch() {
    //...
    const state = this.$store.state
  }
}
App(new MyApp())

weuse.vuex.Consumer(...mappers: Mapper[]): ClassDecorator

Consumer 装饰器

e.g.

@Consumer()
class MyPage {
  onLoad() {
    //...
  }
}
Page(new MyPage())

// 注入state
@Consumer({
  state: ['items', 'count']
})
class MyPage {
  onLoad() {
    //...
    console.log(this.data.items)
    console.log(this.data.count)
  }
}

weuse.vuex.Consumer.State(name?: string): PropertyDecorator weuse.vuex.Consumer.State(func: Function): PropertyDecorator weuse.vuex.Consumer.Getter(name?: string): PropertyDecorator weuse.vuex.Consumer.Mutation(name?: string): PropertyDecorator weuse.vuex.Consumer.Mutation(func: Function): PropertyDecorator weuse.vuex.Consumer.Action(name?: string): PropertyDecorator weuse.vuex.Consumer.Action(func: Function): PropertyDecorator

State/Getter/Mutation/Action 绑定装饰器

e.g.

@Consumer()
class MyPage {
  @Consumer.State
  items: any[]

  @Consumer.State('count')
  size: number

  @Consumer.State(state => state.count)
  count: number

  @Consumer.Getter
  max: number

  @Consumer.Action
  add: Consumer.ActionMethod

  @Consumer.Mutation
  setCount: Consumer.MutationMethod

  async onLoad() {
    //...
    console.log(this.data.items)
    console.log(this.data.size)
    console.log(this.data.count)
    console.log(this.data.max)
    await this.add()
    this.setCount(100)
  }
}

注: State/Getter/Mutation/Action 绑定可与 Consumer 装饰器中的 Mapper 参数共存, 若存在同名属性, 前者会覆盖后者

weuse.vuex.Consumer.namespace(name?: string): Namespace

子模块绑定对象

weuse.vuex.Consumer.Namespace.State(name?: string): PropertyDecorator weuse.vuex.Consumer.Namespace.State(func: Function): PropertyDecorator weuse.vuex.Consumer.Namespace.Getter(name?: string): PropertyDecorator weuse.vuex.Consumer.Namespace.Mutation(name?: string): PropertyDecorator weuse.vuex.Consumer.Namespace.Mutation(func: Function): PropertyDecorator weuse.vuex.Consumer.Namespace.Action(name?: string): PropertyDecorator weuse.vuex.Consumer.Namespace.Action(func: Function): PropertyDecorator

子 State/Getter/Mutation/Action 绑定装饰器

e.g.

const app = Consumer.namespace('app')
@Consumer()
class MyPage {
  @app.State
  items: any[]

  @app.State('count')
  size: number

  onLoad() {
    //...
    console.log(this.data.items)
    console.log(this.data.size)
  }
}

构建

npm run build

包含 source map

SOURCE_MAP=inline-source-map npm run build

License

See License