Skip to content

Commit

Permalink
Feature/set data (#55)
Browse files Browse the repository at this point in the history
* chore: add npmignore and ignore pattern

* feat(tua-mp): hack native setData

* chore: move some devDependencies into packages

* refactor(tua-mp): index -> TuaPage/TuaComp, add utils/hackSetData

* docs: update basic example, add setData example

* perf: add error message when call setData with uninitialized properties

* docs: close #41, update mini code url, add hack setData part

* perf: modify vm.data when call setData
  • Loading branch information
BuptStEve authored Aug 31, 2018
1 parent 06ac3d4 commit 89363ea
Show file tree
Hide file tree
Showing 26 changed files with 688 additions and 438 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</p>

<p align="center">
<a href="https://circleci.com/gh/tuateam/tua-mp/tree/master"><img src="https://img.shields.io/circleci/project/tuateam/tua-mp/master.svg" alt="Build Status"></a>
<a href="https://circleci.com/gh/tuateam/tua-mp/tree/master"><img src="https://img.shields.io/circleci/project/github/tuateam/tua-mp/master.svg" alt="Build Status"></a>
<a href="https://codecov.io/github/tuateam/tua-mp?branch=master"><img src="https://img.shields.io/codecov/c/github/tuateam/tua-mp/master.svg" alt="Coverage Status"></a>
<a href="https://www.npmjs.com/package/tua-mp"><img src="https://img.shields.io/npm/v/tua-mp.svg" alt="Version"></a>
<a href="https://www.npmjs.com/package/tua-mp"><img src="https://img.shields.io/npm/l/tua-mp.svg" alt="License"></a>
Expand All @@ -28,7 +28,7 @@
## 1.1.最基础的使用方式 -- [examples/basic/](https://github.com/tuateam/tua-mp/tree/master/packages/tua-mp/examples/basic)
下载 [https://github.com/tuateam/tua-mp/blob/master/packages/tua-mp/examples/basic/utils/tua-mp.js](https://github.com/tuateam/tua-mp/blob/master/packages/tua-mp/examples/basic/utils/tua-mp.js) 文件到你的小程序项目中,例如保存为 `utils/tua-mp.js`

代码片段地址为:**wechatide://minicode/JzXSn8mb78n8**
代码片段地址为:**wechatide://minicode/2n17t5mU752Z**

> 可以尝试复制以上片段地址到浏览器地址栏中打开
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ footer: MIT Licensed | Copyright © 2018-present StEve Young
</p>

<p align="center">
<a href="https://circleci.com/gh/tuateam/tua-mp/tree/master"><img src="https://img.shields.io/circleci/project/tuateam/tua-mp/master.svg" alt="Build Status"></a>
<a href="https://circleci.com/gh/tuateam/tua-mp/tree/master"><img src="https://img.shields.io/circleci/project/github/tuateam/tua-mp/master.svg" alt="Build Status"></a>
<a href="https://codecov.io/github/tuateam/tua-mp?branch=master"><img src="https://img.shields.io/codecov/c/github/tuateam/tua-mp/master.svg" alt="Coverage Status"></a>
<a href="https://www.npmjs.com/package/tua-mp"><img src="https://img.shields.io/npm/v/tua-mp.svg" alt="Version"></a>
<a href="https://www.npmjs.com/package/tua-mp"><img src="https://img.shields.io/npm/l/tua-mp.svg" alt="License"></a>
Expand Down
30 changes: 28 additions & 2 deletions docs/quick-start/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
官方指南假设你已了解关于 [微信小程序开发](https://developers.weixin.qq.com/miniprogram/dev/index.html)[Vue.js](https://cn.vuejs.org/v2/guide/index.html) 的基础知识。
:::

尝试 `tua-mp` 最简单的方法是 [👉点击这里打开代码片段👈](wechatide://minicode/JzXSn8mb78n8),这个操作会打开你的**微信开发者工具**,并导入代码片段。(详情可参阅 [代码片段文档](https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html)
尝试 `tua-mp` 最简单的方法是 [👉点击这里打开代码片段👈](wechatide://minicode/2n17t5mU752Z),这个操作会打开你的**微信开发者工具**,并导入代码片段。(详情可参阅 [代码片段文档](https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html)

如果还没有安装 【微信开发者工具】 [👉点击这里下载👈](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)

Expand Down Expand Up @@ -38,9 +38,35 @@ TuaPage({

我们已经成功创建了第一个 `tua-mp` 应用!看起来这跟渲染一个字符串模板非常类似,但是 `tua-mp` 在背后做了一点微小的工作。

现在改变数据已经不需要调用 `setData`,所有数据都是响应式的。我们要怎么确认呢?[👉点击这里打开代码片段👈](wechatide://minicode/JzXSn8mb78n8),在控制台里修改 `global.msg` 的值,你将看到上例相应地更新。
现在改变数据已经不需要调用 `setData`,所有数据都是响应式的。我们要怎么确认呢?[👉点击这里打开代码片段👈](wechatide://minicode/2n17t5mU752Z),在控制台里修改 `global.msg` 的值,你将看到上例相应地更新。

```js
// 在开发者工具的控制台中
global.msg = 'young'
```

## hack 原生 setData
`v0.8.0` 中对于原生的 `setData` 方法进行了 hack。例如:

```js {6}
TuaPage({
data: { msg: 'steve' },
computed: { msgPlus: vm => vm.msg + '+' },
created () {
// 使用 setData 也会触发 computed
this.setData({ msg: 'young' })
},
})
```

::: tip
之所以选择 hack `setData` 方法,是因为在改造旧项目时,可能已经有了大量的 `setData` 代码。这样在将其向 [过渡版本](./simple-app.md) 改造的过程中,使用 `setData` 更新的数据不是响应式(Reactive)的,因此重构过程可能十分痛苦...

因此 hack 了 `setData` 之后,只需替换 Page、Component 为 TuaPage、TuaComp 后即可马上使用 computed、watch 等特性,页面依然能够跑起来。这样就可以渐进式地将小程序风格的旧代码改为 Vue 风格代码。
:::

::: warning
虽然小程序原生支持对于未在 data 中定义的数据进行 `setData`,但是在 `tua-mp` 中如果该属性未定义则会报错!

建议在 `data` 选项中先定义该数据![点我查看更多](https://cn.vuejs.org/v2/guide/reactivity.html#%E5%A3%B0%E6%98%8E%E5%93%8D%E5%BA%94%E5%BC%8F%E5%B1%9E%E6%80%A7)
:::
4 changes: 3 additions & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"command": {
"publish": {
"ignoreChanges": [
"*.md"
"**/__mocks__/**",
"**/__tests__/**",
"**/*.md"
]
}
},
Expand Down
6 changes: 0 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,16 @@
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.7.0",
"codecov": "^3.0.2",
"cross-env": "^5.2.0",
"eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-standard": "^3.1.0",
"gh-pages": "^1.2.0",
"husky": "^1.0.0-rc.13",
"jest": "^23.3.0",
"lerna": "^3.0.3",
"lint-staged": "^7.2.2",
"metro-memory-fs": "^0.43.5",
"rimraf": "^2.6.2",
"rollup": "^0.59.4",
"rollup-plugin-babel": "^3.0.4",
"rollup-plugin-eslint": "^4.0.0",
"rollup-plugin-json": "^3.0.0",
Expand Down
5 changes: 5 additions & 0 deletions packages/tua-mp-cli/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__mocks__/
__tests__/

src/
coverage/
8 changes: 7 additions & 1 deletion packages/tua-mp-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"lint": "eslint --fix lib/**/*.js bin/*",
"clean": "rimraf src && mkdir src/ src/app/ src/apis/ src/pages/ src/comps/ && echo {} > src/app/app.json",
"precommit": "lint-staged",
"pub": "yarn test && npm publish"
"pub": "npm test && npm publish"
},
"lint-staged": {
"bin/*": [
Expand Down Expand Up @@ -69,5 +69,11 @@
},
"engines": {
"node": ">=8"
},
"devDependencies": {
"codecov": "^3.0.4",
"cross-env": "^5.2.0",
"jest": "^23.5.0",
"rimraf": "^2.6.2"
}
}
4 changes: 4 additions & 0 deletions packages/tua-mp-service/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__mocks__/
__tests__/

coverage/
5 changes: 5 additions & 0 deletions packages/tua-mp-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,10 @@
},
"engines": {
"node": ">=8"
},
"devDependencies": {
"codecov": "^3.0.4",
"cross-env": "^5.2.0",
"jest": "^23.5.0"
}
}
203 changes: 203 additions & 0 deletions packages/tua-mp/__tests__/TuaComp.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import { afterSetData } from './utils'
import { TuaComp } from '../src'

const event = {
"currentTarget": {
"id": "",
"offsetLeft": 0,
"offsetTop": 0,
"dataset": { "index": 0 }
},
"detail": { "value": [] }
}

const eventVal = { "value": [], "index": 0 }

const getTestForReservedKeys = (type) => {
expect(() => type({ data: { $data: 'young' } })).toThrow()
expect(() => type({ data: { __TUA_PATH__: 'path' } })).toThrow()
expect(() => type({ computed: { $computed () { return '!' } } })).toThrow()
expect(() => type({ methods: { $data () {} } })).toThrow()
}

describe('TuaComp', () => {
test('component lifecycle', () => {
let lifecycleArr = []

const vm = TuaComp({
data: { lc: 'a' },
beforeCreate () {
lifecycleArr.push('beforeCreate')
},
created () {
lifecycleArr.push('created')
},
beforeMount () {
lifecycleArr.push('beforeMount')
},
ready () {
lifecycleArr.push('ready')
},
mounted () {
lifecycleArr.push('mounted')
},
beforeUpdate () {
lifecycleArr.push('beforeUpdate')
},
updated () {
lifecycleArr.push('updated')
},
beforeDestroy () {
lifecycleArr.push('beforeDestroy')
},
destroyed () {
lifecycleArr.push('destroyed')
},
})

expect(lifecycleArr).toEqual(['beforeCreate', 'created', 'beforeMount', 'ready', 'mounted'])

lifecycleArr = []
vm.lc = 'b'

afterSetData(() => {
expect(lifecycleArr).toEqual(['beforeUpdate', 'updated'])

lifecycleArr = []
vm.detached()
expect(lifecycleArr).toEqual(['beforeDestroy', 'destroyed'])
})
})

test('throw error when using reserved keys', () => getTestForReservedKeys(TuaComp))

test('deep and immediate watch', (done) => {
const vm = TuaComp({
data () {
return {
steve: 'young',
a: { b: { c: 'd' } },
}
},
computed: {
e () { return this.steve + this.a.b.c },
},
watch: {
'a.b': {
deep: true,
immediate: true,
handler (newVal, oldVal) {
this.newAB = newVal
this.oldAB = oldVal
},
},
e: { immediate: true, handler: 'eFn' },
},
methods: {
eFn (val) { this.newE = val },
},
})

expect(vm.newE).toBe(vm.e)
expect(vm.e).toBe(vm.steve + 'd')
expect(vm.newAB).toEqual({ c: 'd' })
expect(vm.oldAB).toEqual(undefined)
vm.a.b.c = 'e'

afterSetData(() => {
expect(vm.e).toBe(vm.steve + 'e')
expect(vm.newAB).toEqual({ c: 'e' })
expect(vm.oldAB).toEqual({ c: 'e' })
done()
})
})

test('use it just like MINA', (done) => {
const vm = TuaComp({
properties: {
propA: String,
propB: {
type: Number,
},
propC: {
type: String,
value: 'steve',
},
},
data: { compData: 'compData' },
detached () {},
methods: {
onChangeVal (e) {
this.$emit('onChangeVal', e)
},
onEmitVal () {
this.$emit('onEmitVal')
},
triggerEvent: jest.fn(),
},
})

vm.compData = 'steve'
expect(vm.propA).toBe('')
expect(vm.propB).toBe(0)
expect(vm.propC).toBe('steve')
expect(vm.compData).toBe('steve')

vm.onChangeVal(event)
expect(vm.triggerEvent).toBeCalledWith('onChangeVal', eventVal, undefined)

vm.onEmitVal()
expect(vm.triggerEvent).toBeCalledWith('onEmitVal', {}, undefined)

afterSetData(() => {
vm.detached()
expect(vm.data.compData).toBe('steve')
done()
})
})

test('use it just like Vue', () => {
const vm = TuaComp({
props: {
propA: Number,
propB: [String, Number],
propC: { type: String, required: true },
propD: { type: Number, default: 100 },
propE: { type: Object, default: () => ({ message: 'hello' }) },
propF: { validator: val => ['success', 'warning', 'danger'].indexOf(val) !== -1 },
},
computed: {
dAndE () { return this.propD + this.propE.message },
},
})
expect(vm.propA).toBe(0)
expect(vm.propB).toBe('')
expect(vm.propC).toBe('')
expect(vm.propD).toBe(100)
expect(vm.propE.message).toBe('hello')
expect(vm.propF).toBe('')
expect(vm.dAndE).toBe('100hello')
})

test('edge case', () => {
const data = jest.fn(() => ({}))
const attached = jest.fn()
TuaComp({ data, attached })

expect(data).toBeCalled()
expect(attached).toBeCalled()
})

// close #37
test('not plain object data', () => {
const now = new Date()
const hour = now.getHours()
const vm = TuaComp({
data () { return { now } },
computed: {
hour () { return this.now.getHours() },
},
})
expect(hour).toBe(vm.hour)
})
})
Loading

0 comments on commit 89363ea

Please sign in to comment.