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

v3-mini

v1.0.0-Alpha.2

Published

使用 composition-api 写法开发小程序

Readme

参考 Vue3.x ,尝试使用 composition-api 开发小程序

下载

npm install v3-mini --save

仓库地址

小程序npm使用

注意

  1. 参考 @vue/reactivity 开发小程序版 composition api ,使用 Proxy 而不用 Object.defineProperty 是因为解决属性添加删除上的问题,但小程序对的 Proxy 的适应性并不好
  2. 采用 westore 的 json diff 进行数据对比,减少了 setData 的内容

解决什么

  1. 使用 composition-api 开发,实现全局状态管理
  2. 添加了 reactive, ref, computed, watchEffect 方法
  3. 兼容原生小程序的写法,在原写法上新增写法
  4. 新的写法,data, methods 皆可在 setup 方法中一起定义返回
  5. 钩子函数也可直接在 setup 方法中直接定义

TODO

  1. 自定义组件的生命周期应该是按小程序原写法来还是与 Page 页面统一?
  2. setup的方法更新属于直接覆盖,是否需要对某些保护属性进行保护?
  3. setup返回的ref/reactive对象监听,采用异步setData的方式,数据改变后只执行一次setData,减少了setData方法的执行率
  4. 当页面中存在自定义组件时,是先执行自定义组件的setup后执行页面的setup

缺点

  1. Deps 依赖不同于 Vue3.x 存储于变量中,该版本存储于闭包中,通过js的机制不再引用时进行垃圾回收,使用不当容易造成内容泄露
  2. 采用 Proxy 才能实现 reactive 的数据监听(为了完成 属性添加删除上的问题),但小程序对 Proxy 的适应性并非很好
  3. setup返回的对象和方法,是在onLoad期间绑定在组件实例上的,依次不太适用于大量静态内容, 建议提前定义好data
  4. Provide / Inject 功能基础,有待提升

之后版本更新内容

  1. 内存回收机制完善(Deps、event)
  2. 自定义组件的 特殊的生命周期 暂未实现

setup

setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。

  • 调用时机 在onLoad/attached时候被执行

  • 参数 该函数接收 props 作为其第一个参数, context 第二个参数

VPage({
    ... ,
    setup(props, context) {
        context.event.on('load', () => {});
        context.event.emit('load');
        context.setData({
            age: ref(16)
        })
    }
})
  1. props reactive对象,代理小程序原始 onLoad 的参数 options,可通过 toRefs 函数对其进行分解
  2. context作为上下文对象, 暴露了一些api
  3. event是事件通知模块, 包含常用的emit, on, once, off, context注册的事件, 在页面/组件被销毁时也会主动off
  4. setData是封装后的setData, 支持对reactive/ref对象的解析, 其他用法和原生一致
  5. this指向当前页面/组件实例

包装对象ref

ref

ref接受参数并将其包装在具有value属性的对象中,然后将其用于访问或更改反应变量的值

参数

  1. val {Any} 任意值,赋值于ref.value

返回值 {Object} 返回代理后的ref对象

import { ref } from 'v3-mini'

const count = ref(0)
console.log(count.value) // 0

count.value = 1

console.log(count.value) // 1

在视图层中读取 当该值被setup返回, 将进入data值, 可在模板中被读取到, 会自动解套,无需在模板中额外书写.value

<view>{{ count }}</view>
<view bindtap="updateCount">+</view>
import { VPage, ref } from 'v3-mini'
VPage({
    setup(props, context) {
        const count = ref(0)
        return {
            count,
            updateCount() {
                count.value += 1
            }
        }
    }
})

拆解包装对象

toRefs

对 reactive 对象进行拆解,得到多个 ref 对象

参数

  1. reactive {Reactive} reactive 对象

返回值 {Object} ref 对象集

import { VPage, reactive, toRefs } from 'v3-mini'
VPage({
    setup(props, context) {
        const person = reactive({ name: 'Jack', age: 25 })
        const { name, age } = toRefs(person)
        return {
            name, age,
            updatePerson() {
                name.value = 'Rose'
                person.age = 18
            }
        }
    }
})

