Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
hello-uvue
提交
2b860713
H
hello-uvue
项目概览
DCloud
/
hello-uvue
通知
402
Star
3
Fork
10
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hello-uvue
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
2b860713
编写于
4月 21, 2024
作者:
DCloud-WZF
💬
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor(reactivity): watch
上级
389ac221
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
732 addition
and
150 deletion
+732
-150
pages.json
pages.json
+8
-2
pages/index/index.uvue
pages/index/index.uvue
+16
-0
pages/reactivity/core/watch/watch-composition.test.js
pages/reactivity/core/watch/watch-composition.test.js
+148
-0
pages/reactivity/core/watch/watch-composition.uvue
pages/reactivity/core/watch/watch-composition.uvue
+189
-0
pages/reactivity/core/watch/watch-options.test.js
pages/reactivity/core/watch/watch-options.test.js
+159
-0
pages/reactivity/core/watch/watch-options.uvue
pages/reactivity/core/watch/watch-options.uvue
+212
-0
pages/reactivity/core/watch/watch.uvue
pages/reactivity/core/watch/watch.uvue
+0
-148
未找到文件。
pages.json
浏览文件 @
2b860713
...
...
@@ -492,9 +492,15 @@
}
},
{
"path"
:
"pages/reactivity/core/watch/watch"
,
"path"
:
"pages/reactivity/core/watch/watch
-options
"
,
"style"
:
{
"navigationBarTitleText"
:
"watch"
"navigationBarTitleText"
:
"watch 选项式 API"
}
},
{
"path"
:
"pages/reactivity/core/watch/watch-composition"
,
"style"
:
{
"navigationBarTitleText"
:
"watch 组合式 API"
}
},
{
...
...
pages/index/index.uvue
浏览文件 @
2b860713
...
...
@@ -491,6 +491,22 @@ export default {
name: 'readonly',
url: 'readonly/readonly'
},
{
id: 'watch',
name: 'watch',
children: [
{
id: 'watch-options',
name: 'watch 选项式 API',
url: 'watch-options'
},
{
id: 'watch-composition',
name: 'watch 组合式 API',
url: 'watch-composition'
},
]
},
]
}
] as Page[]
...
...
pages/reactivity/core/watch/watch.test.js
→
pages/reactivity/core/watch/watch
-composition
.test.js
浏览文件 @
2b860713
const
PAGE_PATH
=
'
/pages/composition-api/reactivity/watch/watch
'
const
COMPOSITION_PAGE_PATH
=
'
/pages/reactivity/core/watch/watch-composition
'
describe
(
'
watch
'
,
()
=>
{
let
page
=
null
beforeAll
(
async
()
=>
{
page
=
await
program
.
reLaunch
(
PAGE_PATH
)
await
page
.
waitFor
(
'
view
'
)
page
=
await
program
.
reLaunch
(
COMPOSITION_
PAGE_PATH
)
await
page
.
waitFor
(
1000
)
})
it
(
'
count
'
,
async
()
=>
{
const
count
=
await
page
.
$
(
'
#count
'
)
expect
(
await
count
.
text
()).
toBe
(
'
count:
0
'
)
expect
(
await
count
.
text
()).
toBe
(
'
0
'
)
// watch
const
watchCountRes
=
await
page
.
$
(
'
#watch-count-res
'
)
expect
((
await
watchCountRes
.
text
()).
trim
()).
toBe
(
'
watch count result:
'
)
expect
((
(
await
watchCountRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
// track
const
watchCountTrackNum
=
await
page
.
$
(
'
#watch-count-track-num
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
2
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
2
'
)
const
watchCountCleanupRes
=
await
page
.
$
(
'
#watch-count-cleanup-res
'
)
expect
((
await
watchCountCleanupRes
.
text
()).
trim
()).
toBe
(
'
watch count cleanup result:
'
)
expect
((
(
await
watchCountCleanupRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
// watch count and obj.num
const
watchCountAndObjNumRes
=
await
page
.
$
(
'
#watch-count-obj-num-res
'
)
expect
((
await
watchCountAndObjNumRes
.
text
()).
trim
()).
toBe
(
'
watch count and obj.num result:
'
)
expect
((
(
await
watchCountAndObjNumRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
const
incrementBtn
=
await
page
.
$
(
'
.increment-btn
'
)
await
incrementBtn
.
tap
()
expect
(
await
count
.
text
()).
toBe
(
'
count:
1
'
)
expect
(
await
count
.
text
()).
toBe
(
'
1
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
watch count result: count: 1, prevCount: 0, count ref text (flush sync): count
: 0
'
)
'
count: 1, prevCount: 0, count ref text (flush sync)
: 0
'
)
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
android
'
))
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
2
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
2
'
)
}
else
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
4
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
4
'
)
}
expect
((
await
watchCountCleanupRes
.
text
()).
trim
()).
toBe
(
'
watch count cleanup result:
'
)
expect
((
(
await
watchCountCleanupRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
watch count and obj.num result: state: [1,0], preState: [0,0]
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
state: [1,0], preState: [0,0]
'
)
await
incrementBtn
.
tap
()
expect
(
await
count
.
text
()).
toBe
(
'
count: 2
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
watch count result: count: 2, prevCount: 1, count ref text (flush sync): count: 1
'
)
expect
(
await
count
.
text
()).
toBe
(
'
2
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
count: 2, prevCount: 1, count ref text (flush sync): 1
'
)
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
android
'
))
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
2
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
2
'
)
}
else
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
6
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
6
'
)
}
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup
result: watch count cleanup
: 1
'
)
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup: 1
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
watch count and obj.num result: state: [2,0], preState: [1,0]
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
state: [2,0], preState: [1,0]
'
)
// stop watch
const
stopWatchCountBtn
=
await
page
.
$
(
'
.stop-watch-count-btn
'
)
await
stopWatchCountBtn
.
tap
()
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup
result: watch count cleanup
: 2
'
)
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup: 2
'
)
await
incrementBtn
.
tap
()
expect
(
await
count
.
text
()).
toBe
(
'
count: 3
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
watch count result: count: 2, prevCount: 1, count ref text (flush sync): count: 1
'
)
expect
(
await
count
.
text
()).
toBe
(
'
3
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
count: 2, prevCount: 1, count ref text (flush sync): 1
'
)
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
android
'
))
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
2
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
2
'
)
}
else
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
watch count track number:
6
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
6
'
)
}
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup
result: watch count cleanup
: 2
'
)
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup: 2
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
watch count and obj.num result: state: [3,0], preState: [2,0]
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
state: [3,0], preState: [2,0]
'
)
})
it
(
'
obj
'
,
async
()
=>
{
const
objStr
=
await
page
.
$
(
'
#obj-str
'
)
expect
(
await
objStr
.
text
()).
toBe
(
'
obj.str:
num: 0
'
)
expect
(
await
objStr
.
text
()).
toBe
(
'
num: 0
'
)
const
objNum
=
await
page
.
$
(
'
#obj-num
'
)
expect
(
await
objNum
.
text
()).
toBe
(
'
obj.num:
0
'
)
expect
(
await
objNum
.
text
()).
toBe
(
'
0
'
)
const
objBool
=
await
page
.
$
(
'
#obj-bool
'
)
expect
(
await
objBool
.
text
()).
toBe
(
'
obj.bool:
false
'
)
expect
(
await
objBool
.
text
()).
toBe
(
'
false
'
)
const
objArr
=
await
page
.
$
(
'
#obj-arr
'
)
expect
(
await
objArr
.
text
()).
toBe
(
'
obj.arr:
[0]
'
)
expect
(
await
objArr
.
text
()).
toBe
(
'
[0]
'
)
const
watchObjRes
=
await
page
.
$
(
'
#watch-obj-res
'
)
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
android
'
))
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
watch obj result:
obj: {"arr":[0],"bool":false,"num":0,"str":"num: 0"}, prevObj: {"arr":[0],"bool":false,"num":0,"str":"num: 0"}
'
'
obj: {"arr":[0],"bool":false,"num":0,"str":"num: 0"}, prevObj: {"arr":[0],"bool":false,"num":0,"str":"num: 0"}
'
)
}
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
web
'
))
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
watch obj result:
obj: {"num":0,"str":"num: 0","bool":false,"arr":[0]}, prevObj: null
'
'
obj: {"num":0,"str":"num: 0","bool":false,"arr":[0]}, prevObj: null
'
)
}
const
watchObjStrRes
=
await
page
.
$
(
'
#watch-obj-str-res
'
)
expect
((
await
watchObjStrRes
.
text
()).
trim
()).
toBe
(
'
watch obj.str result:
'
)
expect
((
(
await
watchObjStrRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
// trigger
const
watchObjStrTriggerNum
=
await
page
.
$
(
'
#watch-obj-str-trigger-num
'
)
expect
(
await
watchObjStrTriggerNum
.
text
()).
toBe
(
'
watch obj.str trigger number:
0
'
)
expect
(
await
watchObjStrTriggerNum
.
text
()).
toBe
(
'
0
'
)
const
watchObjBoolRes
=
await
page
.
$
(
'
#watch-obj-bool-res
'
)
expect
((
await
watchObjBoolRes
.
text
()).
trim
()).
toBe
(
'
watch obj.bool result:
'
)
expect
((
(
await
watchObjBoolRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
const
watchObjArrRes
=
await
page
.
$
(
'
#watch-obj-arr-res
'
)
expect
((
await
watchObjArrRes
.
text
()).
trim
()).
toBe
(
'
watch obj.arr result:
'
)
expect
((
(
await
watchObjArrRes
.
text
())
||
''
).
trim
()).
toBe
(
'
'
)
const
updateObjBtn
=
await
page
.
$
(
'
.update-obj-btn
'
)
await
updateObjBtn
.
tap
()
expect
(
await
objStr
.
text
()).
toBe
(
'
obj.str:
num: 1
'
)
expect
(
await
objNum
.
text
()).
toBe
(
'
obj.num:
1
'
)
expect
(
await
objBool
.
text
()).
toBe
(
'
obj.bool:
true
'
)
expect
(
await
objArr
.
text
()).
toBe
(
'
obj.arr:
[0,1]
'
)
expect
(
await
objStr
.
text
()).
toBe
(
'
num: 1
'
)
expect
(
await
objNum
.
text
()).
toBe
(
'
1
'
)
expect
(
await
objBool
.
text
()).
toBe
(
'
true
'
)
expect
(
await
objArr
.
text
()).
toBe
(
'
[0,1]
'
)
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
android
'
))
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
watch obj result:
obj: {"arr":[0,1],"bool":true,"num":1,"str":"num: 1"}, prevObj: {"arr":[0,1],"bool":true,"num":1,"str":"num: 1"}
'
'
obj: {"arr":[0,1],"bool":true,"num":1,"str":"num: 1"}, prevObj: {"arr":[0,1],"bool":true,"num":1,"str":"num: 1"}
'
)
}
if
(
process
.
env
.
uniTestPlatformInfo
.
startsWith
(
'
web
'
))
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
watch obj result:
obj: {"num":1,"str":"num: 1","bool":true,"arr":[0,1]}, prevObj: {"num":1,"str":"num: 1","bool":true,"arr":[0,1]}
'
'
obj: {"num":1,"str":"num: 1","bool":true,"arr":[0,1]}, prevObj: {"num":1,"str":"num: 1","bool":true,"arr":[0,1]}
'
)
}
expect
(
await
watchObjStrRes
.
text
()).
toBe
(
'
watch obj.str result: str: num: 1, prevStr: num: 0, obj.str ref text (flush pre): obj.str
: num: 0
'
)
'
str: num: 1, prevStr: num: 0, obj.str ref text (flush pre)
: num: 0
'
)
expect
(
await
watchObjStrTriggerNum
.
text
()).
toBe
(
'
watch obj.str trigger number:
1
'
)
expect
(
await
watchObjStrTriggerNum
.
text
()).
toBe
(
'
1
'
)
expect
(
await
watchObjBoolRes
.
text
()).
toBe
(
'
watch obj.bool result: bool: true, prevBool: false, obj.bool ref text (flush post): obj.bool
: true
'
'
bool: true, prevBool: false, obj.bool ref text (flush post)
: true
'
)
expect
(
await
watchObjArrRes
.
text
()).
toBe
(
'
watch obj.arr result:
arr: [0,1], prevArr: [0,1]
'
)
expect
(
await
watchObjArrRes
.
text
()).
toBe
(
'
arr: [0,1], prevArr: [0,1]
'
)
const
watchCountAndObjNumRes
=
await
page
.
$
(
'
#watch-count-obj-num-res
'
)
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
watch count and obj.num result: state: [3,1], preState: [3,0]
'
)
if
(
watchCountAndObjNumRes
)
{
expect
(
await
watchCountAndObjNumRes
.
text
()).
toBe
(
'
state: [3,1], preState: [3,0]
'
)
}
})
})
\ No newline at end of file
pages/reactivity/core/watch/watch-composition.uvue
0 → 100644
浏览文件 @
2b860713
<template>
<!-- #ifdef APP -->
<scroll-view style="flex: 1; padding-bottom: 20px">
<!-- #endif -->
<view class="page">
<view class="flex justify-between flex-row mb-10">
<text>count:</text>
<text id="count" ref="countRef">{{ count }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch count result:</text>
<text id="watch-count-res">{{ watchCountRes }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>watch count track number:</text>
<text id="watch-count-track-num">{{ watchCountTrackNum }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch count cleanup number:</text>
<text id="watch-count-cleanup-res">{{ watchCountCleanupRes }}</text>
</view>
<button class="increment-btn mb-10" @click="increment">increment</button>
<button class="stop-watch-count-btn mb-10" @click="triggerStopWatchCount">
stop watch count
</button>
<view class="flex justify-between flex-row mb-10">
<text>obj.str:</text>
<text id="obj-str" ref="objStrRef">{{ obj.str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>watch obj.str trigger number:</text>
<text id="watch-obj-str-trigger-num">{{ watchObjStrTriggerNum }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.num:</text>
<text id="obj-num">{{ obj.num }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.bool:</text>
<text id="obj-bool" ref="objBoolRef">{{ obj.bool }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.arr:</text>
<text id="obj-arr" ref="objArrRef">{{ JSON.stringify(obj.arr) }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj result:</text>
<text id="watch-obj-res">{{ watchObjRes }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj.str result:</text>
<text id="watch-obj-str-res">{{ watchObjStrRes }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj.bool result:</text>
<text id="watch-obj-bool-res">{{ watchObjBoolRes }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj.arr result:</text>
<text id="watch-obj-arr-res">{{ watchObjArrRes }}</text>
</view>
<button class="update-obj-btn mb-10" @click="updateObj">
update obj
</button>
<view class="flex justify-between mb-10">
<text>watch count and obj.num result:</text>
<text id="watch-count-obj-num-res">{{ watchCountAndObjNumRes }}</text>
</view>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
type Obj = {
num : number,
str : string,
bool : boolean,
arr : number[]
}
const countRef = ref<UniTextElement | null>(null)
const count = ref(0)
const watchCountRes = ref('')
const watchCountCleanupRes = ref('')
const watchCountTrackNum = ref(0)
const stopWatchCount = watch(count, (count : number, prevCount : number, onCleanup : OnCleanup) => {
// #ifdef APP
watchCountRes.value = `count: ${count}, prevCount: ${prevCount}, count ref text (flush sync): ${countRef.value!.value}`
// #endif
// #ifdef WEB
watchCountRes.value = `count: ${count}, prevCount: ${prevCount}, count ref text (flush sync): ${(countRef.value!.childNodes[0] as HTMLElement).innerText}`
// #endif
const cancel = () => {
watchCountCleanupRes.value = `watch count cleanup: ${count}`
}
onCleanup(cancel)
}, {
// 侦听器在响应式依赖改变时立即触发
flush: 'sync',
// 响应属性或引用作为依赖项被跟踪时调用
// TODO: vue 3.4 开始, 数据更新,也会触发 onTrack, 待升级 vue 版本时,需要确认该变化是否合理及跟进
onTrack(event : DebuggerEvent) {
if (event.type === 'get') {
watchCountTrackNum.value++
}
}
// TODO: vue>3.4.15 开始 监听函数、onTrack、onTrigger 同时存在修改响应式数据时,会报错 Maximum call stack size exceeded
// 所以将 onTrack 与 onTrigger 调整到两个 watch 里
})
const triggerStopWatchCount = () => stopWatchCount()
const increment = () => {
count.value++
}
const obj = reactive({
num: 0,
str: 'num: 0',
bool: false,
arr: [0]
} as Obj)
// immediate: true 第一次触发, 旧值应该是 undefined, 现在 app 是初始值
const watchObjRes = ref('')
watch(obj, (obj : Obj, prevObj ?: Obj) => {
watchObjRes.value = `obj: ${JSON.stringify(obj)}, prevObj: ${JSON.stringify(prevObj)}`
}, { immediate: true })
const objStrRef = ref<UniTextElement | null>(null)
const watchObjStrRes = ref('')
const watchObjStrTriggerNum = ref(0)
watch(() : string => obj.str, (str : string, prevStr : string) => {
// #ifdef APP
watchObjStrRes.value = `str: ${str}, prevStr: ${prevStr}, obj.str ref text (flush pre): ${objStrRef.value!.value}`
// #endif
// #ifdef WEB
watchObjStrRes.value = `str: ${str}, prevStr: ${prevStr}, obj.str ref text (flush pre): ${(objStrRef.value!.childNodes[0] as HTMLElement).innerText}`
// #endif
}, {
// 侦听器在组件渲染之前触发
flush: 'pre',
// 侦听器回调被依赖项的变更触发时调用
onTrigger(event : DebuggerEvent) {
if (event.type === 'set') {
watchObjStrTriggerNum.value++
}
}
})
const objBoolRef = ref<UniTextElement | null>(null)
const watchObjBoolRes = ref('')
watch(() : boolean => obj.bool, (bool : boolean, prevBool : boolean) => {
// #ifdef APP
watchObjBoolRes.value = `bool: ${bool}, prevBool: ${prevBool}, obj.bool ref text (flush post): ${objBoolRef.value!.value}`
// #endif
// #ifdef WEB
watchObjBoolRes.value = `bool: ${bool}, prevBool: ${prevBool}, obj.bool ref text (flush post): ${(objBoolRef.value!.childNodes[0] as HTMLElement).innerText}`
// #endif
}, {
// 侦听器延迟到组件渲染之后触发
flush: 'post'
})
const watchObjArrRes = ref('')
watch(() : number[] => obj.arr, (arr : number[], prevArr : number[]) => {
watchObjArrRes.value = `arr: ${JSON.stringify(arr)}, prevArr: ${JSON.stringify(prevArr)}`
}, { deep: true })
const watchCountAndObjNumRes = ref('')
watch([count, () : number => obj.num], (state : number[], preState : number[]) => {
watchCountAndObjNumRes.value = `state: ${JSON.stringify(state)}, preState: ${JSON.stringify(preState)}`
})
const updateObj = () => {
obj.num++
obj.str = `num: ${obj.num}`
obj.bool = !obj.bool
obj.arr.push(obj.num)
}
</script>
pages/reactivity/core/watch/watch-options.test.js
0 → 100644
浏览文件 @
2b860713
// TODO: 确认各端差异
const
OPTIONS_PAGE_PATH
=
'
/pages/reactivity/core/watch/watch-options
'
describe
(
'
watch
'
,
()
=>
{
let
page
=
null
const
platformInfo
=
process
.
env
.
uniTestPlatformInfo
.
toLowerCase
()
const
isAndroid
=
platformInfo
.
startsWith
(
'
android
'
)
const
isIos
=
platformInfo
.
startsWith
(
'
ios
'
)
const
isApp
=
isAndroid
||
isIos
const
isWeb
=
platformInfo
.
startsWith
(
'
web
'
)
beforeAll
(
async
()
=>
{
page
=
await
program
.
reLaunch
(
OPTIONS_PAGE_PATH
)
await
page
.
waitFor
(
1000
)
})
it
(
'
count
'
,
async
()
=>
{
const
count
=
await
page
.
$
(
'
#count
'
)
expect
(
await
count
.
text
()).
toBe
(
'
0
'
)
// watch
const
watchCountRes
=
await
page
.
$
(
'
#watch-count-res
'
)
expect
(((
await
watchCountRes
.
text
())
||
''
).
trim
()).
toBe
(
''
)
// track
const
watchCountTrackNum
=
await
page
.
$
(
'
#watch-count-track-num
'
)
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
1
'
)
const
watchCountCleanupRes
=
await
page
.
$
(
'
#watch-count-cleanup-res
'
)
expect
(((
await
watchCountCleanupRes
.
text
())
||
''
).
trim
()).
toBe
(
''
)
const
incrementBtn
=
await
page
.
$
(
'
.increment-btn
'
)
await
incrementBtn
.
tap
()
expect
(
await
count
.
text
()).
toBe
(
'
1
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
count: 1, prevCount: 0, count ref text (flush sync): 0
'
)
if
(
isAndroid
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
1
'
)
}
if
(
isIos
||
isWeb
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
2
'
)
}
expect
(((
await
watchCountCleanupRes
.
text
())
||
''
).
trim
()).
toBe
(
''
)
await
incrementBtn
.
tap
()
expect
(
await
count
.
text
()).
toBe
(
'
2
'
)
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
count: 2, prevCount: 1, count ref text (flush sync): 1
'
)
if
(
isAndroid
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
1
'
)
}
if
(
isIos
||
isWeb
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
3
'
)
}
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup: 1
'
)
// stop watch
const
stopWatchCountBtn
=
await
page
.
$
(
'
.stop-watch-count-btn
'
)
await
stopWatchCountBtn
.
tap
()
if
(
isApp
)
{
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup: 1
'
)
}
if
(
isWeb
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
3
'
)
}
await
incrementBtn
.
tap
()
expect
(
await
count
.
text
()).
toBe
(
'
3
'
)
if
(
isApp
)
{
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
count: 3, prevCount: 2, count ref text (flush sync): 2
'
)
}
if
(
isWeb
)
{
expect
(
await
watchCountRes
.
text
()).
toBe
(
'
count: 2, prevCount: 1, count ref text (flush sync): 1
'
)
}
if
(
isAndroid
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
1
'
)
}
if
(
isIos
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
4
'
)
}
if
(
isWeb
)
{
expect
(
await
watchCountTrackNum
.
text
()).
toBe
(
'
3
'
)
}
expect
(
await
watchCountCleanupRes
.
text
()).
toBe
(
'
watch count cleanup: 2
'
)
})
it
(
'
obj
'
,
async
()
=>
{
const
objStr
=
await
page
.
$
(
'
#obj-str
'
)
expect
(
await
objStr
.
text
()).
toBe
(
'
num: 0
'
)
const
objNum
=
await
page
.
$
(
'
#obj-num
'
)
expect
(
await
objNum
.
text
()).
toBe
(
'
0
'
)
const
objBool
=
await
page
.
$
(
'
#obj-bool
'
)
expect
(
await
objBool
.
text
()).
toBe
(
'
false
'
)
const
objArr
=
await
page
.
$
(
'
#obj-arr
'
)
expect
(
await
objArr
.
text
()).
toBe
(
'
[0]
'
)
const
watchObjRes
=
await
page
.
$
(
'
#watch-obj-res
'
)
if
(
isAndroid
)
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
obj: {"arr":[0],"bool":false,"num":0,"str":"num: 0"}, prevObj: {"arr":[0],"bool":false,"num":0,"str":"num: 0"}
'
)
}
if
(
isIos
||
isWeb
)
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
obj: {"num":0,"str":"num: 0","bool":false,"arr":[0]}, prevObj: null
'
)
}
const
watchObjStrRes
=
await
page
.
$
(
'
#watch-obj-str-res
'
)
expect
(((
await
watchObjStrRes
.
text
())
||
''
).
trim
()).
toBe
(
''
)
// trigger
const
watchObjStrTriggerNum
=
await
page
.
$
(
'
#watch-obj-str-trigger-num
'
)
expect
(
await
watchObjStrTriggerNum
.
text
()).
toBe
(
'
0
'
)
const
watchObjBoolRes
=
await
page
.
$
(
'
#watch-obj-bool-res
'
)
expect
(((
await
watchObjBoolRes
.
text
())
||
''
).
trim
()).
toBe
(
''
)
const
watchObjArrRes
=
await
page
.
$
(
'
#watch-obj-arr-res
'
)
expect
(((
await
watchObjArrRes
.
text
())
||
''
).
trim
()).
toBe
(
''
)
const
updateObjBtn
=
await
page
.
$
(
'
.update-obj-btn
'
)
await
updateObjBtn
.
tap
()
expect
(
await
objStr
.
text
()).
toBe
(
'
num: 1
'
)
expect
(
await
objNum
.
text
()).
toBe
(
'
1
'
)
expect
(
await
objBool
.
text
()).
toBe
(
'
true
'
)
expect
(
await
objArr
.
text
()).
toBe
(
'
[0,1]
'
)
if
(
isAndroid
)
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
obj: {"arr":[0,1],"bool":true,"num":1,"str":"num: 1"}, prevObj: {"arr":[0,1],"bool":true,"num":1,"str":"num: 1"}
'
)
}
if
(
isIos
||
isWeb
)
{
expect
(
await
watchObjRes
.
text
()).
toBe
(
'
obj: {"num":1,"str":"num: 1","bool":true,"arr":[0,1]}, prevObj: {"num":1,"str":"num: 1","bool":true,"arr":[0,1]}
'
)
}
expect
(
await
watchObjStrRes
.
text
()).
toBe
(
'
str: num: 1, prevStr: num: 0, obj.str ref text (flush pre): num: 0
'
)
expect
(
await
watchObjStrTriggerNum
.
text
()).
toBe
(
'
0
'
)
expect
(
await
watchObjBoolRes
.
text
()).
toBe
(
'
bool: true, prevBool: false, obj.bool ref text (flush post): true
'
)
expect
(
await
watchObjArrRes
.
text
()).
toBe
(
'
arr: [0,1], prevArr: [0,1]
'
)
})
})
\ No newline at end of file
pages/reactivity/core/watch/watch-options.uvue
0 → 100644
浏览文件 @
2b860713
<template>
<!-- #ifdef APP -->
<scroll-view style="flex: 1; padding-bottom: 20px">
<!-- #endif -->
<view class="page">
<view class="flex justify-between flex-row mb-10">
<text>count:</text>
<text id="count" ref="countRef">{{ count }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch count result:</text>
<text id="watch-count-res">{{ watchCountRes }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>watch count track number:</text>
<text id="watch-count-track-num">{{ watchCountTrackNum }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch count cleanup number:</text>
<text id="watch-count-cleanup-res">{{ watchCountCleanupRes }}</text>
</view>
<button class="increment-btn mb-10" @click="increment">increment</button>
<button class="stop-watch-count-btn mb-10" @click="triggerStopWatchCount">
stop watch count
</button>
<view class="flex justify-between flex-row mb-10">
<text>obj.str:</text>
<text id="obj-str" ref="objStrRef">{{ obj.str }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>watch obj.str trigger number:</text>
<text id="watch-obj-str-trigger-num">{{ watchObjStrTriggerNum }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.num:</text>
<text id="obj-num">{{ obj.num }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.bool:</text>
<text id="obj-bool" ref="objBoolRef">{{ obj.bool }}</text>
</view>
<view class="flex justify-between flex-row mb-10">
<text>obj.arr:</text>
<text id="obj-arr" ref="objArrRef">{{ JSON.stringify(obj.arr) }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj result:</text>
<text id="watch-obj-res">{{ watchObjRes }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj.str result:</text>
<text id="watch-obj-str-res">{{ watchObjStrRes }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj.bool result:</text>
<text id="watch-obj-bool-res">{{ watchObjBoolRes }}</text>
</view>
<view class="flex justify-between mb-10">
<text>watch obj.arr result:</text>
<text id="watch-obj-arr-res">{{ watchObjArrRes }}</text>
</view>
<button class="update-obj-btn mb-10" @click="updateObj">
update obj
</button>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script lang="uts">
type Obj = {
num : number,
str : string,
bool : boolean,
arr : number[]
}
export default {
data() {
return {
countRef: null as UniTextElement | null,
count: 0,
watchCountRes: '',
watchCountCleanupRes: '',
watchCountTrackNum: 0,
stopWatchCount: () => { },
obj: {
num: 0,
str: 'num: 0',
bool: false,
arr: [0]
} as Obj,
watchObjRes: '',
objStrRef: null as UniTextElement | null,
watchObjStrRes: '',
watchObjStrTriggerNum: 0,
objBoolRef: null as UniTextElement | null,
watchObjBoolRes: '',
watchObjArrRes: '',
}
},
onReady() {
// TODO: app-android this.$watch 返回类型不对
// watchCountTrackNum 各端表现也不一致
const self = this
// #ifdef APP
this.$watch('count',
function (count : number, prevCount : number, onCleanup : OnCleanup) {
this.watchCountRes = `count: ${count}, prevCount: ${prevCount}, count ref text (flush sync): ${(this.$refs['countRef'] as UniTextElement).value}`
const cancel = () => {
this.watchCountCleanupRes = `watch count cleanup: ${count}`
}
onCleanup(cancel)
},
{
// 侦听器在响应式依赖改变时立即触发
flush: 'sync',
// 响应属性或引用作为依赖项被跟踪时调用
// TODO: vue 3.4 开始, 数据更新,也会触发 onTrack, 待升级 vue 版本时,需要确认该变化是否合理及跟进
onTrack(event : DebuggerEvent) {
if (event.type === 'get') {
self.watchCountTrackNum++
}
}
// TODO: vue>3.4.15 开始 监听函数、onTrack、onTrigger 同时存在修改响应式数据时,会报错 Maximum call stack size exceeded
// 所以将 onTrack 与 onTrigger 调整到两个 watch 里
})
// #endif
// #ifdef WEB
this.stopWatchCount = this.$watch(
'count',
function (count : number, prevCount : number, onCleanup : OnCleanup) {
this.watchCountRes = `count: ${count}, prevCount: ${prevCount}, count ref text (flush sync): ${this.$refs['countRef'].childNodes[0].innerText}`
const cancel = () => {
this.watchCountCleanupRes = `watch count cleanup: ${count}`
}
onCleanup(cancel)
},
{
// 侦听器在响应式依赖改变时立即触发
flush: 'sync',
// 响应属性或引用作为依赖项被跟踪时调用
// TODO: vue 3.4 开始, 数据更新,也会触发 onTrack, 待升级 vue 版本时,需要确认该变化是否合理及跟进
onTrack(event : DebuggerEvent) {
if (event.type === 'get') {
self.watchCountTrackNum++
}
}
// TODO: vue>3.4.15 开始 监听函数、onTrack、onTrigger 同时存在修改响应式数据时,会报错 Maximum call stack size exceeded
// 所以将 onTrack 与 onTrigger 调整到两个 watch 里
})
// #endif
},
watch: {
obj: {
handler(obj : Obj, prevObj ?: Obj) {
this.watchObjRes = `obj: ${JSON.stringify(obj)}, prevObj: ${JSON.stringify(prevObj)}`
},
// immediate: true 第一次触发, 旧值应该是 undefined, 现在 app 是初始值
immediate: true,
deep: true
},
'obj.str': function (str : string, prevStr : string) {
// #ifdef APP
this.watchObjStrRes = `str: ${str}, prevStr: ${prevStr}, obj.str ref text (flush pre): ${(this.$refs['objStrRef'] as UniTextElement).value}`
// #endif
// #ifdef WEB
this.watchObjStrRes = `str: ${str}, prevStr: ${prevStr}, obj.str ref text (flush pre): ${this.$refs.objStrRef.childNodes[0].innerText}`
// #endif
},
'obj.bool': {
handler: function (bool : boolean, prevBool : boolean) {
// #ifdef APP
this.watchObjBoolRes = `bool: ${bool}, prevBool: ${prevBool}, obj.bool ref text (flush post): ${(this.$refs['objBoolRef'] as UniTextElement).value}`
// #endif
// #ifdef WEB
this.watchObjBoolRes = `bool: ${bool}, prevBool: ${prevBool}, obj.bool ref text (flush post): ${this.$refs.objBoolRef.childNodes[0].innerText}`
// #endif
},
// 侦听器延迟到组件渲染之后触发
flush: 'post',
deep: true
},
'obj.arr': {
handler: function (arr : number[], prevArr : number[]) {
this.watchObjArrRes = `arr: ${JSON.stringify(arr)}, prevArr: ${JSON.stringify(prevArr)}`
},
deep: true
}
},
methods: {
triggerStopWatchCount() {
// #ifdef WEB
this.stopWatchCount()
// #endif
},
increment() {
this.count++
},
updateObj() {
this.obj.num++
this.obj.str = `num: ${this.obj.num}`
this.obj.bool = !this.obj.bool
this.obj.arr.push(this.obj.num)
}
}
}
</script>
\ No newline at end of file
pages/reactivity/core/watch/watch.uvue
已删除
100644 → 0
浏览文件 @
389ac221
<template>
<!-- #ifdef APP -->
<scroll-view style="flex: 1; padding-bottom: 20px">
<!-- #endif -->
<view class="page">
<text id="count" ref="countRef" class="mb-10">count: {{ count }}</text>
<text id="watch-count-res" class="mb-10">watch count result: {{ watchCountRes }}</text>
<text id="watch-count-track-num" class="mb-10">watch count track number: {{ watchCountTrackNum }}</text>
<text id="watch-count-cleanup-res" class="mb-10">watch count cleanup result:
{{ watchCountCleanupRes }}</text>
<button class="increment-btn mb-10" @click="increment">
increment
</button>
<button class="stop-watch-count-btn mb-10" @click="triggerStopWatchCount">
stop watch count
</button>
<text id="obj-str" ref="objStrRef" class="mb-10">obj.str: {{ obj.str }}</text>
<text id="watch-obj-str-trigger-num" class="mb-10">watch obj.str trigger number:
{{ watchObjStrTriggerNum }}</text>
<text id="obj-num" class="mb-10">obj.num: {{ obj.num }}</text>
<text id="obj-bool" ref="objBoolRef" class="mb-10">obj.bool: {{ obj.bool }}</text>
<text id="obj-arr" ref="objArrRef" class="mb-10">obj.arr: {{ JSON.stringify(obj.arr) }}</text>
<text id="watch-obj-res" class="mb-10">watch obj result: {{ watchObjRes }}</text>
<text id="watch-obj-str-res" class="mb-10">watch obj.str result: {{ watchObjStrRes }}</text>
<text id="watch-obj-bool-res" class="mb-10">watch obj.bool result: {{ watchObjBoolRes }}</text>
<text id="watch-obj-arr-res" class="mb-10">watch obj.arr result: {{ watchObjArrRes }}</text>
<button class="update-obj-btn mb-10" @click="updateObj">
update obj
</button>
<text id="watch-count-obj-num-res" class="mb-10">watch count and obj.num result:
{{ watchCountAndObjNumRes }}</text>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup>
type Obj = {
num : number,
str : string,
bool : boolean,
arr : number[]
}
const countRef = ref<UniTextElement | null>(null)
const count = ref(0)
const watchCountRes = ref('')
const watchCountCleanupRes = ref('')
const watchCountTrackNum = ref(0)
const stopWatchCount = watch(count, (count : number, prevCount : number, onCleanup : OnCleanup) => {
// #ifdef APP
watchCountRes.value = `count: ${count}, prevCount: ${prevCount}, count ref text (flush sync): ${countRef.value!.value}`
// #endif
// #ifdef WEB
watchCountRes.value = `count: ${count}, prevCount: ${prevCount}, count ref text (flush sync): ${(countRef.value!.childNodes[0] as HTMLElement).innerText}`
// #endif
const cancel = () => {
watchCountCleanupRes.value = `watch count cleanup: ${count}`
}
onCleanup(cancel)
}, {
// 侦听器在响应式依赖改变时立即触发
flush: 'sync',
// 响应属性或引用作为依赖项被跟踪时调用
// TODO: vue 3.4 开始, 数据更新,也会触发 onTrack, 待升级 vue 版本时,需要确认该变化是否合理及跟进
onTrack(event : DebuggerEvent) {
if (event.type === 'get') {
watchCountTrackNum.value++
}
}
// TODO: vue>3.4.15 开始 监听函数、onTrack、onTrigger 同时存在修改响应式数据时,会报错 Maximum call stack size exceeded
// 所以将 onTrack 与 onTrigger 调整到两个 watch 里
})
const triggerStopWatchCount = () => stopWatchCount()
const increment = () => {
count.value++
}
const obj = reactive({
num: 0,
str: 'num: 0',
bool: false,
arr: [0]
} as Obj)
// immediate: true 第一次触发, 旧值应该是 undefined, 现在 app 是初始值
const watchObjRes = ref('')
watch(obj, (obj : Obj, prevObj ?: Obj) => {
watchObjRes.value = `obj: ${JSON.stringify(obj)}, prevObj: ${JSON.stringify(prevObj)}`
}, { immediate: true })
const objStrRef = ref<UniTextElement | null>(null)
const watchObjStrRes = ref('')
const watchObjStrTriggerNum = ref(0)
watch(() : string => obj.str, (str : string, prevStr : string) => {
// #ifdef APP
watchObjStrRes.value = `str: ${str}, prevStr: ${prevStr}, obj.str ref text (flush pre): ${objStrRef.value!.value}`
// #endif
// #ifdef WEB
watchObjStrRes.value = `str: ${str}, prevStr: ${prevStr}, obj.str ref text (flush pre): ${(objStrRef.value!.childNodes[0] as HTMLElement).innerText}`
// #endif
}, {
// 侦听器在组件渲染之前触发
flush: 'pre',
// 侦听器回调被依赖项的变更触发时调用
onTrigger(event : DebuggerEvent) {
if (event.type === 'set') {
watchObjStrTriggerNum.value++
}
}
})
const objBoolRef = ref<UniTextElement | null>(null)
const watchObjBoolRes = ref('')
watch(() : boolean => obj.bool, (bool : boolean, prevBool : boolean) => {
// #ifdef APP
watchObjBoolRes.value = `bool: ${bool}, prevBool: ${prevBool}, obj.bool ref text (flush post): ${objBoolRef.value!.value}`
// #endif
// #ifdef WEB
watchObjBoolRes.value = `bool: ${bool}, prevBool: ${prevBool}, obj.bool ref text (flush post): ${(objBoolRef.value!.childNodes[0] as HTMLElement).innerText}`
// #endif
}, {
// 侦听器延迟到组件渲染之后触发
flush: 'post'
})
const watchObjArrRes = ref('')
watch(() : number[] => obj.arr, (arr : number[], prevArr : number[]) => {
watchObjArrRes.value = `arr: ${JSON.stringify(arr)}, prevArr: ${JSON.stringify(prevArr)}`
}, { deep: true })
const watchCountAndObjNumRes = ref('')
watch([count, () : number => obj.num], (state : number[], preState : number[]) => {
watchCountAndObjNumRes.value = `state: ${JSON.stringify(state)}, preState: ${JSON.stringify(preState)}`
})
const updateObj = () => {
obj.num++
obj.str = `num: ${obj.num}`
obj.bool = !obj.bool
obj.arr.push(obj.num)
}
</script>
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录