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 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 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 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 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` 属性值不同,用户可以选择拍照或录像;选项“文件”会拉起文管,用户可以上传任意内容。