# 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 }
}
})
```