• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用Web组件上传文件
2<!--Kit: ArkWeb-->
3<!--Subsystem: Web-->
4<!--Owner: @zourongchun-->
5<!--Designer: @zhufenghao-->
6<!--Tester: @ghiker-->
7<!--Adviser: @HelloCrease-->
8
9Web组件支持前端页面选择文件上传功能,应用开发者可以使用[onShowFileSelector()](../reference/apis-arkweb/arkts-basic-components-web-events.md#onshowfileselector9)接口来处理前端页面文件上传的请求,如果应用开发者不做任何处理,Web会提供默认行为来处理前端页面文件上传的请求。
10
11## 使用onShowFileSelector拉起文件管理器
12
13下面的示例中,当用户在前端页面点击文件上传按钮,应用侧在[onShowFileSelector()](../reference/apis-arkweb/arkts-basic-components-web-events.md#onshowfileselector9)接口中收到文件上传请求,在此接口中开发者将上传的本地文件路径设置给前端页面。
14
15
16- 应用侧代码。
17
18  ```ts
19  // xxx.ets
20  import { webview } from '@kit.ArkWeb';
21  import { BusinessError } from '@kit.BasicServicesKit';
22  import { picker } from '@kit.CoreFileKit';
23
24  @Entry
25  @Component
26  struct WebComponent {
27    controller: webview.WebviewController = new webview.WebviewController();
28
29    build() {
30      Column() {
31        Web({ src: $rawfile('local.html'), controller: this.controller })
32          .onShowFileSelector((event) => {
33            console.info('MyFileUploader onShowFileSelector invoked');
34            const documentSelectOptions = new picker.DocumentSelectOptions();
35            let uri: string | null = null;
36            const documentViewPicker = new picker.DocumentViewPicker();
37            documentViewPicker.select(documentSelectOptions).then((documentSelectResult) => {
38              uri = documentSelectResult[0];
39              console.info('documentViewPicker.select to file succeed and uri is:' + uri);
40              if (event) {
41                event.result.handleFileList([uri]);
42              }
43            }).catch((err: BusinessError) => {
44              console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
45            })
46            return true;
47          })
48      }
49    }
50  }
51  ```
52
53
54- local.html页面代码。
55
56  ```html
57  <!DOCTYPE html>
58  <html>
59  <head>
60      <meta charset="utf-8">
61      <meta name="viewport" content="width=device-width" />
62      <title>Document</title>
63  </head>
64
65  <body>
66  <!-- 点击上传文件按钮 -->
67  <input type="file"><br>
68  </body>
69  </html>
70  ```
71![web-app-document](./figures/web-app-document.gif)
72
73## 使用onShowFileSelector拉起图库
74
75下面的示例中,当用户在前端页面点击文件上传按钮,应用侧在[onShowFileSelector()](../reference/apis-arkweb/arkts-basic-components-web-events.md#onshowfileselector9)接口中收到文件上传请求,在此接口中开发者将上传的本地图片路径设置给前端页面。
76
77
78- 应用侧代码。
79
80  ```ts
81  // xxx.ets
82  import { webview } from '@kit.ArkWeb';
83  import { photoAccessHelper } from '@kit.MediaLibraryKit';
84
85  @Entry
86  @Component
87  struct WebComponent {
88    controller: webview.WebviewController = new webview.WebviewController();
89
90    async selectFile(result: FileSelectorResult): Promise<void> {
91      let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
92      let photoPicker = new photoAccessHelper.PhotoViewPicker();
93      // 过滤选择媒体文件类型为IMAGE_VIDEO
94      photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
95      // 设置最大选择数量
96      photoSelectOptions.maxSelectNumber = 5;
97      let chooseFile: photoAccessHelper.PhotoSelectResult = await photoPicker.select(photoSelectOptions);
98      // 获取选择的文件列表
99      result.handleFileList(chooseFile.photoUris);
100    }
101
102    build() {
103      Column() {
104        Web({ src: $rawfile('local.html'), controller: this.controller })
105          .onShowFileSelector((event) => {
106            if (event) {
107              this.selectFile(event.result);
108            }
109            return true;
110          })
111      }
112    }
113  }
114  ```
115
116
117- local.html页面代码。
118
119  ```html
120  <!DOCTYPE html>
121  <html>
122  <head>
123      <meta charset="utf-8">
124      <meta name="viewport" content="width=device-width" />
125      <title>Document</title>
126  </head>
127
128  <body>
129  <!-- 点击上传文件按钮 -->
130  <input type="file"><br>
131  </body>
132  </html>
133  ```
134![web-app-photo](./figures/web-app-photo.gif)
135
136## 使用onShowFileSelector拉起相机
137
138Web组件支持前端页面上传图片文件时调用相机即时拍照,应用开发者可以使用[onShowFileSelector()](../reference/apis-arkweb/arkts-basic-components-web-events.md#onshowfileselector9)接口来处理前端页面文件上传的请求并自行拉起相机,如果应用开发者不做任何处理,Web会提供默认行为来处理前端页面调用相机的请求。
139
140此示例中,应用侧通过监听[onShowFileSelector](../reference/apis-arkweb/arkts-basic-components-web-events.md#onshowfileselector9)事件并返回`true`拦截ArkWeb默认弹窗,并调用系统CameraPicker拉起相机。
141应用可以通过获取AcceptType对不同类型的目标文件做更精细的筛选。
142
143```ts
144// xxx.ets
145import { webview } from '@kit.ArkWeb';
146import { camera, cameraPicker } from '@kit.CameraKit';
147import { BusinessError } from '@kit.BasicServicesKit';
148import { common } from '@kit.AbilityKit';
149
150async function openCamera(callback: Callback<string>, uiContext: UIContext) {
151  let mContext = uiContext.getHostContext() as common.Context;
152  try {
153    let pickerProfile: cameraPicker.PickerProfile = {
154      cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
155    };
156    let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(mContext,
157      [cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.VIDEO], pickerProfile);
158    callback(pickerResult.resultUri);
159  } catch (error) {
160    let err = error as BusinessError;
161    console.error(`the pick call failed. error code: ${err.code}`);
162  }
163}
164
165@Entry
166@Component
167struct Index {
168  webviewController: webview.WebviewController = new webview.WebviewController();
169
170  build() {
171    Column() {
172      Web({ src: $rawfile("webCamera.html"), controller: this.webviewController })
173        .onShowFileSelector((event) => {
174            //开发者可以通过event.fileSelector.getAcceptType()和event.fileSelector.isCapture()判断文件类型,并有选择地做出筛选以拉起不同的文件选择器
175            openCamera((result) => {
176                if (event) {
177                console.info('Title is ' + event.fileSelector.getTitle());
178                console.info('Mode is ' + event.fileSelector.getMode());
179                console.info('Accept types are ' + event.fileSelector.getAcceptType());
180                console.info('Capture is ' + event.fileSelector.isCapture());
181                event.result.handleFileList([result]);
182                }
183            }, this.getUIContext())
184            return true;
185        })
186    }
187    .height('100%')
188    .width('100%')
189  }
190}
191```
192
193html页面代码
194```html
195<!DOCTYPE html>
196<html lang="en">
197<head>
198    <meta charset="UTF-8">
199    <meta name="viewport" content="width=device-width, initial-scale=1.0">
200    <title>WebCamera</title>
201</head>
202<body>
203    <input type="file" name="photo" id="photo"><br>
204    <img style="display: none;width:200px;" id="img">
205    <script>
206        let photo = document.getElementById("photo");
207        photo.addEventListener("change", preViewImg)
208
209        function preViewImg(event) {
210            let fileReader = new FileReader();
211            let img = document.getElementById("img");
212            fileReader.addEventListener(
213                "load",
214                () => {
215                    // 将图像文件转换为 Base64 字符串
216                    img.src = fileReader.result;
217                    img.style.display = "block";
218                },
219                false
220            );
221            if (event.target.files && event.target.files[0]) {
222              fileReader.readAsDataURL(event.target.files[0]);
223            } else {
224              console.error("File not exist.");
225            }
226        }
227    </script>
228</body>
229</html>
230```
231![web-app-camera](./figures/web-app-camera.gif)
232
233## 使用ArkWeb默认的方式处理文件上传请求
234
235`accept` 属性是一个字符串,它定义了文件 input 应该接受的文件类型。这个字符串是一个以逗号为分隔的唯一文件类型说明符列表。由于给定的文件类型可以用多种方式指定,因此当你需要给定格式的文件时,提供一组完整的类型指定符是非常有用的。
236
237`capture` 属性是一个字符串,如果 `accept` 属性指出了 input 是图片或者视频类型,则它指定了使用哪个摄像头去获取这些数据。值 `user` 表示应该使用前置摄像头和(或)麦克风。值 `environment` 表示应该使用后置摄像头和(或)麦克风。如果缺少此属性,则用户代理可以自由决定做什么。如果请求的前置模式不可用,则用户代理可能退回到其首选的默认模式。
238
239当指定布尔类型属性 `multiple` 时,文件 input 允许用户选择多个文件。
240
241示例页面内有数个文件选择器,分别设置了不同的accept及capture属性,这两个属性对相机的影响如下:
242
243| accept                      | capture                     | 文件选择器行为                                     |
244| --------------------------- | --------------------------- | -------------------------------------------------- |
245| 仅包含图片类型              | 设置为"environment"或"user" | 直接拉起相机拍照模式。                             |
246| 仅包含图片类型               | 不设置                      | 先拉起弹窗,用户选择拍照后拉起相机拍照模式。       |
247| 仅包含视频类型              | 设置为"environment"或"user" | 直接拉起相机录像模式。                             |
248| 仅包含视频类型               | 不设置                      | 先拉起弹窗,用户选择拍照后拉起相机录像模式。       |
249| 包含图片和视频类型          | 设置为"environment"或"user" | 直接拉起相机拍照模式,可录像。                     |
250| 包含图片和视频类型            | 不设置                      | 先拉起弹窗,用户选择拍照后拉起相机拍照模式,可录像。 |
251| 不设置图片或视频类型        | 设置为"environment"或"user" | 直接拉起相机拍照模式,可录像。                     |
252| 不设置图片或视频类型          | 不设置                      | 先拉起弹窗,用户选择拍照后拉起相机拍照模式,可录像。 |
253| 不包含图片或视频类型        | 设置为"environment"或"user" | 直接拉起文件选择,不可拉起相机。                    |
254| 不包含图片或视频类型          | 不设置                      | 直接拉起文件选择,不可拉起相机。                   |
255
256> 当前ArkWeb识别的文件类型有
257>  - 图片:tif, xbm, tiff, pjp, jfif, bmp, avif, apng, ico, webp, svg, gif, svgz, jpg, jpeg, png, pjpeg
258>  - 视频:mp4, mpg, mpeg, m4v, ogm, ogv, webm
259
260>  **说明:**
261>
262> ArkWeb默认仅拉起相机后置摄像头,值 `'user'`不会被处理成拉起前置摄像头。如有需要,请在应用侧通过[onShowFileSelector()](../reference/apis-arkweb/arkts-basic-components-web-events.md#onshowfileselector9)接口另行处理
263
264html页面代码
265```html
266<!DOCTYPE html>
267<html lang="en">
268<head>
269    <meta charset="UTF-8">
270    <meta name="viewport" content="width=device-width, initial-scale=1.0">
271    <title>WebCamera</title>
272</head>
273<body>
274    <input type="file" name="picture" id="picture" accept="image/*"><br>
275    <img style="display: none;width:200px" id="img">
276    <script>
277        let picture = document.getElementById("picture");
278        picture.addEventListener("change", preViewImg)
279
280        function preViewImg(event) {
281            let fileReader = new FileReader();
282            let img = document.getElementById("img");
283            fileReader.addEventListener(
284                "load",
285                () => {
286                    // 将图像文件转换为 Base64 字符串
287                    img.src = fileReader.result;
288                    img.style.display = "block";
289                },
290                false
291            );
292            if (event.target.files && event.target.files[0]) {
293              fileReader.readAsDataURL(event.target.files[0]);
294            } else {
295              console.error("File not exist.");
296            }
297        }
298    </script>
299</body>
300</html>
301```
302
303应用侧代码
304```ts
305// xxx.ets
306import { webview } from '@kit.ArkWeb';
307
308@Entry
309@Component
310struct Index {
311  webviewController: webview.WebviewController = new webview.WebviewController();
312
313  build() {
314    Column() {
315      Web({ src: $rawfile("webCamera.html"), controller: this.webviewController })
316    }
317    .height('100%')
318    .width('100%')
319  }
320}
321```
322![web-default-camera](./figures/web-default-camera.gif)
323
324## 常见问题
325
326### onShowFileSelector配合ArkWeb默认弹窗使用
327
328用户点击文件上传按钮后,程序优先执行onShowFileSelector中的回调进行逻辑处理,应用开发者可以根据处理结果选择 `return false;` ,进而拉起ArkWeb默认弹窗,此时不推荐同时拉起应用侧各Picker。
329
330### 回调中getAcceptType和getMimeTypes的区别
331
332getAcceptType返回的是 `accept` 属性值全量转换为文件扩展名所组成的字符串数组,getMimeTypes返回的是 `accept` 属性值用逗号拆分后所组成的字符串数组。
333
334如若 `accept` 属性值为 `video/mp4, .png` ,则getAcceptType返回  `.mp4, .m4v; .png` ,getMimeTypes返回 `video/mp4; .png` 。
335
336### ArkWeb默认弹窗的说明
337
338选项“图片”会拉起图库,根据 `accept` 属性值不同,用户可以选择上传图片或视频;选项“拍照”会拉起相机,根据 `accept` 属性值不同,用户可以选择拍照或录像;选项“文件”会拉起文件管理器,用户可以上传任意内容。
339
340### handleFileList的使用说明
341
342该函数将选择的文件路径提交给ArkWeb,入参主要有两种类型:
3431. file协议路径,目前只支持前缀为 `file://media/` 、`file://docs/` 的公共路径和 `file://<packageName>/` 的应用包名路径,其他file协议路径无权限。
3442. 沙箱目录,具体参考[应用沙箱目录](../file-management/app-sandbox-directory.md)。