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