WebLocalPool.ets
6.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
import { UIContext } from '@ohos.arkui.UIContext';
import { NodeController, BuilderNode, FrameNode } from '@ohos.arkui.node';
import { BusinessError } from '@ohos.base';
import { WebNetErrorList } from '@ohos.web.netErrorList';
import { Logger } from 'wdKit';
// @Builder中为动态组件的具体组件内容
// WebViewPoolData为入参封装类
class WebViewPoolData {
target: string = ''
webOption: WebOptions = { } as WebOptions
webEvents?: WebEvents = undefined
webHeight: Length = 0
constructor(webOption: WebOptions, target: string, webHeight: Length, webEvent?:WebEvents) {
this.webOption = webOption
this.webEvents = webEvent
this.target = target
this.webHeight = webHeight
}
}
const TAG = 'WebViewPool';
// 影响web组件加载的网络错误码
class webLoadFail {
static ERR_TIMED_OUT = WebNetErrorList.ERR_TIMED_OUT;
static ERR_NETWORK_CHANGED = WebNetErrorList.ERR_NETWORK_CHANGED;
}
// 不需要重试刷新的网络错误码
class excludeRetryLoad {
static ERR_FAILED = WebNetErrorList.ERR_FAILED;
}
function isErrorCode(code: string) {
return Object.keys(webLoadFail).includes(code);
}
@Component
export struct DynamicWebView {
target: string = '';
private webOption: WebOptions = { } as WebOptions
private webEvents?: WebEvents = undefined
@Prop webHeight: Length
aboutToAppear(): void {
}
build() {
Row() {
Web(this.webOption)
.backgroundColor(Color.White)
.domStorageAccess(true)
.databaseAccess(true)
.javaScriptAccess(true)
.imageAccess(true)
.mixedMode(MixedMode.All)
.onlineImageAccess(true)
.nestedScroll({
scrollForward: NestedScrollMode.SELF_FIRST,
scrollBackward: NestedScrollMode.PARENT_FIRST
})
.width('100%')
.height('100%')
.onPageBegin((event) => {
this.webEvents?.onPageBegin(event)
})
.onPageEnd((event) => {
this.webEvents?.onPageEnd(event)
})
.onLoadIntercept((event) => {
if (!this.webEvents) {
return false
}
return this.webEvents?.onLoadIntercept(event);
})
}.width('100%')
.height(this.webHeight)
}
}
@Builder
export function webBuilder(data: WebViewPoolData) {
DynamicWebView({
webOption: data.webOption,
target: data.target,
webEvents: data.webEvents,
webHeight: data.webHeight
})
}
export class WebNodeController extends NodeController {
private rootNode: BuilderNode<[WebViewPoolData]> | null = null;
public webOption: WebOptions = { } as WebOptions
public webEvents?: WebEvents = undefined
private webHeight: Length = 0
private target: string = '';
public webNodeInTree:boolean = false;
constructor(webOption: WebOptions, target: string, webHeight: Length, webEvent?:WebEvents) {
super();
this.webOption = webOption
this.webEvents = webEvent
this.target = target
this.webHeight = webHeight
}
aboutToAppear(): void {
this.webNodeInTree = true;
Logger.debug(TAG, `WebNodeController aboutToAppear target: ${this.target} ==> url:${this.webOption.src.toString()}`);
}
aboutToDisappear(): void {
try {
this.webNodeInTree = false;
// 下树时给commonWebView加载空白页面
// if (!getNWeb(this.target)) {
// this.webOption.controller?.loadData(
// "<html><body bgcolor=\"#18181A\"></body></html>",
// "text/html",
// "UTF-8"
// );
// }
Logger.debug(TAG, `WebNodeController aboutToDisappear target: ${this.target} ==> url:${this.webOption.src.toString()}`);
} catch (error) {
Logger.error(TAG,`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
}
makeNode(context: UIContext): FrameNode | null {
if (!context) {
Logger.error(TAG, " uicontext is undifined : " + (context === undefined));
}
if (this.rootNode != null) {
// 返回FrameNode节点
return this.rootNode.getFrameNode();
}
// 返回null控制动态组件脱离绑定节点
return null;
}
// 此函数为自定义函数,可作为初始化函数使用
// 通过UIContext初始化BuilderNode,再通过BuilderNode中的build接口初始化@Builder中的内容
initWeb(uiContext: UIContext) {
if (this.rootNode != null) {
return;
}
this.rootNode = new BuilderNode(uiContext);
this.rootNode.build(wrapBuilder<[WebViewPoolData]>(webBuilder),
new WebViewPoolData(this.webOption, this.target, this.webHeight, this.webEvents));
}
prepareForReuse(): boolean | undefined {
return this.webEvents?.onPrepareForReuse()
}
destoryWeb() {
this.rootNode?.dispose()
this.rootNode = null
}
updateWebHeight(webHeight: Length) {
try {
if (this.rootNode !== null) {
this.webHeight = webHeight
this.rootNode.update(new WebViewPoolData(this.webOption, this.target, this.webHeight, this.webEvents));
}
} catch (err) {
Logger.warn(TAG, `commonWebView update error : ${err}`);
}
}
updateWebEvents(webEvent: WebEvents) {
try {
if (this.rootNode !== null) {
this.webEvents = webEvent
this.rootNode.update(new WebViewPoolData(this.webOption, this.target, this.webHeight, this.webEvents));
}
} catch (err) {
Logger.warn(TAG, `commonWebView update error : ${err}`);
}
}
}
export interface WebEvents {
onPrepareForReuse(): boolean
onPageBegin(event: OnPageBeginEvent): void;
onPageEnd(event: OnPageEndEvent): void;
onLoadIntercept(event: OnLoadInterceptEvent): boolean;
}
// 创建Map保存所需要的NodeController
const nodeMap: Map<string, WebNodeControllerInfo> = new Map();
// NodeController内容和创建时间戳
class WebNodeControllerInfo {
webNodeController?: WebNodeController;
createTime: number = 0;
constructor(webNodeController: WebNodeController, createTime: number) {
this.webNodeController = webNodeController;
this.createTime = createTime;
}
}
// 自定义获取NodeController接口
export const getPoolWebNodeController = (target: string): WebNodeController | undefined => {
return nodeMap.get(target)?.webNodeController;
}
// 自定义获取WebviewController接口
export const getPoolWebController = (target: string): WebviewController | undefined => {
return nodeMap.get(target)?.webNodeController?.webOption.controller as WebviewController;
}
// 初始化需要UIContext 需在Ability获取
export const createReuseableWeb = (uiContext: UIContext, webOption: WebOptions, target: string, webHeight: Length, webEvent?:WebEvents) => {
// 创建NodeController
let baseNode = new WebNodeController(webOption, target, webHeight, webEvent);
// 初始化自定义Web组件
baseNode.initWeb(uiContext);
nodeMap.set(target, new WebNodeControllerInfo(baseNode, Date.now()));
}
export const destoryReuseableWeb = (target: string) => {
if (nodeMap.get(target)) {
getPoolWebNodeController(target)?.destoryWeb()
nodeMap.delete(target)
}
}