# v3-mini **Repository Path**: w_494917128/v3-mini ## Basic Information - **Project Name**: v3-mini - **Description**: 小程序框架,使用vue3.0的composition-api写法开发小程序 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-07-27 - **Last Updated**: 2021-03-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 参考 [Vue3.x](https://v3.vuejs.org) ,尝试使用 composition-api 开发小程序 ### 下载 > npm install v3-mini --save > [仓库地址](https://gitee.com/w_494917128/v3-mini) > [小程序npm使用](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html) ### 注意 1. 参考 @vue/reactivity 开发小程序版 composition api ,使用 Proxy 而不用 Object.defineProperty 是因为解决属性添加删除上的问题,但[小程序对的 Proxy 的适应性](https://developers.weixin.qq.com/miniprogram/dev/framework/runtime/js-support.html)并不好 2. 采用 [westore](https://github.com/Tencent/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 第二个参数 ```js 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对象 ```js 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` ```html {{ count }} + ``` ```js 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 对象集 ```js 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对象 将数据包装成一种可观测的类型,当数据产生变更的时候,监听并执行响应操作 ```js 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对象 ```js 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} 返回停止监听的方法 ```js 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` 一族的函数来注册生命周期钩子: ```js import { VPage, onLoad, onHide, onShow } from 'v3-mini' VPage({ setup() { onLoad(() => { console.log('onLoad!') }) onHide(() => { console.log('onHide!') }) onShow(() => { console.log('onShow!') }) }, } ``` ### VPage使用 ```html name: {{name}} count1: {{count1}} count2: {{count2}} allCount.count1: {{allCount.count1}} allCount.count2: {{allCount.count2}} allCount.count3: {{allCount.count3}} changeName addCount1 addCount3 delCount3 stopWatch ``` ```js 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使用 ```html name: {{name}} changeName ``` ```html ``` ```js 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 } } }) ```