包装对象reactive

reactive

参数

  1. val {Object|Array} 创建该对象/数组的代理,监听数据变化

返回值 {Proxy} 返回代理后的reactive对象

将数据包装成一种可观测的类型,当数据产生变更的时候,监听并执行响应操作

import { reactive, watchEffect } from 'v3-mini'

const person = reactive({ name: 'Jack', age: 25 })
watchEffect(() => console.log(person.name)) // Jack
person.name = 'Rose' // Rose

reactive 对象中可使用 ref 对象

计算属性

computed

返回一个 不可手动修改的 ref 对象,收集监听当ref/reactive发送变化时随之更新值

参数

  1. setter {Function} 监听变化的回调, 返回任意值

返回值 {Object} 返回计算后的ref对象

import { ref, computed } from 'v3-mini'

const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2
count.value = 5
console.log(plusOne.value) // 6

计算属性总是最少会执行一次,为了第一次赋值

监听ref/reactive值更新

watchEffect 当被监听的ref/reactive对象变化时, 将触发

参数

  1. callback 监听变化的回调

返回值 {Function} 返回停止监听的方法

import { ref, watchEffect } from 'v3-mini'

const count = ref(1)
const stop = watchEffect(() => console.log(`count: ${count.value}`)) // count: 1
count.value++ // count: 2
stop()
count.value++ // 无输出

watchEffect 总是最少会执行一次,为了收集依赖 注意:第一次执行 watchEffect 时并没有生成 stop ,在 callback 中使用 stop 会产生错误


生命周期函数

可以直接导入 onXXX 一族的函数来注册生命周期钩子:

import { VPage, onLoad, onHide, onShow } from 'v3-mini'

VPage({
  setup() {
    onLoad(() => {
      console.log('onLoad!')
    })
    onHide(() => {
      console.log('onHide!')
    })
    onShow(() => {
      console.log('onShow!')
    })
  },
}

VPage使用

<view>name: {{name}}</view>
<view>count1: {{count1}}</view>
<view>count2: {{count2}}</view>
<view>allCount.count1: {{allCount.count1}}</view>
<view>allCount.count2: {{allCount.count2}}</view>
<view>allCount.count3: {{allCount.count3}}</view>
<view bindtap="changeName">changeName</view>
<view bindtap="addCount1">addCount1</view>
<view bindtap="addCount3">addCount3</view>
<view bindtap="delCount3">delCount3</view>
<view bindtap="stopWatch">stopWatch</view>
import { VPage, ref, toRefs, reactive, watchEffect, computed, onLoad } from 'v3-mini';

VPage({
    setup(props) {
        let { name } = toRefs(props)
        let count1 = ref(1)
        let count2 = computed(() => count1.value * 2)
        let allCount = reactive({ count1, count2 })

        const stop = watchEffect(() => {
            console.log(`监听allCount.${'count2'}: ${allCount['count2']}`);
        })
        function changeName() {
            name.value = 'Rose'
        }
        function addCount1() {
            count1.value++
        }
        function addCount3() {
            allCount.count3 = (allCount.count3 || 0) + 3
        }
        function delCount3() {
            delete allCount.count3
        }
        function stopWatch() {
            console.log(`停止监听allCount.${'count2'}`);
            stop()
        }

        onLoad(() => {
            console.log('onLoad!')
        })
        return { name, count1, count2, allCount, changeName, addCount1, addCount3, delCount3, stopWatch }
    }
})

VComponent使用

<view>name: {{name}}</view>
<view bindtap="changeName">changeName</view>
<myView name="Jack" />
import { VComponent, toRefs, attached } from 'v3-mini';

VComponent({
    properties:{
        name: String
    },
    setup(props) {
        let { name } = toRefs(props)

        function changeName() {
            name.value = 'Rose'
        }

        attached(() => {
            console.log('attached!')
        })
        return { name, changeName }
    }
})