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 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 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 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 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)。