提交 8a20a93c 编写于 作者: E ester.zhou 提交者: Gitee

Merge branch 'master' of gitee.com:openharmony/docs into TR-9431

Signed-off-by: Nester.zhou <ester.zhou@huawei.com>
......@@ -177,7 +177,6 @@ zh-cn/application-dev/napi/napi-guidelines.md @RayShih
zh-cn/application-dev/napi/drawing-guidelines.md @ge-yafang
zh-cn/application-dev/napi/rawfile-guidelines.md @HelloCrease
zh-cn/application-dev/reference/js-service-widget-ui/ @HelloCrease
zh-cn/application-dev/website.md @zengyawen
zh-cn/application-dev/faqs/ @zengyawen
zh-cn/application-dev/file-management/ @qinxiaowang
zh-cn/application-dev/application-test/ @HelloCrease
......@@ -370,7 +369,6 @@ zh-cn/application-dev/reference/apis/js-apis-useriam-faceauth.md @zengyawen
zh-cn/application-dev/reference/apis/js-apis-userfilemanager.md @qinxiaowang
zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md @zengyawen
zh-cn/application-dev/reference/apis/js-apis-buffer.md @zengyawen
zh-cn/application-dev/reference/apis/Readme-CN.md @zengyawen
zh-cn/application-dev/reference/apis/development-intro.md @zengyawen
zh-cn/application-dev/reference/apis/js-apis-accessibility-extension-context.md @RayShih
zh-cn/application-dev/reference/apis/js-apis-application-abilityLifecycleCallback.md @RayShih
......
# APIs
- [API Reference Document Description](development-intro.md)
- Ability Framework
- FA Model
- [@ohos.ability.featureAbility](js-apis-featureAbility.md)
- [@ohos.ability.particleAbility](js-apis-particleAbility.md)
......@@ -28,8 +26,6 @@
- application/[FormExtensionContext](js-apis-formextensioncontext.md)
- application/[PermissionRequestResult](js-apis-permissionrequestresult.md)
- application/[ServiceExtensionContext](js-apis-service-extension-context.md)
- [InputMethodExtensionAbility](js-apis-inputmethod-extension-ability.md)
- [InputMethodExtensionContext](js-apis-inputmethod-extension-context.md)
- FA and Stage Models
- [@ohos.ability.dataUriUtils](js-apis-DataUriUtils.md)
- [@ohos.ability.errorCode](js-apis-ability-errorCode.md)
......@@ -60,18 +56,15 @@
- application/[ExtensionRunningInfo](js-apis-extensionrunninginfo.md)
- application/[MissionSnapshot](js-apis-application-MissionSnapshot.md)
- application/[ProcessRunningInfo](js-apis-processrunninginfo.md)
- application/[ProcessRunningInformation](js-apis-processrunninginformation.md)
- application/[shellCmdResult](js-apis-application-shellCmdResult.md)
- continuation/[ContinuationResult](js-apis-continuation-continuationResult.md)
- Common Event and Notification
- [@ohos.commonEvent](js-apis-commonEvent.md)
- [@ohos.events.emitter](js-apis-emitter.md)
- [@ohos.notification](js-apis-notification.md)
- [@ohos.reminderAgent](js-apis-reminderAgent.md)
- application/[EventHub](js-apis-eventhub.md)
- Bundle Management
- Bundle Management
- [@ohos.bundle](js-apis-Bundle.md)
- [@ohos.bundle.defaultAppManager](js-apis-bundle-defaultAppManager.md)
- [@ohos.bundle.innerBundleManager)](js-apis-Bundle-InnerBundleManager.md)
......@@ -92,17 +85,13 @@
- bundle/[ModuleInfo](js-apis-bundle-ModuleInfo.md)
- bundle/[PermissionDef](js-apis-bundle-PermissionDef.md)
- bundle/[RemoteAbilityInfo](js-apis-bundle-remoteAbilityInfo.md)
- bundle/[ShortcutInfo](js-apis-bundle-ShortcutInfo.md)
- bundle/[ShortcutInfo<sup>(deprecated)</sup>](js-apis-bundle-ShortcutInfo.md)
- UI Page
- [@ohos.animator](js-apis-animator.md)
- [@ohos.mediaquery](js-apis-mediaquery.md)
- [@ohos.prompt](js-apis-prompt.md)
- [@ohos.router](js-apis-router.md)
- [@ohos.uiAppearance](js-apis-uiappearance.md)
- Graphics
- Graphics
- [@ohos.animation.windowAnimationManager](js-apis-windowAnimationManager.md)
- [@ohos.display ](js-apis-display.md)
- [@ohos.effectKit](js-apis-effectKit.md)
......@@ -111,42 +100,31 @@
- [@ohos.window](js-apis-window.md)
- [webgl](js-apis-webgl.md)
- [webgl2](js-apis-webgl2.md)
- Media
- [@ohos.multimedia.audio](js-apis-audio.md)
- [@ohos.multimedia.camera](js-apis-camera.md)
- [@ohos.multimedia.image](js-apis-image.md)
- [@ohos.multimedia.media](js-apis-media.md)
- [@ohos.multimedia.medialibrary](js-apis-medialibrary.md)
- Resource Management
- [@ohos.i18n](js-apis-i18n.md)
- [@ohos.intl](js-apis-intl.md)
- [@ohos.resourceManager](js-apis-resource-manager.md)
- Resource Scheduling
- Resource Scheduling
- [@ohos.backgroundTaskManager](js-apis-backgroundTaskManager.md)
- [@ohos.distributedMissionManager](js-apis-distributedMissionManager.md)
- [@ohos.workScheduler ](js-apis-workScheduler.md)
- [@ohos.WorkSchedulerExtensionAbility](js-apis-WorkSchedulerExtensionAbility.md)
- Custom Management
- [@ohos.configPolicy](js-apis-config-policy.md)
- [@ohos.enterpriseDeviceManager](js-apis-enterprise-device-manager.md)
- [@ohos.EnterpriseAdminExtensionAbility](js-apis-EnterpriseAdminExtensionAbility.md)
- [@ohos.enterpriseDeviceManager](js-apis-enterprise-device-manager.md)
- enterpriseDeviceManager/[DeviceSettingsManager](js-apis-enterpriseDeviceManager-DeviceSettingsManager.md)
- Security
- [@ohos.abilityAccessCtrl](js-apis-abilityAccessCtrl.md)
- [@ohos.privacyManager](js-apis-privacyManager.md)
- [@ohos.security.huks ](js-apis-huks.md)
- [@ohos.userIAM.userAuth ](js-apis-useriam-userauth.md)
- [@ohos.userIAM.faceAuth](js-apis-useriam-faceauth.md)
- [@ohos.userIAM.userAuth ](js-apis-useriam-userauth.md)
- [@system.cipher](js-apis-system-cipher.md)
- Data Management
......@@ -167,46 +145,40 @@
- [@ohos.document](js-apis-document.md)
- [@ohos.environment](js-apis-environment.md)
- [@ohos.fileio](js-apis-fileio.md)
- [@ohos.fileManager](js-apis-filemanager.md)
- [@ohos.multimedia.medialibrary](js-apis-medialibrary.md)
- [@ohos.securityLabel](js-apis-securityLabel.md)
- [@ohos.statfs](js-apis-statfs.md)
- [@ohos.storageStatistics](js-apis-storage-statistics.md)
- [@ohos.volumeManager](js-apis-volumemanager.md)
- [@ohos.securityLabel](js-apis-securityLabel.md)
- Telephony Service
- [@ohos.contact](js-apis-contact.md)
- [@ohos.telephony.call](js-apis-call.md)
- [@ohos.telephony.data](js-apis-telephony-data.md)
- [@ohos.telephony.observer](js-apis-observer.md)
- [@ohos.telephony.radio](js-apis-radio.md)
- [@ohos.telephony.sim](js-apis-sim.md)
- [@ohos.telephony.sms](js-apis-sms.md)
- [@ohos.telephony.data](js-apis-telephony-data.md)
- Network Management
- [@ohos.net.connection](js-apis-net-connection.md)
- [@ohos.net.http](js-apis-http.md)
- [@ohos.request](js-apis-request.md)
- [@ohos.net.socket](js-apis-socket.md)
- [@ohos.net.webSocket](js-apis-webSocket.md)
- [@ohos.request](js-apis-request.md)
- Connectivity
- [@ohos.bluetooth](js-apis-bluetooth.md)
- [@ohos.connectedTag](js-apis-connectedTag.md)
- [@ohos.nfc.cardEmulation](js-apis-cardEmulation.md)
- [@ohos.nfc.controller](js-apis-nfcController.md)
- [@ohos.nfc.tag](js-apis-nfcTag.md)
- [@ohos.nfc.tag](js-apis-nfctech.md)
- [@ohos.nfc.tag](js-apis-tagSession.md)
- [@ohos.rpc](js-apis-rpc.md)
- [@ohos.wifi](js-apis-wifi.md)
- [@ohos.wifiext](js-apis-wifiext.md)
- [@ohos.nfc.tag](js-apis-nfctech.md)
- [@ohos.nfc.tag](js-apis-tagSession.md)
- Basic Features
- [@ohos.accessibility](js-apis-accessibility.md)
- [@ohos.accessibility.config](js-apis-accessibility-config.md)
- [@ohos.faultLogger](js-apis-faultLogger.md)
- [@ohos.hiAppEvent](js-apis-hiappevent.md)
- [@ohos.hichecker](js-apis-hichecker.md)
......@@ -217,13 +189,15 @@
- [@ohos.hiTraceMeter](js-apis-hitracemeter.md)
- [@ohos.inputMethod](js-apis-inputmethod.md)
- [@ohos.inputMethodEngine](js-apis-inputmethodengine.md)
- [@ohos.inputmethodextensionability](js-apis-inputmethod-extension-ability.md)
- [@ohos.inputmethodextensioncontext](js-apis-inputmethod-extension-context.md)
- [@ohos.pasteboard](js-apis-pasteboard.md)
- [@ohos.screenLock](js-apis-screen-lock.md)
- [@ohos.systemTime](js-apis-system-time.md)
- [@ohos.systemTimer](js-apis-system-timer.md)
- [@ohos.wallpaper](js-apis-wallpaper.md)
- [Timer](js-apis-timer.md)
- Device Management
- [@ohos.batteryInfo ](js-apis-battery-info.md)
......@@ -239,6 +213,7 @@
- [@ohos.multimodalInput.keyCode](js-apis-keycode.md)
- [@ohos.multimodalInput.keyEvent](js-apis-keyevent.md)
- [@ohos.multimodalInput.mouseEvent](js-apis-mouseevent.md)
- [@ohos.multimodalInput.pointer](js-apis-pointer.md)
- [@ohos.multimodalInput.touchEvent](js-apis-touchevent.md)
- [@ohos.power](js-apis-power.md)
- [@ohos.runningLock](js-apis-runninglock.md)
......@@ -249,15 +224,12 @@
- [@ohos.update](js-apis-update.md)
- [@ohos.usb](js-apis-usb.md)
- [@ohos.vibrator](js-apis-vibrator.md)
- Account Management
- Account Management
- [@ohos.account.appAccount](js-apis-appAccount.md)
- [@ohos.account.distributedAccount](js-apis-distributed-account.md)
- [@ohos.account.osAccount](js-apis-osAccount.md)
- Language Base Class Library
- Language Base Class Library
- [@ohos.buffer](js-apis-buffer.md)
- [@ohos.convertxml](js-apis-convertxml.md)
- [@ohos.process](js-apis-process.md)
- [@ohos.uri](js-apis-uri.md)
......@@ -279,16 +251,14 @@
- [@ohos.util.Vector](js-apis-vector.md)
- [@ohos.worker](js-apis-worker.md)
- [@ohos.xml](js-apis-xml.md)
- Test
- [@ohos.application.testRunner](js-apis-testRunner.md)
- [@ohos.uitest](js-apis-uitest.md)
- APIs No Longer Maintained
- APIs No Longer Maintained
- [@ohos.bytrace](js-apis-bytrace.md)
- [@ohos.data.storage](js-apis-data-storage.md)
- [@ohos.prompt](js-apis-prompt.md)
- [@ohos.reminderAgent](js-apis-reminderAgent.md)
- [@system.app](js-apis-system-app.md)
- [@system.battery](js-apis-system-battery.md)
- [@system.bluetooth](js-apis-system-bluetooth.md)
......
# User File Access and Management
The **fileManager** module provides APIs for accessing and managing user files. It interworks with the underlying file management services to implement media library and external card management, and provides capabilities for applications to query and create user files.
>**NOTE**<br/>
>
>- The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
>- The APIs of this module are system APIs and cannot be called by third-party applications. Currently, these APIs can be called only by **filepicker**.
## Modules to Import
```js
import filemanager from '@ohos.fileManager';
```
## filemanager.getRoot
getRoot(options? : {dev? : DevInfo}) : Promise&lt;FileInfo[]&gt;
Obtains information about the root album or directory in asynchronous mode. This API uses a promise to return the result.
**System capability**: SystemCapability.FileManagement.UserFileService
**Parameters**
| Name| Type| Mandatory| Description|
| --- | --- | --- | -- |
| options | Object | No| The options are as follows:<br>- &nbsp;**dev**: See [DevInfo](#devinfo). It is **dev = {name: "local"}** by default if not specified. Currently, only 'local' is supported.|
**Return value**
| Type| Description|
| --- | -- |
| Promise&lt;[FileInfo](#fileinfo)[]&gt; | Promise used to return the root album or directory information obtained.|
**Example**
```js
filemanager.getRoot().then((fileInfos) => {
for (var i = 0; i < fileInfos.length; i++) {
console.log("files:"+JSON.stringify(fileInfos));
}
}).catch((err) => {
console.log(err)
});
```
## filemanager.getRoot
getRoot(options? : {dev? : DevInfo}, callback : AsyncCallback&lt;FileInfo[]&gt;) : void
Obtains information about the root album or directory in asynchronous mode. This API uses a callback to return the result.
**System capability**: SystemCapability.FileManagement.UserFileService
**Parameters**
| Name | Type | Mandatory| Description |
| -------- | ------------------------- | ---- | ----------------------------- |
| options | Object | No| The options are as follows:<br>- &nbsp;**dev**: See [DevInfo](#devinfo). It is **dev = {name: "local"}** by default if not specified. Currently, only 'local' is supported.|
| callback | AsyncCallback&lt;[FileInfo](#fileinfo)[]&gt; | Yes | Callback invoked to return the root album or directory information obtained. |
**Example**
```js
let options = {
"dev":{
"name":"local"
}
};
filemanager.getRoot(options, (err, fileInfos)=>{
for (var i = 0; i < fileInfos.length; i++) {
console.log("files:"+JSON.stringify(fileInfos));
}
});
```
## filemanager.listFile
listFile(path : string, type : string, options? : {dev? : DevInfo, offset? : number, count? : number}) : Promise&lt;FileInfo[]&gt;
Obtains information about the second-level album or files in asynchronous mode. This API uses a promise to return the result.
**System capability**: SystemCapability.FileManagement.UserFileService
**Parameters**
| Name| Type| Mandatory| Description|
| --- | --- | --- | -- |
| path | string | Yes| URI of the directory to query.|
| type | string | Yes| Type of the files to query. The file type can be **file**, **image**, **audio**, or **video**.|
| options | Object | No| The options are as follows:<br>- &nbsp;**dev**: See [DevInfo](#devinfo). It is **dev = {name: "local"}** by default if not specified. Currently, only 'local' is supported.<br>- &nbsp;**offset**: position to start the query. The value is a number.<br>- &nbsp;**count**: number of files to query.|
**Return value**
| Type| Description|
| --- | -- |
| Promise&lt;FileInfo[]&gt; | Promise used to return the album or file information obtained.|
**Error**
| Error Info| Error Code|Description|
| -- | --- | -- |
| No such file or directory | 2 | The directory or album of the specified URI does not exist.|
| No such process | 3 | Failed to obtain the FMS service.|
| Not a directory | 20 | The object specified by the URI is not a directory or album.|
**Example**
```js
// Obtain all files in the directory. You can use getRoot to obtain the directory URI.
filemanager.getRoot().then((fileInfos) => {
let file = fileInfos.find(item => item.name == "file_folder");
let path = file.path;
filemanager.listFile(path, "file").then((files) => {
console.log("files:" + JSON.stringify(files));
}).catch((err) => {
console.log("failed to get files" + err);
});
}).catch((err) => {
console.log("failed to get root" + err);
});
```
## filemanager.listFile
listFile(path : string, type : string, options? : {dev? : DevInfo, offset? : number, count? : number}, callback : AsyncCallback&lt;FileInfo[]&gt;) : void
Obtains information about the second-level album or files in asynchronous mode. This API uses a callback to return the result.
**System capability**: SystemCapability.FileManagement.UserFileService
**Parameters**
| Name | Type | Mandatory| Description |
| -------- | ------------------------- | ---- | ------------------------------------------------------------ |
| path | string | Yes | URI of the directory to query. |
| type | string | Yes | Type of the files to query. The file type can be **file**, **image**, **audio**, or **video**.|
| options | Object | No| The options are as follows:<br>- &nbsp;**dev**: See [DevInfo](#devinfo). It is **dev = {name: "local"}** by default if not specified. Currently, only 'local' is supported.<br>- &nbsp;**offset**: position to start the query. The value is a number.<br>- &nbsp;**count**: number of files to query.|
| callback | AsyncCallback&lt;[FileInfo](#fileinfo)[]&gt; | Yes | Callback invoked to return the root album or directory information obtained. |
**Error**
| Error Info | Error Code| Description |
| ------------------------- | ------ | ------------------------- |
| No such file or directory | 2 | The directory or album of the specified URI does not exist.|
| No such process | 3 | Failed to obtain the FMS service. |
| Not a directory | 20 | The object specified by the URI is not a directory or album.|
**Example**
```js
// Obtain all files in the directory. You can use getRoot to obtain the directory URI.
filemanager.getRoot().then((fileInfos) => {
let file = fileInfos.find(item => item.name == "image_album");
let path = file.path;
filemanager.listFile(path, "image",function(err, files){
console.log("files:" + JSON.stringify(files));
})
}).catch((err) => {
console.log("failed to get root" + err);
});
```
## filemanager.createFile
createFile(path : string, filename : string, options? : {dev? : DevInfo}) : Promise&lt;string&gt;
Creates a file in the specified path in asynchronous mode. This API uses a promise to return the result.
**System capability**: SystemCapability.FileManagement.UserFileService
**Parameters**
| Name| Type| Mandatory| Description|
| --- | --- | --- | -- |
| filename | string | Yes| Name of the file to create.|
| path | string | Yes| URI of the file to create.|
| options | Object | No| The options are as follows:<br>- &nbsp;**dev**: See [DevInfo](#devinfo). It is **dev = {name: "local"}** by default if not specified. Currently, only 'local' is supported.|
**Return value**
| Type| Description|
| --- | -- |
| Promise&lt;string&gt; | Promise used to return the URI of the file created.|
**Error**
| Error Info| Error Code|Description|
| -- | --- | -- |
| Operation not permitted | 1 | A file with the same name already exists.|
| No such file or directory | 2 | The directory or album of the specified URI does not exist.|
| No such process | 3 | Failed to obtain the FMS service.|
| Not a directory | 20 | The object specified by the URI is not a directory or album.|
**Example**
```js
// Create a file.
let media_path = "" // Obtain the file URI using listFile() and getRoot().
let name = "xxx.jpg" // File to be saved.
filemanager.createFile(media_path, name).then((uri) => {
// The URI of the file created is returned.
console.log("file uri:"+uri);
}).catch((err) => {
console.log(err);
});
```
## filemanager.createFile
createFile(path : string, filename: string, options? : {dev? : DevInfo}, callback : AsyncCallback&lt;string&gt;) : void
Creates a file in the specified path in asynchronous mode. This API uses a callback to return the result.
**System capability**: SystemCapability.FileManagement.UserFileService
**Parameters**
| Name | Type | Mandatory| Description |
| -------- | ------------------------- | ---- | ----------------------------- |
| filename | string | Yes | Name of the file to create. |
| path | string | Yes | URI of the file to create. |
| options | Object | No| The options are as follows:<br>- &nbsp;**dev**: See [DevInfo](#devinfo). It is **dev = {name: "local"}** by default if not specified. Currently, only 'local' is supported.|
| callback | AsyncCallback&lt;[FileInfo](#fileinfo)[]&gt; | Yes | Callback invoked to return the root album or directory information obtained. |
**Error**
| Error Info | Error Code| Description |
| ------------------------- | ------ | ------------------------- |
| Operation not permitted | 1 | A file with the same name already exists. |
| No such file or directory | 2 | The directory or album of the specified URI does not exist.|
| No such process | 3 | Failed to obtain the FMS service. |
| Not a directory | 20 | The object specified by the URI is not a directory or album.|
**Example**
```js
// Create a file.
// Call listFile() and getRoot() to obtain the file URI.
let media_path = ""
// File to be saved.
let name = "xxx.jpg"
let options = {
"dev":{
"name":"local"
}
};
filemanager.createFile(media_path, name, options, function(err, uri) {
// The URI of the file created is returned.
console.log("file uri:"+uri);
});
```
## FileInfo
Defines the file information returned by **getRoot()** or **listFile()**.
**System capability**: SystemCapability.FileManagement.UserFileService
### Attributes
| Name| Type| Readable| Writable| Description|
| --- | -- | -- | -- | -- |
| name | string | Yes| No| File name.|
| path | string | Yes| No| URI of the file.|
| type | string | Yes| No| File type.|
| size | number | Yes| No| File size.|
| addedTime | number | Yes| No| Time when the file was scanned to the database.|
| modifiedTime | number | Yes| No| Time when the file was modified.|
## DevInfo
Defines the device type.
**System capability**: SystemCapability.FileManagement.UserFileService
### Attributes
| Name| Type | Readable| Writable| Description |
| ------ | ------ | ---- | ---- | -------- |
| name | string | Yes | Yes | Device name.|
......@@ -11,49 +11,11 @@
- [Resource File Categories](ui-ts-basic-resource-file-categories.md)
- [Resource Access](ts-resource-access.md)
- [Pixel Units](ts-pixel-units.md)
- Declarative Syntax
- [About Usage of UI Description Specifications](ts-syntax-intro.md)
- About General UI Description Specifications
- [Basic Concepts](ts-general-ui-concepts.md)
- Declarative UI Description Specifications
- [Configuration Without Parameters](ts-parameterless-configuration.md)
- [Configuration with Mandatory Parameters](ts-configuration-with-mandatory-parameters.md)
- [Attribute Configuration](ts-attribution-configuration.md)
- [Event Configuration](ts-event-configuration.md)
- [Child Component Configuration](ts-child-component-configuration.md)
- Componentization
- [@Component](ts-component-based-component.md)
- [@Entry](ts-component-based-entry.md)
- [@Preview](ts-component-based-preview.md)
- [@Builder](ts-component-based-builder.md)
- [@Extend](ts-component-based-extend.md)
- [@CustomDialog](ts-component-based-customdialog.md)
- [@Styles](ts-component-based-styles.md)
- About UI State Management
- [Basic Concepts](ts-ui-state-mgmt-concepts.md)
- Managing Component States
- [@State](ts-component-states-state.md)
- [@Prop](ts-component-states-prop.md)
- [@Link](ts-component-states-link.md)
- Managing Application States
- [AppStorage](ts-application-states-appstorage.md)
- [LocalStorage](ui-ts-local-storage.md)
- [PersistentStorage](ts-application-states-apis-persistentstorage.md)
- [Environment](ts-application-states-apis-environment.md)
- Managing Other States
- [@Observed and @ObjectLink](ts-other-states-observed-objectlink.md)
- [@Consume and @Provide](ts-other-states-consume-provide.md)
- [@Watch](ts-other-states-watch.md)
- Rendering Control Syntax
- [if/else](ts-rending-control-syntax-if-else.md)
- [ForEach](ts-rending-control-syntax-foreach.md)
- [LazyForEach](ts-rending-control-syntax-lazyforeach.md)
- About Componentization
- [build Function](ts-function-build.md)
- Componentization
- [Initialization of Custom Components' Member Variables](ts-custom-component-initialization.md)
- [Custom Component Lifecycle Callbacks](ts-custom-component-lifecycle-callbacks.md)
- [Examples: Component Creation and Re-initialization](ts-component-creation-re-initialization.md)
- [About Syntactic Sugar](ts-syntactic-sugar.md)
- [Component Creation and Re-initialization](ts-component-creation-re-initialization.md)
- Common Component Development Guidelines
- [Button](ui-ts-basic-components-button.md)
- [Web](ui-ts-components-web.md)
......
# Environment
Environment is a singleton object created by the framework when the application is started. It provides the AppStorage with a series of environment state attributes required by the application. These attributes describe the device environment where the application runs. Environment and its attributes are immutable, and all attribute values are of the simple type. The following example shows how to obtain the semantic environment from Environment:
```ts
Environment.EnvProp("accessibilityEnabled", "default");
var enable = AppStorage.Get("accessibilityEnabled");
```
accessibilityEnabled is the default system variable identifier provided by Environment. You need to bind the corresponding system attribute to the AppStorage. Then, you can use the methods or decorators in the AppStorage to access the corresponding system attribute data.
## Environment APIs
| key | Parameter | Return Value | Description |
| -------- | -------- | -------- | -------- |
| EnvProp | key: string,<br/>defaultValue: any | boolean | Binds this system attribute to the AppStorage. You are advised to use this API during application startup. If the attribute already exists in the AppStorage, false is returned. Do not use the variables in the AppStorage. Instead, call this method to bind environment variables. |
| EnvProps | keys: {<br/>key: string,<br/>defaultValue: any<br/>}[] | void | Associates this system item array with the AppStorage. |
| Keys | Array&lt;string&gt; | number | Returns the associated system item array. |
## Built-in Environment Variables
| key | Type | Description |
| -------- | -------- | -------- |
| accessibilityEnabled | boolean | Whether to enable accessibility. |
| colorMode | ColorMode | Color mode. The options are as follows:<br/>- **ColorMode.LIGHT**: light mode.<br/>- **ColorMode.DARK**: dark mode. |
| fontScale | number | Font scale. The value range is [0.85, 1.45]. |
| fontWeightScale | number | Font weight scale. The value range is [0.6, 1.6]. |
| layoutDirection | LayoutDirection | Layout direction. The options are as follows:<br/>- **LayoutDirection.LTR**: The direction is from left to right.<br/>- **LayoutDirection.RTL**: The direction is from right to left. |
| languageCode | string | Current system language. The value is in lowercase, for example, zh. |
# PersistentStorage
ArkUI provides some static methods in the PersistentStorage class for managing persistent data of applications. Persistent data with specific tags can be linked to the AppStorage, and then the persistent data can be accessed through the AppStorage APIs. Alternatively, the @StorageLink decorator can be used to access the variable of the specific key.
| Name | Type | Return Value | Definition |
| -------- | -------- | -------- | -------- |
| PersistProp | key : string<br/>defaultValue: T | void | Changes the associated named attribute to persistent data in the AppStorage. The value overwriting sequence is as follows:<br/>- If the attribute exists in the AppStorage, use it to overwrite the value in Persistent.<br/>- If Persistent contains the specified attribute, use the attribute value in Persistent.<br/>- If the preceding conditions are not met, use defaultValue. The values null and undefined are not supported. |
| DeleteProp | key: string | void | Cancels two-way binding. The value of this attribute will be deleted from the persistent storage. |
| PersistProps | keys: {<br/>key: string,<br/>defaultValue: any<br/>}[] | void | Associates multiple named attribute bindings. |
| Keys | void | Array &lt;string&gt; | Returns the flags of all persistent attributes. |
> **NOTE**
>
> - When using **PersistProp**, ensure that the input key exists in the AppStorage.
>
> - **DeleteProp** takes effect only for the data that has been linked during the current startup.
```ts
// xxx.ets
PersistentStorage.PersistProp("highScore", "0");
@Entry
@Component
struct PersistentComponent {
@StorageLink('highScore') highScore: string = '0'
@State currentScore: number = 0
build() {
Column() {
if (this.currentScore === Number(this.highScore)) {
Text(`new highScore : ${this.highScore}`)
}
Button() {
Text(`goal!, currentScore : ${this.currentScore}`)
.fontSize(10)
}.onClick(() => {
this.currentScore++
if (this.currentScore > Number(this.highScore)) {
this.highScore = this.currentScore.toString()
}
})
}
}
}
```
# AppStorage
AppStorage is a singleton object in an application, which is created by the UI framework when the application is started and destroyed when the application exits. It is used to provide central storage for changing state attributes of an application. AppStorage contains all the state attributes that need to be accessed throughout the application. The AppStorage retains all attributes and their values as long as the application remains running, and the attribute values can be accessed through unique key values.
The UI component can synchronize the application state data with the AppStorage through the decorators. The application service logic can also be implemented by accessing the AppStorage through APIs.
The selection state attribute of the AppStorage can be synchronized with different data sources or data sinks. These data sources and data sinks can be local or remote devices and provide different functions, such as data persistence. Such data sources and data sinks can be implemented independently of the UI in the service logic.
By default, the attributes in the AppStorage are changeable. If needed, AppStorage can also use immutable (read-only) attributes.
## AppStorage APIs
| Name | Type | Return Value | Definition |
| -------- | -------- | -------- | -------- |
| SetAndLink | key: string,<br/>defaultValue: T | @Link | Works in a way similar to the Link API. If the current key is stored in the AppStorage, the value corresponding to the key is returned. If the key has not been created, a Link instance corresponding to the default value is created and returned. |
| Set | key: string,<br/>newValue: T | void | Replaces the value of a saved key. |
| Link | key: string | @Link | Returns two-way binding to this attribute if there is data with a given key. This means that attribute changes made by a variable or component will be synchronized to the AppStorage, and attribute changes made through the AppStorage will be synchronized to the variable or component. If the attribute with this key does not exist or is read-only, undefined is returned. |
| SetAndProp | propName: string,<br/>defaultValue: S | @Prop | Works in a way similar to the Prop API. If the current key is stored in the AppStorage, the value corresponding to the key is returned. If the key has not been created, a Prop instance corresponding to the default value is created and returned. |
| Prop | key: string | @Prop | Returns one-way binding to an attribute with a given key if the attribute exists. This means that attribute changes made through the AppStorage will be synchronized to the variable or component, but attribute changes made by the variable or component will be synchronized to the AppStorage. The variable returned by this method is an immutable one, which is applicable both to the variable and immutable state attributes. If the attribute with the specified key does not exist, undefined is returned.<br/>**NOTE**<br/>The attribute value used in the prop method must be of a simple type. |
| SetOrCreate | key: string,<br/>newValue: T | boolean | If an attribute that has the same name as the specified key exists: replaces the value of the attribute and returns true when the attribute can be modified; retains the original value of the attribute and returns false otherwise.<br/>If an attribute that has the same name as the specified key does not exist: creates an attribute whose key is key and value is newValue. The values null and undefined are not supported. |
| Get | key: string | T or undefined | Obtains the value of the specified key. |
| Has | propName: string | boolean | Checks whether the attribute corresponding to the specified key value exists. |
| Keys | void | array&lt;string&gt; | Returns an array of strings containing all keys. |
| Delete | key: string | boolean | Deletes the key-value pair for the specified key. Returns true if the key-value pair exists and is successfully deleted; returns false otherwise. |
| Clear | void | boolean | Deletes all attributes. If any of the attributes is being referenced by a state variable, false is returned. |
| IsMutable | key: string | boolean | Specifies whether the attribute exists and can be changed. |
## Synchronization Between AppStorage and Components
In [Managing Component States](ts-component-states-state.md), we have defined how to synchronize the state variables of child components with the @State decorated variables in the parent component or ancestor component, including @Prop, @Link, and @Consume.
In this section, we'll describe how to synchronize component variables with the AppStorage through the @StorageLink and @StorageProp decorators.
### @StorageLink Decorator
Two-way data binding can be established between components and the AppStorage through state variables decorated by @StorageLink(_key_). Wherein, key is the attribute key value in the AppStorage. When a component containing the @StorageLink decorated variable is created, the variable is initialized using the value in the AppStorage. Changes made to this variable in the component will be first synchronized to the AppStorage, and then to other bound instances, such as PersistentStorage or other bound UI components.
### @StorageProp Decorator
One-way data binding can be established between components and the AppStorage through state variables decorated by @StorageProp(_key_). Wherein, key is the attribute key value in the AppStorage. When a component containing the @StorageProp decorated variable is created, the variable is initialized using the value in the AppStorage. Changes made to the value in the AppStorage will cause the bound UI component to update the state.
## Example
```ts
// xxx.ets
@Entry
@Component
struct ComponentA {
@StorageLink('varA') varA: number = 2
@StorageProp('languageCode') lang: string = 'en'
private label: string = 'count'
aboutToAppear() {
this.label = (this.lang === 'en') ? 'Number' : 'Count'
}
build() {
Row({ space: 20 }) {
Button(`${this.label}: ${this.varA}`)
.onClick(() => {
AppStorage.Set<number>('varA', AppStorage.Get<number>('varA') + 1)
})
Button(`lang: ${this.lang}`)
.onClick(() => {
if (this.lang === 'zh') {
AppStorage.Set<string>('languageCode', 'en')
} else {
AppStorage.Set<string>('languageCode', 'en')
}
this.label = (this.lang === 'en') ? 'Number' : 'Count'
})
}
}
}
```
Each time the user clicks the **Count** button, the value of **this.varA** will increase by 1. This variable is synchronized with varA in the AppStorage. Each time the user clicks the language icon, the value of **languageCode** in the AppStorage will be changed, and the change will be synchronized to the **this.lang** variable.
# Attribute Configuration
Use attribute methods to configure component attributes. An attribute method follows the corresponding component and is bound to the component using the "." operator.
- The following is an example of configuring the font size attribute of the Text component:
```ts
Text('123')
.fontSize(12)
```
- Use the "." operator to implement chain call to configure multiple attributes at the same time, as shown below:
```ts
Image('a.jpg')
.alt('error.jpg')
.width(100)
.height(100)
```
- In addition to constants, you can also pass variables or expressions, as shown below:
```ts
// Size, count, and offset are private variables defined in the component.
Text('hello')
.fontSize(this.size)
Image('a.jpg')
.width(this.count % 2 === 0 ? 100 : 200)
.height(this.offset + 100)
```
- For attributes of preset components, the framework also provides some predefined enumeration types, which you can pass as parameters to methods. Enumeration types must meet the parameter type requirements on the enumeration type definitions for specific attributes. You can configure the font color and weight attributes of the Text component as follows:
```ts
Text('hello')
.fontSize(20)
.fontColor(Color.Red)
.fontWeight(FontWeight.Bold)
```
# Child Component Configuration
For a component that supports child components, for example, a container component, add the UI descriptions of the child components inside "{ ... }". The **\<Column>**, **\<Row>**, **\<Stack>**, **\<Button>**, **\<Grid>**, and **\<List>** components are container components.
- The following is a simple example of the **\<Column>** component:
```ts
Column() {
Text('Hello')
.fontSize(100)
Divider()
Text(this.myText)
.fontSize(100)
.fontColor(Color.Red)
}
```
- Multiple child components can be nested in the **\<Column>** component, as shown below:
```ts
Column() {
Column() {
Button() {
Text('+ 1')
}.type(ButtonType.Capsule)
.onClick(() => console.log ('+1 clicked!'))
Image('1.jpg')
}
Divider()
Column() {
Button() {
Text('+ 2')
}.type(ButtonType.Capsule)
.onClick(() => console.log ('+2 clicked!'))
Image('2.jpg')
}
Divider()
Column() {
Button() {
Text('+ 3')
}.type(ButtonType.Capsule)
.onClick(() => console.log('+3 clicked!'))
Image('3.jpg')
}
}.alignItems(HorizontalAlign.Center) // center align components inside Column
```
# @Component
A struct decorated by **@Component** has the componentization capability and can serve as an independent component. This type of component is also called a custom component, and its UI structure is described in the **build** method. Custom components have the following features:
- Composability: Custom components can be used with preset or other components, as well as common attributes and methods.
- Chain call<sup>9+</sup>: Universal attributes can be invoked in chain call mode to change the component style.
- Reusable: Custom components can be reused by other components and used as different instances in different parent components or containers.
- Lifecycle: Custom components provide callbacks for service logic processing throughout the lifecycle.
- Data-driven update: The UI of custom components can be automatically updated based on the data of state variables.
For details about componentization, see [About @Component](ts-custom-component-initialization.md).
> **NOTE**
>
> - The **build** method must be defined for a custom component.
>- Custom constructors are prohibited for custom components.
The following code illustrates how to create a custom component named **MyComponent**:
```ts
@Component
struct MyComponent {
build() {
Column() {
Text('my component')
.fontColor(Color.Red)
}.alignItems(HorizontalAlign.Center) // center align Text inside Column
}
}
```
The **build** method of **MyComponent** is executed during initial rendering. When the component status changes, the **build** method will be executed again.
The following code illustrates how to use **MyComponent**:
```ts
@Component
struct ParentComponent {
build() {
Column() {
MyComponent()
Text('we use component')
.fontSize(20)
}
}
}
```
**MyComponent** can be applied multiple times and reused in different components, as shown in the code below:
```ts
@Component
struct ParentComponent {
build() {
Row() {
Column() {
MyComponent()
Text('first column')
.fontSize(20)
}
Column() {
MyComponent()
Text('second column')
.fontSize(20)
}
}
}
aboutToAppear() {
console.log('ParentComponent: Just created, about to become rendered first time.')
}
aboutToDisappear() {
console.log('ParentComponent: About to be removed from the UI.')
}
}
```
Universal attributes can be invoked in chain call mode to diversify component styles.
> **NOTE**
>
> This feature is supported since API version 9.
>
> The chain call for custom components does not support trailing closures in the following scenario: When the custom component is initialized, the component name is followed by a pair of braces ({}) to form a trailing closure (as in `Index(){}`). You can consider a trailing closure as a container and add content to it, as in `{Column(){Text("content")}`.
```ts
@Entry
@Component
struct Index {
@State bannerValue: string = 'Hello,world';
build() {
Column() {
Chind({ ChindBannerValue:$bannerValue })
.height(60)
.width(250)
.border({ width:5, color:Color.Red, radius:10, style: BorderStyle.Dotted })
}
}
}
@Component
struct Chind {
@Link ChindBannerValue: string;
build() {
Column() {
Text(this.ChindBannerValue)
.fontSize(30)
}
}
}
```
# @CustomDialog
The @CustomDialog decorator is used to decorate custom pop-up dialog boxes.
```ts
// custom-dialog-demo.ets
@CustomDialog
struct DialogExample {
controller: CustomDialogController;
action: () => void;
build() {
Row() {
Button ("Close CustomDialog")
.onClick(() => {
this.controller.close();
this.action();
})
}.padding(20)
}
}
@Entry
@Component
struct CustomDialogUser {
dialogController : CustomDialogController = new CustomDialogController({
builder: DialogExample({action: this.onAccept}),
cancel: this.existApp,
autoCancel: true
});
onAccept() {
console.log("onAccept");
}
existApp() {
console.log("Cancel dialog!");
}
build() {
Column() {
Button("Click to open Dialog")
.onClick(() => {
this.dialogController.open()
})
}
}
}
```
# @Entry
The custom component decorated by @Entry functions as the default entry component of the respective page. When the page is loaded, the custom component decorated by @Entry is created and displayed first.
> **NOTE**
>
> A source file can contain at most one custom component decorated by @Entry.
Example of using @Entry:
```ts
// Only MyComponent decorated by @Entry is rendered and displayed. "hello world" is displayed, but "goodbye" is not displayed.
@Entry
@Component
struct MyComponent {
build() {
Column() {
Text('hello world')
.fontColor(Color.Red)
}
}
}
@Component
struct HideComponent {
build() {
Column() {
Text('goodbye')
.fontColor(Color.Blue)
}
}
}
```
# @Extend
The @Extend decorator adds new attribute functions to preset components, such as **\<Text>**, **\<Column>**, and **\<Button>**. You can use the @Extend decorator to quickly define and reuse the custom styles of a component.
```ts
// xxx.ets
@Extend(Text) function fancy(fontSize: number) {
.fontColor(Color.Red)
.fontSize(fontSize)
.fontStyle(FontStyle.Italic)
}
@Entry
@Component
struct FancyUse {
build() {
Row({ space: 10 }) {
Text("Fancy")
.fancy(16)
Text("Fancy")
.fancy(24)
}
}
}
```
> **NOTE**
>
> The @Extend decorator cannot be used in the struct definition of a custom component.
\ No newline at end of file
# @Preview
You can use **@Preview** to decorate a custom component so that it can be previewed in real time in DevEco Studio. This component is created and displayed when the page where it is located is loaded. Dynamic pictures and dynamic preview are not yet supported.
> **NOTE**
>
> In a source file, at most 10 custom components can be decorated by **@Preview**. For details, see [@Preview](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-previewing-app-service-0000001218760596#section146052489820).
Example of using **@Preview**:
```ts
// xxx.ets
@Entry
@Component
struct MyComponent {
build() {
Column() {
Row() {
Text('Hello World!')
.fontSize("50lpx")
.fontWeight(FontWeight.Bold)
}
Row() {
Component1()
}
Row() {
Component2()
}
}
}
}
@Preview
@Component
struct Component1 {
build() {
Column() {
Row() {
Text('Hello Component1')
.fontSize("50lpx")
.fontWeight(FontWeight.Bold)
}
}
}
}
@Component
struct Component2 {
build() {
Column() {
Row() {
Text('Hello Component2')
.fontSize("50lpx")
.fontWeight(FontWeight.Bold)
}
}
}
}
```
# @Styles
The **@Styles** decorator adds new attribute functions to basic components, such as **\<Text>**, **\<Column>**, and **\<Button>**. Currently, **@Styles** supports only universal attributes. You can use the **@Styles** decorator to quickly define and reuse the custom styles of a component.
**@Styles** can be defined inside or outside a component. When it is defined outside a component, the keyword **function** must be added before the API name.
```ts
// xxx.ets
@Styles function globalFancy() {
.backgroundColor(Color.Red)
}
@Entry
@Component
struct FancyUse {
@Styles componentFancy() {
.backgroundColor(Color.Blue)
}
build() {
Column({ space: 10 }) {
Text("Fancy")
.globalFancy()
.width(100)
.height(100)
.fontSize(30)
Text("Fancy")
.componentFancy()
.width(100)
.height(100)
.fontSize(30)
}
}
}
```
**@Styles** can also be used inside the **StateStyles** attribute to assign state-specific attributes to components.
In **StateStyles**, styles defined outside the component can be directly called. However, the keyword **this** must be used to call styles defined in the component.
```ts
// xxx.ets
@Styles function globalFancy() {
.width(100)
.height(100)
}
@Entry
@Component
struct FancyUse {
@Styles componentFancy() {
.width(50)
.height(50)
}
build() {
Row({ space: 10 }) {
Button() {
Text("Fancy")
}
.stateStyles({
normal: {
.width(80)
.height(80)
},
disabled: this.componentFancy,
pressed: globalFancy
})
}
}
}
```
# @Link
Two-way binding can be established between the @Link decorated variable and the @State decorated variable of the parent component. The @Link data has the following features:
- Support for multiple types: The value of the @Link decorated variable can be of the same type as the @State decorated variable; that is, the value can be of the following types: class, number, string, boolean, or arrays of these types.
- Private: Data is accessed only within the component.
- Single data source: The variable of the parent component for initializing the @Link decorated variable must be the @State decorated variable.
- Two-way binding: When a child component changes the @Link decorated variable, the @State decorated variable of its parent component is also changed.
- Support for initialization with the variable reference passed to the @Link decorated variable: When creating a new instance of the component, you must use the naming parameter to initialize all @Link decorated variables. The @Link decorated variable can be initialized by using the reference of the @State or @Link decorated variable. Wherein, the @State decorated variable can be referenced using the ` '$' ` operator.
> **NOTE**
>
> The @Link decorated variable cannot be initialized within the component.
## Simple Type Example
```ts
// xxx.ets
@Entry
@Component
struct Player {
@State isPlaying: boolean = false
build() {
Column() {
PlayButton({buttonPlaying: $isPlaying})
Text(`Player is ${this.isPlaying? '':'not'} playing`)
}
}
}
@Component
struct PlayButton {
@Link buttonPlaying: boolean
build() {
Column() {
Button() {
Image(this.buttonPlaying? 'play.png' : 'pause.png')
}.onClick(() => {
this.buttonPlaying = !this.buttonPlaying
})
}
}
}
```
The @Link semantics are derived from the `'$'` operator. In other words, `$isPlaying` is the two-way binding of the internal state ` this.isPlaying ` . When you click **PlayButton**, the **\<Image>** and **\<Text>** components of **PlayButton** are refreshed at the same time.
## Complex Type Example
```ts
// xxx.ets
@Entry
@Component
struct Parent {
@State arr: number[] = [1, 2, 3]
build() {
Column() {
Child({items: $arr})
ForEach(this.arr,
item => Text(`${item}`),
item => item.toString())
}
}
}
@Component
struct Child {
@Link items: number[]
build() {
Column() {
Button() {
Text('Button1: push')
}.onClick(() => {
this.items.push(100)
})
Button() {
Text('Button2: replace whole item')
}.onClick(() => {
this.items = [100, 200, 300]
})
}
}
}
```
In the example above, click **Button1** and **Button2** to change the list of text items displayed in the parent component.
## Example of Using @Link, @State, and @Prop Together
```ts
// xxx.ets
@Entry
@Component
struct ParentView {
@State counter: number = 0
build() {
Column() {
ChildA({counterVal: this.counter}) // pass by value
ChildB({counterRef: $counter}) // $ creates a Reference that can be bound to counterRef
}
}
}
@Component
struct ChildA {
@Prop counterVal: number
build() {
Button() {
Text(`ChildA: (${this.counterVal}) + 1`)
}.onClick(() => {this.counterVal+= 1})
}
}
@Component
struct ChildB {
@Link counterRef: number
build() {
Button() {
Text(`ChildB: (${this.counterRef}) + 1`)
}.onClick(() => {this.counterRef+= 1})
}
}
```
In the preceding example, ParentView contains two child components: ChildA and ChildB. They are initialized by the state variable counter of ParentView.
- ChildB uses @Link to establish two-way state binding. When the value of the counterRef state variable is changed in ChildB, the change is synchronized to ParentView and ChildA.
- ChildA uses @Prop to establish one-way state binding from ParentView to itself. When ChildA changes the state, it is re-rendered, but the change is not updated to ParentView or ChildB.
# @Prop
@Prop and @State have the same semantics but different initialization modes. Variables decorated by @Prop must be initialized using the @State decorated variable provided by their parent components. The @Prop decorated variable can be modified in the component, but the modification is not updated to the parent component; that is, @Prop uses one-way data binding.
The @Prop state data has the following features:
- Support for simple types: The number, string, and boolean types are supported.
- Private: Data is accessed only within the component.
- Support for multiple instances: A component can have multiple attributes decorated by @Prop.
- Support for initialization with a value passed to the @Prop decorated variable: When a new instance of the component is created, all @Prop decorated variables must be initialized. Initialization inside the component is not supported.
## Example
```ts
// xxx.ets
@Entry
@Component
struct ParentComponent {
@State countDownStartValue: number = 10 // 10 Nuggets default start value in a Game
build() {
Column() {
Text(`Grant ${this.countDownStartValue} nuggets to play.`)
Button() {
Text('+1 - Nuggets in New Game')
}.onClick(() => {
this.countDownStartValue += 1
})
Button() {
Text('-1 - Nuggets in New Game')
}.onClick(() => {
this.countDownStartValue -= 1
})
// When creating a child component, you must provide the initial value of its @Prop decorated variable in the constructor parameter and initialize the regular variable CostOfOneAttump (not Prop).
CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2})
}
}
}
@Component
struct CountDownComponent {
@Prop count: number
private costOfOneAttempt: number
build() {
Column() {
if (this.count > 0) {
Text(`You have ${this.count} Nuggets left`)
} else {
Text('Game over!')
}
Button() {
Text('Try again')
}.onClick(() => {
this.count -= this.costOfOneAttempt
})
}
}
}
```
In the preceding example, when you press +1 or -1, the status of the parent component changes and the build method is executed again. In this case, a new CountDownComponent is created. The countDownStartValue property of the parent component is used to initialize the @Prop decorated variable of the child component. When you tap the Try again button of the child component, the value of the @Prop decorated variable count is changed. As a result, the CountDownComponent is rendered again. However, the change of the count value does not affect the countDownStartValue value of the parent component.
> **NOTE**
>
> When a new component instance is created, all its @Prop decorated variables must be initialized.
# @State
The @State decorated variable is the internal state data of the component. When the state data is modified, the build method of the component is called to refresh the UI. Note that the @State decorator cannot listen for data changes at the inner layer.
The @State data has the following features:
- Support for multiple types: The following types are supported: strong types by value and by reference, including class, number, boolean, string, as well as arrays of these types, that is, Array&lt;class&gt;, Array&lt;string&gt;, Array&lt;boolean&gt;, and Array&lt;number>. object and any are not allowed.
- Support for multiple instances: Multiple instances can coexist in a component. The internal state data of different instances is independent.
- Private: An attribute marked with @State can only be accessed within the component.
- Local initialization required: Initial values must be allocated to all @State decorated variables through the initialization process. Otherwise, they may become undefined in the framework.
- Support for setting of initial attribute values based on the state variable name: When creating a component instance, you can explicitly specify the initial value of the @State decorated attribute based on the variable name.
## Simple Example of @State Decorated Attribute
```ts
// xxx.ets
@Entry
@Component
struct MyComponent {
@State count: number = 0
// MyComponent provides a method for modifying the @State status data member.
private toggleClick() {
this.count += 1
}
build() {
Column() {
Button() {
Text(`click times: ${this.count}`)
.fontSize(10)
}.onClick(this.toggleClick.bind(this))
}
}
}
```
## Complex Example of @State Decorated Variable
```ts
// Customize the status data class.
// xxx.ets
class Model {
value: string
constructor(value: string) {
this.value = value
}
}
@Entry
@Component
struct EntryComponent {
build() {
Column() {
MyComponent({count: 1, increaseBy: 2}) // MyComponent1 in this document
MyComponent({title: {value: 'Hello, World 2'}, count: 7}) //MyComponent2 in this document
}
}
}
@Component
struct MyComponent {
@State title: Model = {value: 'Hello World'}
@State count: number = 0
private toggle: string = 'Hello World'
private increaseBy: number = 1
build() {
Column() {
Text(`${this.title.value}`).fontSize(30)
Button() {
Text(`Click to change title`).fontSize(20).fontColor(Color.White)
}.onClick(() => {
this.title.value = (this.toggle == this.title.value) ? 'Hello World' : 'Hello UI'
}) // Modify the internal state of MyComponent using the anonymous method.
Button() {
Text(`Click to increase count=${this.count}`).fontSize(20).fontColor(Color.White)
}.onClick(() => {
this.count += this.increaseBy
}) // Modify the internal state of MyComponent using the anonymous method.
}
}
}
```
In the preceding example:
- Two @State decorated variables, count and title, have been defined for MyComponent. If the value of count or title changes, the build method of MyComponent needs to be called to render the component again.
- The EntryComponent has multiple MyComponent instances. The internal status change of the first MyComponent does not affect the second MyComponent.
- When creating a MyComponent instance, initialize the variables in the component based on the variable name. For example:
```ts
MyComponent({title: {value: 'Hello, World 2'}, count: 7})
```
# Configuration with Mandatory Parameters
If the API definition of a component contains any mandatory parameter, set the parameters in the parentheses next to the component. Use constants to assign values to the parameters.
Examples:
- Set the mandatory parameter src of the &lt;Image&gt; component as follows:
```ts
Image('http://xyz/a.jpg')
```
- Set the mandatory parameter content of the **\<Text>** component as follows:
```ts
Text('123')
```
You can also use variables or expressions to assign values to parameters. The result type returned by an expression must meet the parameter type requirements. For example, to pass a variable or expression to construct the Image and Text components:
```ts
// imagePath, where imageUrl is a private data variable defined in the component.
Image(this.imagePath)
Image('http://' + this.imageUrl)
// count is a private data variable defined in the component.
// (``) and (${}) are the template character string features supported by the TS language and comply with the
// features of the corresponding language. This specification is not limited.
Text(`count: ${this.count}`)
```
# Event Configuration
You can use event methods to configure events supported by components. Since API version 9, you can obtain the context associated with the current component from the callback. For details, see [Obtaining the Context on an eTS Page](../ability/context-userguide.md).
- Example of using a lambda expression to configure the event of a component:
```ts
// Counter is a private data variable defined in the component.
Button('add counter')
.onClick(() => {
this.counter += 2
})
```
- When using an anonymous function expression to configure the event of a component, **bind** must be used to ensure that the contained components are referenced by **this** in the function body.
```ts
// Counter is a private data variable defined in the component.
Button('add counter')
.onClick(function () {
this.counter += 2
}.bind(this))
```
- Example of using a component's member function to configure the event of the component:
```ts
myClickHandler(): void {
// do something
}
...
Button('add counter')
.onClick(this.myClickHandler)
```
# build Function
The build function meets the definition of the **Builder** API and is used to define the declarative UI description of components. Components must comply with the preceding **Builder** API constraints. Custom or preset components are combined in declarative mode in the build method. The **build** API is called when a component is created or updated.
```ts
interface Builder {
build: () => void
}
```
> **NOTE**
>
> The build method supports only composite components and uses the rendering control syntax.
# Basic Concepts
The TypeScript-based declarative development paradigm provides a wide array of basic components, which can be combined and extended in a declarative manner to describe the UI of an application. It also provides basic data binding and event processing mechanisms to help you implement the application interaction logic.
## HelloWorld Example
```ts
// An example of displaying Hello World. After you click the button, Hello UI is displayed.
// xxx.ets
@Entry
@Component
struct Hello {
@State myText: string = 'World'
build() {
Column() {
Text('Hello')
.fontSize(30)
Text(this.myText)
.fontSize(32)
Divider()
Button() {
Text('Click me')
.fontColor(Color.Red)
}.onClick(() => {
this.myText = 'UI'
})
.width(500)
.height(200)
}
}
}
```
## Basic Concepts
The preceding sample code shows the structure of a simple page. It involves the following basic concepts:
- Decorator: a special kind of declaration that can be applied to classes, structures, methods, and variables. In the sample code, @Entry, @Component, and @State are decorators.
- Custom component: a reusable UI unit, which can be combined with other components. In the sample code, struct Hello decorated by @Component is a custom component.
- UI description: declaratively describes the UI structure. In the sample code, the block of code in the build() method provides the UI description.
- Built-in component: the default basic or layout component preset in the framework. You can directly invoke these components, such as &lt;Column&gt;, &lt;Text&gt;, &lt;Divider&gt;, and &lt;Button&gt; components in the sample code.
- Attribute method: a method used to configure component attributes, such as fontSize(), width(), height(), and color().
- Event method: a method used to add the component response logic to an event. In the sample code, the onClick method is added for the Button component for defining the click response logic.
# @Consume and @Provide
As the data provider, @Provide can update the data of child nodes and trigger page rendering. After @Consume detects that the @Provide data is updated, it will initiate re-rendering of the current view.
Table 1 @Provide
| Name | Description |
| -------- | -------- |
| Decorator parameter | A constant of the string type, which is used to set an alias for a decorated variable. If an alias is specified, implement the data update for this alias. If there is no alias, use the variable name as the alias. @Provide("_alias_") is recommended. |
| Synchronization mechanism | The @Provide decorated variable is similar to the @state variable. You can modify the variable to re-render the page. You can also modify the @Consume decorated variable to modify the @State decorated variable reversely. |
| Initial value | The initial value must be set. |
| Page re-rendering scenarios | The following will trigger page re-rendering:<br/>- Changes of variables in primitive types (boolean, string, and number)<br/>- Changes of the @Observed decorated classes or their attributes<br/>- Adding, deleting, or updating elements in an array |
Table 2 @Consume
| Type | Description |
| -------- | -------- |
| Initial value | No default value can be set. |
> **NOTE**
>
> To avoid infinite loops caused by circular reference, exercise caution when using @Provide and @Consume.
The description of other attributes is the same as that of @Provide.
```ts
// xxx.ets
@Entry
@Component
struct CompA {
@Provide("reviewVote") reviewVotes : number = 0;
build() {
Column() {
CompB()
Button() {
Text(`${this.reviewVotes}`)
.fontSize(30)
}
.onClick(() => {
this.reviewVotes += 1;
})
}
}
}
@Component
struct CompB {
build() {
Column() {
CompC()
}
}
}
@Component
struct CompC {
@Consume("reviewVote") reviewVotes : number;
build() {
Column() {
Button() {
Text(`${this.reviewVotes}`)
.fontSize(30)
}
.onClick(() => {
this.reviewVotes += 1;
})
}
}
}
```
# @Observed and @ObjectLink
This section introduces to you two new decorators: @Observed and @ObjectLink.
- @Observed applies to a class, indicating that the data changes in the class are managed by the UI page, for example, @Observed class ClassA {}.
- @ObjectLink applies to an object decorated by @Observed, for example, @ObjectLink a: ClassA.
## Background
When you need to set bidirectional synchronization in a child component for a variable (parent_a) of its parent component, you can use @State to decorate the variable (parent_a) in the parent component and use @Link to decorate the corresponding variable (child_a) in the child component. In this way, data can be synchronized between the parent component and the specific child component, and between the parent component and its other child components. As shown below, bidirectional synchronization is configured for variables of ClassA in the parent and child components. If attribute c of the variable in child component 1 has its value changed, the parent component will be notified to synchronize the change. If attribute c in the parent component has its value changed, all child components will be notified to synchronize the change.
![en-us_image_0000001267647861](figures/en-us_image_0000001267647861.png)
In the preceding example, full synchronization is performed for a data object. If you want to synchronize partial information of a data object in a parent component, and if the information is a class object, use @ObjectLink and @Observed instead, as shown below.
![en-us_image_0000001267607881](figures/en-us_image_0000001267607881.png)
## Configuration Requirement
- @Observed applies to classes, and @ObjectLink applies to variables.
- The variables decorated by @ObjectLink must be of the class type.
- The classes must be decorated by @Observed.
- Parameters of the primitive types are not supported. You can use @Prop to perform unidirectional synchronization.
- @ObjectLink decorated variables are immutable.
- Attribute changes are allowed. If an object is referenced by multiple @ObjectLink decorated variables, all custom components that have these variables will be notified for re-rendering.
- Default values cannot be set for @ObjectLink decorated variables.
- The parent component must be initialized with a TypeScript expression that involves variables decorated by @State, @Link, @StorageLink, @Provide, or @Consume.
- @ObjectLink decorated variables are private variables and can be accessed only within the component.
## Examples
### Example 1
```ts
// When the data of the ClassA object in the parent component ViewB's class object ClassB is synchronized with that of the child component ViewA, use @ObjectLink to synchronize the changes in the value of c are synchronized to the parent component.
@Observed
class ClassA {
public name : string;
public c: number;
constructor(c: number, name: string = 'OK') {
this.name = name;
this.c = c;
}
}
class ClassB {
public a: ClassA;
constructor(a: ClassA) {
this.a = a;
}
}
@Component
struct ViewA {
label : string = "ep1";
@ObjectLink a : ClassA;
build() {
Column() {
Text(`ViewA [${this.label}]: a.c=${this.a.c}`)
.fontSize(20)
Button(`+1`)
.width(100)
.margin(2)
.onClick(() => {
this.a.c += 1;
})
Button(`reset`)
.width(100)
.margin(2)
.onClick(() => {
this.a = new ClassA(0); // Error: Variable a decorated by @ObjectLink is immutable.
})
}
}
}
@Entry
@Component
struct ViewB {
@State b : ClassB = new ClassB(new ClassA(10));
build() {
Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center}) {
ViewA({label: "ViewA #1", a: this.b.a})
ViewA({label: "ViewA #2", a: this.b.a})
Button(`ViewB: this.b.a.c += 1` )
.width(320)
.margin(4)
.onClick(() => {
this.b.a.c += 1;
})
Button(`ViewB: this.b.a = new ClassA(0)`)
.width(240)
.margin(4)
.onClick(() => {
this.b.a = new ClassA(0);
})
Button(`ViewB: this.b = new ClassB(ClassA(0))`)
.width(240)
.margin(4)
.onClick(() => {
this.b = new ClassB(new ClassA(0));
})
}
}
}
```
### Example 2
```ts
// When the data of class object ClassA in the parent component ViewB is synchronized with that of the child component ViewA, use @ObjectLink and @Observed to synchronize data changes to the parent component and its other child components.
var nextID: number = 0;
@Observed
class ClassA {
public name : string;
public c: number;
public id : number;
constructor(c: number, name: string = 'OK') {
this.name = name;
this.c = c;
this.id = nextID++;
}
}
@Component
struct ViewA {
label : string = "ViewA1";
@ObjectLink a: ClassA;
build() {
Row() {
Button(`ViewA [${this.label}] this.a.c= ${this.a.c} +1`)
.onClick(() => {
this.a.c += 1;
})
}.margin({ top: 10 })
}
}
@Entry
@Component
struct ViewB {
@State arrA : ClassA[] = [ new ClassA(0), new ClassA(0) ];
build() {
Column() {
ForEach (this.arrA, (item) => {
ViewA({label: `#${item.id}`, a: item})
},
(item) => item.id.toString()
)
ViewA({label: `ViewA this.arrA[first]`, a: this.arrA[0]})
ViewA({label: `ViewA this.arrA[last]`, a: this.arrA[this.arrA.length-1]})
Button(`ViewB: reset array`)
.margin({ top: 10 })
.onClick(() => {
this.arrA = [ new ClassA(0), new ClassA(0) ];
})
Button(`ViewB: push`)
.margin({ top: 10 })
.onClick(() => {
this.arrA.push(new ClassA(0))
})
Button(`ViewB: shift`)
.margin({ top: 10 })
.onClick(() => {
this.arrA.shift()
})
}
}
}
```
# @Watch
@Watch is used to listen for changes of state variables. The syntax structure is as follows:
```ts
@State @Watch("onChanged") count : number = 0
```
As shown above, add an @Watch decorator to the target state variable to register an onChanged callback. When the state variable count is changed, the onChanged callback will be triggered.
@Watch can be used to listen for changes of variables decorated by @State, @Prop, @Link, @ObjectLink, @Provide, @Consume, @StorageProp, or @StorageLink.
```ts
// xxx.ets
@Entry
@Component
struct CompA {
@State @Watch("onBasketUpdated") shopBasket : Array<number> = [ 7, 12, 47, 3 ];
@State totalPurchase : number = 0;
updateTotal() : number {
let sum = 0;
this.shopBasket.forEach((i) => { sum += i; });
// Calculate the total amount of items in the shopping basket. If the amount exceeds CNY100, the specified discount will be applied.
this.totalPurchase = (sum < 100) ? sum : 0.9 * sum;
return this.totalPurchase;
}
// @Watch cb
onBasketUpdated(propName: string) : void {
this.updateTotal();
}
build() {
Column() {
Button("add to basket").onClick(() => { this.shopBasket.push(Math.round(100 * Math.random())) })
Text(`${this.totalPurchase}`)
.fontSize(30)
}
}
}
```
# Configuration Without Parameters
If the API definition of a component does not contain mandatory parameters, you do not need to configure any content in the parentheses next to the component. For example, the Divider component does not contain parameters:
```ts
Column() {
Text('item 1')
Divider() // No parameter configuration of the divider component
Text('item 2')
}
```
# ForEach
The development framework provides **ForEach** to iterate arrays and create components for each array item. If a large number of elements are involved in **ForEach**, the page loading may become slow. For best possible results, you are advised to use **[LazyForEach](ts-rending-control-syntax-lazyforeach.md)** instead. **ForEach** is defined as follows:
```ts
ForEach(
arr: any[], // Array to be iterated
itemGenerator: (item: any, index?: number) => void, // child component generator
keyGenerator?: (item: any, index?: number) => string // (optional) Unique key generator, which is recommended.
)
```
## ForEach
ForEach(arr: any[],itemGenerator: (item: any, index?: number) =&gt; void, keyGenerator?: (item: any, index?: number) =&gt; string):void
Table 1 Parameters
| Name | Type | Mandatory | Default Value | Description |
| ------------- | ---------------------------------------- | ---- | ---- | ---------------------------------------- |
| arr | any[] | Yes | - | Must be an array. An empty array is allowed. If the array is empty, no child component is created. The functions that return array-type values are also allowed, for example, **arr.slice (1, 3)**. The set functions cannot change any state variables including the array itself, such as **Array.splice**, **Array.sort**, and **Array.reverse**.|
| itemGenerator | (item: any, index?: number) =&gt; void | Yes | - | Lambda function used to generate one or more child components for a given array item. A component and its child component list must be enclosed in braces ({...}).|
| keyGenerator | (item: any, index?: number) =&gt; string | No | - | Anonymous parameter used to generate a unique and stable key value for a given array item. When the position of a subitem in the array is changed, the key value of the subitem cannot be changed. When a subitem in the array is replaced with a new item, the key value of the current item must be different from that of the new item. This key-value generator is optional. However, for performance reasons, it is strongly recommended that the key-value generator be provided, so that the development framework can better identify array changes. If the array is reversed while no key-value generator is provided, all nodes in **ForEach** will be rebuilt.|
> **NOTE**
> - **ForEach** must be used in container components.
>
> - The generated child components are allowed in the parent container component of **ForEach**. The child component generator function can contain the **if/else** conditional statement, and the **if/else** conditional statement can contain **ForEach**.
>
> - The call sequence of subitem generator functions may be different from that of the data items in the array. During the development, do not assume whether the subitem generator and key value generator functions are executed and the execution sequence. Below is an example of incorrect usage:
> ```ts
> ForEach(anArray, item => {Text(`${++counter}. item.label`)})
> ```
>
> Below is an example of correct usage:
>
> ```ts
> ForEach(anArray.map((item1, index1) => { return { i: index1 + 1, data: item1 }; }),
> item => Text(`${item.i}. item.data.label`),
> item => item.data.id.toString())
> ```
## Example
The following is an example of a simple-type array:
```ts
// xxx.ets
@Entry
@Component
struct MyComponent {
@State arr: number[] = [10, 20, 30]
build() {
Column() {
Button() {
Text('Reverse Array')
}.onClick(() => {
this.arr.reverse()
})
ForEach(this.arr, // Parameter 1: array to be iterated
(item: number) => { // Parameter 2: item generator
Text(`item value: ${item}`)
Divider()
},
(item: number) => item.toString() // Parameter 3: unique key generator, which is optional but recommended.
)
}
}
}
```
The following is an example of a complex-type array:
```ts
// xxx.ets
class Month {
year: number
month: number
days: Array<number>
constructor(year, month, days) {
this.year = year;
this.month = month;
this.days = days;
}
}
@Entry
@Component
struct Calendar1 {
// simulate with 6 months
@State calendar: Month[] = [
new Month(2020, 1, [...Array(31).keys()]),
new Month(2020, 2, [...Array(28).keys()]),
new Month(2020, 3, [...Array(31).keys()]),
new Month(2020, 4, [...Array(30).keys()]),
new Month(2020, 5, [...Array(31).keys()]),
new Month(2020, 6, [...Array(30).keys()]),
]
build() {
Column() {
Button('next month')
.onClick(() => {
this.calendar.shift()
this.calendar.push({
year: 2020,
month: 7,
days: [...Array(31)
.keys()]
})
})
ForEach(this.calendar,
(item: Month) => {
Text('month:' + item.month)
.fontSize(30)
.padding(20)
Grid() {
ForEach(item.days,
(day: number) => {
GridItem() {
Text((day + 1).toString())
.fontSize(30)
}
},
(day: number) => day.toString())
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
.rowsGap(20)
},
// field is used together with year and month as the unique ID of the month.
(item: Month) => (item.year * 12 + item.month).toString())
}
}
}
```
# if/else
Use if/else for conditional rendering.
> **NOTE**
> - State variables can be used in the if conditional statement.
>
> - You can use the if conditional statement to implement rendering of child components.
>
> - The if conditional statement must be used in container components.
>
> - Some container components limit the type or number of child components. When if is placed in these components, the limitation applies to components created in if and else statements. For example, when if is used in the &lt;Grid&gt; component, whose child components can only be &lt;GridItem&gt;, only the &lt;GridItem> component can be used in the if conditional statement.
## Example
Example of using the if conditional statement:
```ts
Column() {
if (this.count > 0) {
Text('count is positive')
}
}
```
Example of using the if, else if, and else conditional statements:
```ts
Column() {
if (this.count < 0) {
Text('count is negative')
} else if (this.count % 2 === 0) {
Divider()
Text('even')
} else {
Divider()
Text('odd')
}
}
```
# LazyForEach
The development framework provides LazyForEach to iterate data from provided data sources and create corresponding components during each iteration. LazyForEach is defined as follows:
```ts
LazyForEach(
dataSource: IDataSource, // Data source to be iterated
itemGenerator: (item: any) => void, // child component generator
keyGenerator?: (item: any) => string // (optional) Unique key generator, which is recommended.
): void
interface IDataSource {
totalCount(): number; // Get total count of data
getData(index: number): any; // Get single data by index
registerDataChangeListener(listener: DataChangeListener): void; // Register listener to listening data changes
unregisterDataChangeListener(listener: DataChangeListener): void; // Unregister listener
}
interface DataChangeListener {
onDataReloaded(): void; // Called while data reloaded
onDataAdd(index: number): void; // Called while single data added
onDataMove(from: number, to: number): void; // Called while single data moved
onDataDelete(index: number): void; // Called while single data deleted
onDataChange(index: number): void; // Called while single data changed
}
```
## APIs
### LazyForEach
LazyForEach(dataSource: IDataSource, itemGenerator: (item: any) => void, keyGenerator?: (item: any) => string):void
Table 1 Parameters
| Name | Type | Mandatory | Default Value | Description |
| -------- | -------- | -------- | -------- | -------- |
| dataSource | IDataSource | Yes | - | Object used to implement the IDataSource API. You need to implement related APIs. |
| itemGenerator | (item: any) => void | Yes | - | Used to generate the lambda function of the child components. It generates one or more child components for a given array item. A single component and its child component list must be contained in the braces ({...}) |
| keyGenerator | (item: any) => string | No | - | Used as an anonymous parameter for generating a unique and stable key value for a given array item. When the position of a subitem in the array is changed, the key value of the subitem cannot be changed. When a subitem in the array is replaced with a new item, the key value of the current item must be different from that of the new item. This key-value generator is optional. However, for performance reasons, it is strongly recommended that the key-value generator be provided, so that the development framework can better identify array changes. If the array is reversed while no key-value generator is provided, all nodes in LazyForEach will be rebuilt. |
Table 2 Description of IDataSource
| Name | Description |
| -------- | -------- |
| totalCount(): number | Obtains the total number of data records. |
| getData(index: number): any | Obtains the data corresponding to the specified index. |
| registerDataChangeListener(listener: DataChangeListener): void | Registers the data change listener. |
| unregisterDataChangeListener(listener: DataChangeListener): void | Unregisters the data change listener. |
Table 3 Description of DataChangeListener
| Name | Description |
| -------- | -------- |
| onDataReloaded(): void | Reloads all data. |
| onDataAdded(index: number): void | Notifies the component that data is added to the position indicated by the specified index. |
| onDataMoved(from: number, to: number): void | Notifies the component that data is moved from the **from** position to the **to** position. |
| onDataDeleted(index: number): void | Notifies the component that data is deleted from the position indicated by the specified index. |
| onDataChanged(index: number): void | Notifies the component that data in the position indicated by the specified index is changed. |
| onDataAdd(index: number): void<sup>8+</sup> | Notifies the component that data is added to the position indicated by the specified index. |
| onDataMove(from: number, to: number): void<sup>8+</sup> | Notifies the component that data is moved from the **from** position to the **to** position. |
| onDataDelete(index: number): void<sup>8+</sup> | Notifies the component that data is deleted from the position indicated by the specified index. |
| onDataChange(index: number): void<sup>8+</sup> | Notifies the component that data in the position indicated by the specified index is changed. |
> **NOTE**
>
> - LazyForEach must be used in the container component. Only the **\<List>**, **\<Grid>**, and \**<Swiper>** components support LazyForEach (that is, only the visible part and a small amount of data before and after the visible part are loaded for caching). For other components, all data is loaded at a time.
>
> - LazyForEach must create one and only one child component in each iteration.
>
> - The generated child component must be in the parent container component of LazyForEach.
>
> - LazyForEach can be included in an if/else conditional statement, but cannot contain an if/else conditional statement.
>
> - For the purpose of high-performance rendering, when the onDataChanged method of the DataChangeListener object is used to update the UI, the component update is triggered only when the state variable is used in the component specified in the UI description of itemGenerator.
>
> - The calling sequence of the subitem generator function may be different from that of the data items in the data source. During the development, do not assume whether the subitem generator and key value generator functions are executed and the execution sequence. The following is an example of incorrect usage:
> ```ts
> LazyForEach(dataSource, item => {Text(`${++counter}. item.label`)})
> ```
>
> Below is an example of correct usage:
>
> ```ts
> LazyForEach(dataSource,
> item => Text(`${item.i}. item.data.label`)),
> item => item.data.id.toString())
> ```
## Example
```ts
// Basic implementation of IDataSource to handle data listener
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = []
public totalCount(): number {
return 0
}
public getData(index: number): any {
return undefined
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener')
this.listeners.push(listener)
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener')
this.listeners.splice(pos, 1)
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
}
class MyDataSource extends BasicDataSource {
private dataArray: string[] = ['/path/image0', '/path/image1', '/path/image2', '/path/image3']
public totalCount(): number {
return this.dataArray.length
}
public getData(index: number): any {
return this.dataArray[index]
}
public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(index)
}
public pushData(data: string): void {
this.dataArray.push(data)
this.notifyDataAdd(this.dataArray.length - 1)
}
}
@Entry
@Component
struct MyComponent {
private data: MyDataSource = new MyDataSource()
build() {
List({space: 3}) {
LazyForEach(this.data, (item: string) => {
ListItem() {
Row() {
Image(item).width("30%").height(50)
Text(item).fontSize(20).margin({left:10})
}.margin({left: 10, right: 10})
}
.onClick(()=>{
this.data.pushData('/path/image' + this.data.totalCount())
})
}, item => item)
}
}
}
```
# About Syntactic Sugar
## Decorators
A decorator **@Decorator** can decorate a class, structure, or class attribute. Multiple decorators can be applied to the same target element and defined on a single line or multiple lines. It is recommended that the decorators be defined on multiple lines.
In the example below, the elements decorated by **@Component** take on the form of a component, and the variables decorated by **@State** can be used to represent states.
```ts
@Component
struct MyComponent {
@State count: number = 0
}
```
Multiple decorators can be defined on a single line, as shown below:
```ts
@Entry @Component struct MyComponent {
}
```
However, you are advised to define the decorators on multiple lines, as shown below:
```ts
@Entry
@Component
struct MyComponent {
}
```
### Supported Decorators
| Decorator | Decorates... | Description |
| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| @Component | struct | The decorated structure has the component-based capability. The **build** method must be implemented to update the UI.|
| @Entry | struct | The decorated component is used as the entry of a page. The component is rendered and displayed when the page is loaded. |
| @Preview | struct | Custom components decorated by **@Preview** can be previewed in DevEco Studio. When the target page is loaded, the custom components decorated by **@Preview** are created and displayed.|
| @Builder | Methods | In the decorated method, you can use the declarative UI description to quickly generate multiple layouts in a custom component.|
| @Extend | Methods | This decorator adds attribute functions to a preset component, allowing you to quickly define and reuse the custom style of the component.|
| @CustomDialog | struct | This decorator is used to decorate custom pop-up dialog boxes. |
| @State | Primitive data types, classes, and arrays | If the decorated state data is modified, the **build** method of the component will be called to update the UI. |
| @Prop | Primitive data types | This decorator is used to establish one-way data binding between the parent and child components. When the data associated with the parent component is modified, the UI of the current component is updated.|
| @Link | Primitive data types, classes, and arrays | This decorator is used to establish two-way data binding between the parent and child components. The internal state data of the parent component is used as the data source. Any changes made to one component will be reflected to the other.|
| @Observed | Classes | This decorator is used to indicate that the data changes in the class will be managed by the UI page. |
| @ObjectLink | Objects of **@Observed** decorated classes | When the decorated state variable is modified, the parent and sibling components that have the state variable will be notified for UI re-rendering.|
| @Consume | Primitive data types, classes, and arrays | When the **@Consume** decorated variable detects the update of the **@Provide** decorated variable, the re-rendering of the current custom component is triggered.|
| @Provide | Primitive data types, classes, and arrays | As the data provider, **@Provide** can update the data of child nodes and trigger page rendering.|
| @Watch | Variables decorated by **@State**, **@Prop**, **@Link**, **@ObjectLink**, **@Provide**, **@Consume**, **@StorageProp**, or **@StorageLink** | This decorator is used to listen for the changes of the state variables. The application can register a callback method through **@Watch**. |
## Chain Call
You can configure the UI structure and its attributes and events and separate them with a dot(.) to implement chain call.
```ts
Column() {
Image('1.jpg')
.alt('error.jpg')
.width(100)
.height(100)
}.padding(10)
```
## struct
Components can be implemented based on **struct**s. Components cannot inherit from each other. The **struct**s implemented components can be created and destroyed more quickly than **class** implemented components.
```ts
@Component
struct MyComponent {
@State data: string = ''
build() {
}
}
```
## Instantiating a struct Without the new Keyword
You can omit the **new** keyword when instantiating a **struct**.
```ts
// Definition
@Component
struct MyComponent {
build() {
}
}
// Usage
Column() {
MyComponent()
}
// Equivalent to
new Column() {
new MyComponent()
}
```
## Restrictions on Using TypeScript in Generators
TypeScript has the following restrictions on generators:
- Expressions can be used only in character strings (${expression}), **if** conditions, **ForEach** parameters, and component parameters.
- No expressions should cause any application state variables (**@State**, **@Link**, and **@Prop**) to change. Otherwise, undefined and potentially unstable framework behavior may occur.
- The generator function cannot contain local variables.
None of the above restrictions apply to anonymous function implementations of event-handling functions (such as **onClick**)
Incorrect:
```ts
build() {
let a: number = 1 // invalid: variable declaration not allowed
Column() {
Text(`Hello ${this.myName.toUpperCase()}`) // ok.
ForEach(this.arr.reverse(), ..., ...) // invalid: Array.reverse modifies the @State array variable in place
}
buildSpecial() // invalid: no function calls
Text(this.calcTextValue()) // this function call is ok.
}
```
## Two-Way Binding of Variables
**$$** supports two-way binding for simple variables and **@State**, **@Link**, and **@Prop** decorated variables.
Currently, **$$** supports only the rendering between the **show** parameter of the **[bindPopup](../reference/arkui-ts/ts-universal-attributes-popup.md)** attribute and the **@State** decorated variable, the **checked** attribute of the **\<Radio>** component, and the **refreshing** parameter of the **\<Refresh>** component.
```ts
// xxx.ets
@Entry
@Component
struct bindPopup {
@State customPopup: boolean = false
build() {
Column() {
Button(){
Text('Popup')
}
.onClick(()=>{
this.customPopup = !this.customPopup
})
.bindPopup(
$$this.customPopup, {
message: "showPopup"
}
)
}
}
}
```
## Restrictions on Declaring Multiple Data Types of State Variables
If a **@State**, **@Provide**, **@Link**, or **@Consume** decorated state variable supports multiple data types, they must be all simple data types or references at one time.
Example:
```ts
@Entry
@Component
struct Index {
// Incorrect: @State message: string | Resource = 'Hello World'
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(`${ this.message }`)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
```
# Overview
This section defines the core mechanism and functions of the TypeScript-based declarative development paradigm. It acquaints you with the declarative UI descriptions, componentization mechanisms, UI state management, rendering control syntax, and syntactic sugar.
Follow the provided guidelines for UI development. For details about the components, see components.
> **NOTE**
> - All examples use the TypeScript (TS) language. If you are using another language, comply with the syntax requirements for that language.
>
> - The components used in the examples are preset in the UI framework and are used only to explain the UI description specifications.
>
> - Universal attribute and event methods generally apply to all components, and the attribute and event methods within a component apply only to this component.
# Basic Concepts
In the declarative UI programming paradigm, the UI is a function in the specific application state, and you update a UI by modifying the current application state. The development framework provides comprehensive application state management capabilities, as shown in the figure below.
![en-us_image_0000001222967768](figures/en-us_image_0000001222967768.png)
## State Variable Decorators
- @State: state attribute of the component. Each time the @State decorated variable changes, the component re-renders and updates the UI.
- @Link: allows a component to depend on some state attributes of its parent component. Each time the data in one component is updated, the state of the other component is updated, and the parent and child components are rendered again.
- @Prop: works in a way similar to that of @Link. The difference is that the changes made by a child component are not synchronized to the parent component.
> **NOTE**
>
> The state variable cannot use an ID as its name, as in **@Prop id:number**.
## Application State Data
AppStorage is the central store of the application states in the entire UI. The UI framework creates a singleton AppStorage object for the application and provides the corresponding decorators and APIs for the application.
- @StorageLink: works in a way similar to that of @Consume. The difference is that the link object with the specified name is obtained from the AppStorage. It establishes two-way binding between the UI component and AppStorage to synchronize data.
- @StorageProp: synchronizes UI component attributes with the AppStorage unidirectionally. That is, the value change in the AppStorage will trigger an update of the corresponding UI component, but the change of the UI component will not cause an update of the attribute value in the AppStorage.
- Service logic implementation API: adds, reads, modifies, or deletes the state attributes of applications. The changes made by this API will be synchronized to the UI component for UI update.
# LocalStorage
> **NOTE**
>
> This component is supported since API version 9. Updates will be marked with a superscript to indicate their earliest API version.
**LocalStorage** is a storage unit in an application. Its lifecycle is determined by the ability to which it is bound. **LocalStorage** provides storage for variable and non-variable state attributes within the scope of an application. The variable and non-variable state attributes work together to build an application UI, including the UI of abilities.
Application layer: Multiple **LocalStorage** instances can be created for an application. Each ability of an application corresponds to a **LocalStorage** instance.
Ability: An application can have multiple abilities. Only one **LocalStorage** instance can be allocated to the child components of an ability. Once allocated a **LocalStorage** instance, the child components have access to objects stored in the **LocalStorage**.
A component can access only one **LocalStorage** instance, and a **LocalStorage** instance can be allocated to multiple components.
## @LocalStorageLink Decorator
Two-way data binding can be established between a component and the **LocalStorage** through the component's state variable decorated by **@LocalStorageLink(*key*)**. Wherein, **key** is the attribute key value in the **LocalStorage**. When a component that contains a **@LocalStorageLink** decorated state variable is created, the state variable is initialized with the value predefined in the **LocalStorage**. If no initial value is assigned in the **LocalStorage**, the state variable will use the value defined by **@LocalStorageLink**. Changes made to this variable in the component will be first synchronized to the **LocalStorage**, and then to other components of the bound ability.
## @LocalStorageProp Decorator
One-way data binding can be established between a component and the **LocalStorage** through the component's state variable decorated by **@LocalStorageProp(*key*)**. Wherein, **key** is the attribute key value in the **LocalStorage**. When a component that contains a **@LocalStorageProp** decorated state variable is created, the state variable is initialized with the value predefined in the **LocalStorage**. Changes made to the value in the **LocalStorage** will cause all UI components of the bound ability to update the state.
> **NOTE**
>
> If a **LocalStorage** instance has initial values assigned when being created, these values will be used for the **@LocalStorageLink** and **@LocalStorageProp** decorated state variables in the component. Otherwise, the initial values assigned for **@LocalStorageLink** and **@LocalStorageProp** will be used instead.
## LocalStorage
### constructor
constructor(initializingProperties?: Object)
Creates and initializes a **LocalStorage** instance.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| ---------------------- | ------ | :--: | ---- | ---------------------------------------- |
| initializingProperties | Object | No | - | Object attributes and their values returned by **object.keys(obj)**.|
### GetShared
static GetShared(): LocalStorage
Obtains the current shared **LocalStorage** object.
This API can be used only in the stage model.
**Return value**
| Type | Description |
| ----------------------------- | ----------------- |
| [LocalStorage](#localstorage) | **LocalStorage** object.|
### has
has(propName: string): boolean
Checks whether the **LocalStorage** contains the specified attribute value.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | ------- |
| propName | string | Yes | - | Attribute value.|
**Return value**
| Type | Description |
| ------- | ------------- |
| boolean | Whether the attribute value is contained.|
### get
get\<T>(propName: string): T
Obtains the value corresponding to the given key.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | ----------- |
| propName | string | Yes | - | Key of the value to obtain.|
**Return value**
| Type | Description |
| -------------- | ---------------------------------------- |
| T \| undefined | Returns the value if it is found; returns **undefined** otherwise.|
### set
set\<T>(propName: string, newValue: T): boolean
Sets the value for the given key.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | ----------- |
| propName | string | Yes | - | Key of the value to set. |
| newValue | T | Yes | - | Value to set.|
**Return value**
| Type | Description |
| ------- | ----------------------------------- |
| boolean | Returns **true** if the value is successfully set for the key; returns **false** otherwise.|
### setOrCreate
setOrCreate\<T>(propName: string, newValue: T): boolean
Creates or updates the value for the given key.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | -------------- |
| propName | string | Yes | - | Key of the value to create or update. |
| newValue | T | Yes | - | Value to create or update.|
**Return value**
| Type | Description |
| ------- | ---------------------------------------- |
| boolean | Updates the value of the attribute and returns **true** if an attribute that has the same name as the specified key exists; creates an attribute with the specified value of the T type as its default value and returns **false** otherwise. **true** cannot be returned for **undefined** or **null**.|
### link
link\<T>(propName: string): T
Establishes two-way data binding between an attribute and this **LocalStorage** instance.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | ----------- |
| propName | string | Yes | - | Key of the target attribute.|
**Return value**
| Type | Description |
| ---- | ---------------------------------------- |
| T | Returns the two-way data binding if an attribute that has the same name as the specified key exists; returns **undefined** otherwise.|
### setAndLink
setAndLink\<T>(propName: string, defaultValue: T): T
Establishes two-way data binding between an attribute and this **LocalStorage** instance. This API works in a way similar to the **link** API.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| ------------ | ------ | :--: | ---- | ----------- |
| propName | string | Yes | - | Key of the target attribute.|
| defaultValue | T | Yes | - | Default value to set. |
**Return value**
| Type | Description |
| ------------------------------------ | ------------------------------------------------------------ |
| [@Link](ts-component-states-link.md) | Returns the value corresponding to the specified key if the key is stored in the **LocalStorage**; creates and returns a **Link** instance with the specified value as its default value otherwise.|
### prop
prop\<T>(propName: string): T
Establishes one-way data binding with an attribute to update its status.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | ------------- |
| propName | string | Yes | - | Key of the target attribute.|
**Return value**
| Type | Description |
| ------------------------------------ | ---------------------------------------- |
| [@Prop](ts-component-states-prop.md) | Returns one-way binding to an attribute with a given key if the attribute exists; returns **undefined** otherwise. This means that attribute changes made through the **LocalStorage** will be synchronized to the variable or component, but attribute changes made by the variable or component will not be synchronized to the **LocalStorage**. Note that the variables returned are immutable variables, which are applicable to mutable and immutable state variables. |
### setAndProp
setAndProp\<T>(propName: string, defaultValue: T): T
Sets up one-way data binding with the **localStorage**. This API works in a way similar to the **Prop** API.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| ------------ | ------ | :--: | ---- | --------------- |
| propName | string | Yes | - | Key value in the key-value pair to be saved.|
| defaultValue | T | Yes | - | Default value to set. |
**Return value**
| Type | Description |
| ------------------------------------ | ---------------------------------------- |
| [@Prop](ts-component-states-prop.md) | Returns the value corresponding to the specified key if the key is stored in the **LocalStorage**; creates and returns a **Prop** instance with the specified value as its default value otherwise.|
### delete
delete(propName: string): boolean
Deletes the key-value pair specified by key.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| -------- | ------ | :--: | ---- | ------------ |
| propName | string | Yes | - | Key value of the attribute to be deleted.|
**Return value**
| Type | Description |
| ------- | ---------------------------------------- |
| boolean | Returns **true** if the key-value pair exists and is successfully deleted; returns **false** otherwise.|
### keys
keys(): IterableIterator\<string>
Searches for all keys.
**Return value**
| Type | Description |
| -------------- | -------------- |
| array\<string> | Returns an array of strings containing all keys.|
### size
size(): number
Number of existing key-value pairs.
**Return value**
| Type | Description |
| ------ | --------- |
| number | Number of key-value pairs.|
### Clear
clear(): boolean
Deletes all attributes.
**Return value**
| Type | Description |
| ------- | --------------------------------- |
| boolean | Returns **true** if all attributes are deleted; returns **false** if any of the attributes is being referenced by a state variable.|
### Example 1 (Creating a LocalStorage in an Ability)
```ts
import Ability from '@ohos.application.Ability'
export default class MainAbility extends Ability {
storage : LocalStorage
onCreate() {
this.storage = new LocalStorage();
this.storage.setOrCreate("storageSimpleProp",121);
console.log("[Demo MainAbility onCreate]");
}
onDestroy() {
console.log("[Demo MainAbility onDestroy]")
}
onWindowStageCreate(windowStage) {
windowStage.loadContent("pages/index",this.storage)
}
onWindowStageDestroy() {
console.log("[Demo] MainAbility onWindoeStageDestroy")
}
onForeground() {
console.log("[Demo] MainAbility onForeground")
}
onBackground() {
console.log("[Demo] MainAbility onBackground")
}
}
```
The @Component decorated component obtains data.
```ts
let storage = LocalStorage.GetShared()
@Entry(storage)
@Component
struct LocalStorageComponent {
@LocalStorageLink("storageSimpleProp") simpleVarName: number = 0
build() {
Column(){
Text(this.simpleVarName.toString())
.onClick(()=>{
this.simpleVarName +=1;
})
Text(JSON.stringify(this.simpleVarName))
.fontSize(50)
}
.height(500)
}
}
```
### Example 2 (Defining LocalStorage on the Entry Page)
```ts
let storage = new LocalStorage({"PropA":47});
@Entry(storage)
@Component
struct ComA {
@LocalStorageLink("PropA") storLink: number = 1;
build() {
Column() {
Text(`Parent from LocalStorage ${ this.storLink }`)
.onClick(()=>this.storLink+=1)
Child()
}
}
}
@Component
struct Child{
@LocalStorageLink("PropA") storLink: number = 1;
build() {
Text(`Parent from LocalStorage ${ this.storLink }`)
.onClick(()=>this.storLink+=1)
}
}
```
......@@ -8,7 +8,7 @@ The open-source code repositories are available at [https://openharmony.gitee.co
## Overview of Source Code Acquisition<a name="section12763342204"></a>
The OpenHarmony source code is open to you as [HPM parts](../hpm-part/Readme-EN.md), which can be obtained in any of the following ways:
The OpenHarmony source code is open to you as [HPM parts](../hpm-part/hpm-part-about.md), which can be obtained in any of the following ways:
- **Method 1**: Acquire the source code from the Gitee code repository. You can use the **repo** or **git** tool to download the latest code from the code repository.
- **Method 2**: Acquire the source code from [DevEco Marketplace](https://repo.harmonyos.com/#/en/home). Visit [DevEco Marketplace](https://repo.harmonyos.com/#/en/home), search for your desired open-source distribution, and download the bundle list \(or customize bundles and download the bundle list\). Then use the **hpm-cli** tool to download and install the bundles and compilation toolchain on your local PC.
......@@ -67,7 +67,11 @@ The OpenHarmony source code is open to you as [HPM parts](../hpm-part/Readme-EN.
>![](../public_sys-resources/icon-note.gif) **NOTE**
>
>Download the master code if you want to get quick access to the latest features for your development. Download the release code, which is more stable, if you want to develop commercial functionalities.
>Download the release code, which is more stable, if you want to develop commercial functionalities. Download the master code if you want to get quick access to the latest features for your development.
- **Obtaining OpenHarmony release code**
For details about how to obtain the source code of an OpenHarmony release, see the [Release Notes](../../release-notes/Readme.md).
- **Obtaining OpenHarmony master code**
......@@ -87,10 +91,6 @@ The OpenHarmony source code is open to you as [HPM parts](../hpm-part/Readme-EN.
repo forall -c 'git lfs pull'
```
- **Obtaining OpenHarmony release code**
For details about how to obtain the source code of an OpenHarmony release, see the [Release Notes]([Release Notes](../../release-notes/Readme.md).
## Method 2: Acquiring Source Code from DevEco Marketplace<a name="section463013147412"></a>
......
# Privacy and Security<a name="EN-US_TOPIC_0000001111199450"></a>
- **[Privacy Protection](security-privacy-protection.md)**
- **[Security Guidelines](security-guidelines-overall.md)**
# Telephony
- **[Telephony Overview](subsys-tel-overview.md)**
- **[Telephony Development](subsys-tel-guide.md)**
# 应用测试
- 自动化测试框架
- [自动化测试框架使用指导](arkxtest-guidelines.md)
- SmartPerf性能工具
- [SmartPerf性能工具使用指导](smartperf-guidelines.md)
# SmartPerf性能工具使用指导
## 概述
为支撑OpenHarmony性能测试,我们向用户提供了符合功能需求并且可靠、易用的性能测试工具。支持开发者针对应用进行相应的性能数据采集以及指标计算功能。
## 简介
SmartPerf端是一款基于OpenHarmony系统开发的性能功耗测试工具,操作简单易用,可提供包括性能、功耗的关键KPI指标,给出具体指标的测试值,包括采集设备的FPS、CPU、GPU、Ftrace等指标数据;
目前SmartPerf工具提供了两种使用方式,分别为hap应用可视化操作方式(SmartPerf-Device)和shell命令行方式(SmartPerf-Daemon),其中SmartPerf-Device支持可视化操作、悬浮窗控制暂停,悬浮窗实时展示数据,SmartPerf-Daemon主要适用于无屏设备、性能较差的设备,对3568等设备同样支持。
## 实现原理
SmartPerf工具主要包括SmartPerf-Device、SmartPerf-Daemon两个部分,其中Device采集的FPS、RAM、Trace等指标需要通过发送消息给Daemon端去采集数据,然后接收Daemon回传的数据展示,同时Daemon端也提供了shell命令的方式单独执行采集,工具的主要功能组成如下图:
![图片说明](figures/SmartPerfStru.png)
## 约束与限制
1.SmartPerf-Device、SmartPerf-Daemon在3.2系统版本后开始预制使用。
2.其中SmartPerf-Device的使用必须是具备屏幕的设备。
## 环境准备
SmartPerf-Daemon执行需要PC连接OpenHarmony设备,如RK3568开发板等。
## 执行性能测试
**SmartPerf-Device应用可视化使用示例**
以下SmartPerf-Device应用内截图以RK3568设备为例。
1.应用采集配置。
启动SmartPerf-Device进入首页,选择测试应用、测试指标项,点击”开始测试“,拉起测试应用。
![图片说明](figures/SmartPerfConfig1.png)
![图片说明](figures/SmartPerfConfig2.png)
![图片说明](figures/SmartPerfConfig3.png)
2.悬浮窗控制采集。
点击悬浮窗”start“开始采集,单击悬浮窗”计时器“暂停采集,再次单击继续采集双击计时器,实时展示采集数据,可拖动悬浮框更改悬浮框位置,长按”计时器“,结束采集。
![图片说明](figures/SmartPerfControl1.png)
![图片说明](figures/SmartPerfControl2.png)
3.查看报告。
点击“报告”,查看测试报告列表,点击“报告列表”,查看测试指标项详情。
![图片说明](figures/SmartPerfReport1.png)
![图片说明](figures/SmartPerfReport2.png)
**SmartPerf-Daemon命令行使用示例**
1.进入shell, 执行查看帮助命令。
```
:# SP_daemon --help
```
2.执行采集命令。
```
:# SP_daemon -N 2 -PKG com.ohos.contacts -c -g -t -p -r
```
**采集命令使用示例解析**
| 命令 | 功能 |是否必选|
| :-----| :--------------------- |:-----|
| -N | 设置采集次数 |是|
| -PKG | 设置包名 | 否|
| -PID | 设置进程pid(对于ram适用) |否|
| -c | 是否采集cpu | 否|
| -g | 是否采集gpu |否|
| -f | 是否采集fps |否|
| -t | 是否采集温度 |否|
| -p | 是否采集电流 |否|
| -r | 是否采集内存 |否|
**测试结果默认输出路径如下**
```
报告存放路径:/data/local/tmp/data.csv
```
......@@ -2,7 +2,7 @@
- [Ability框架开发常见问题](faqs-ability.md)
- [UI框架(JS)开发常见问题](faqs-ui-js.md)
- [UI框架(eTS)开发常见问题](faqs-ui-ets.md)
- [UI框架(ArkTS)开发常见问题](faqs-ui-ets.md)
- [图形图像开发常见问题](faqs-graphics.md)
- [文件管理开发常见问题](faqs-file-management.md)
- [网络与连接开发常见问题](faqs-connectivity.md)
......
# UI框架(eTS)开发常见问题
# UI框架(ArkTS)开发常见问题
## TS语言在生成器函数中编译失败,有哪些使用限制?
## ArkTS语言在生成器函数中编译失败,有哪些使用限制?
适用于:OpenHarmony SDK 3.2.5.3版本,API9 Stage模型
TS语言的使用在生成器函数中存在以下限制:
ArkTS语言的使用在生成器函数中存在以下限制:
- 表达式仅允许在字符串(${expression})、if条件、ForEach的参数和组件的参数中使用;
......
......@@ -8,7 +8,7 @@ AudioCapturer提供了用于获取原始音频文件的方法。开发者可以
## 运作机制
该模块提供了音频采集模块的状态变化示意图
该模块提供了音频采集模块的状态变化示意图
**图1** 音频采集状态变化示意图
......
......@@ -143,12 +143,28 @@ struct LocalStorageComponent {
@LocalStorageLink("storageSimpleProp") simpleVarName: number = 0
build() {
Column(){
Text(this.simpleVarName.toString())
Button(`LocalStorageLink: ${ this.simpleVarName.toString() }`)
.onClick(()=>{
this.simpleVarName +=1;
})
Text(JSON.stringify(this.simpleVarName))
.fontSize(50)
LocalStorageComponentProp();
}
.height(500)
}
}
@Component
struct LocalStorageComponentProp {
@LocalStorageProp("storageSimpleProp") simpleVarName: number = 0
build() {
Column() {
Button(`LocalStorageProp: ${ this.simpleVarName.toString() }`)
.onClick(() => {
this.simpleVarName += 1;
})
Text(JSON.stringify(this.simpleVarName))
.fontSize(50)
}
.height(500)
}
......
......@@ -64,6 +64,14 @@ create(colorSpaceName: ColorSpace): ColorSpaceManager
| ------------------ | ------------------------ |
| [ColorSpaceManager](#colorspacemanager) | 返回当前创建的色域对象实例。 |
**错误码:**
以下错误码的详细介绍请参见[色彩管理错误码](../errorcodes/errorcode-colorspace-manager.md)
| 错误码ID | 错误信息 |
| ------- | ----------------------- |
| 18600001 | Parameter value is abnormal. |
**示例:**
```js
......@@ -96,6 +104,14 @@ create(primaries: ColorSpacePrimaries, gamma: number): ColorSpaceManager
| ------------------ | ------------------------ |
| [ColorSpaceManager](#colorspacemanager) | 返回当前创建的色域对象实例。<br>色域类型定义为[ColorSpace](#colorspace)枚举值`CUSTOM`。 |
**错误码:**
以下错误码的详细介绍请参见[色彩管理错误码](../errorcodes/errorcode-colorspace-manager.md)
| 错误码ID | 错误信息 |
| ------- | ----------------------- |
| 18600001 | Parameter value is abnormal. |
**示例:**
```js
......@@ -138,6 +154,14 @@ getColorSpaceName(): ColorSpace
| ------------------ | ------------------------ |
| [ColorSpace](#colorspace) | 返回色域类型枚举值。 |
**错误码:**
以下错误码的详细介绍请参见[色彩管理错误码](../errorcodes/errorcode-colorspace-manager.md)
| 错误码ID | 错误信息 |
| ------- | ----------------------- |
| 18600001 | Parameter value is abnormal. |
**示例:**
```js
......@@ -162,6 +186,14 @@ getWhitePoint(): Array\<number\>
| ------------------ | ------------------------ |
| Array\<number\> | 返回色域白点值[x, y]。 |
**错误码:**
以下错误码的详细介绍请参见[色彩管理错误码](../errorcodes/errorcode-colorspace-manager.md)
| 错误码ID | 错误信息 |
| ------- | ----------------------- |
| 18600001 | Parameter value is abnormal. |
**示例:**
```js
......@@ -186,6 +218,14 @@ getGamma(): number
| ------------------ | ------------------------ |
| number | 返回色域gamma值。 |
**错误码:**
以下错误码的详细介绍请参见[色彩管理错误码](../errorcodes/errorcode-colorspace-manager.md)
| 错误码ID | 错误信息 |
| ------- | ----------------------- |
| 18600001 | Parameter value is abnormal. |
**示例:**
```js
......
......@@ -89,8 +89,9 @@ getDefaultDisplaySync(): Display
**示例:**
```js
let displayClass = null;
try {
let displayClass = display.getDefaultDisplaySync();
displayClass = display.getDefaultDisplaySync();
} catch (exception) {
console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception));
};
......@@ -208,8 +209,9 @@ try {
return;
};
let ret = undefined;
try {
let ret = display.hasPrivateWindow(displayClass.id);
ret = display.hasPrivateWindow(displayClass.id);
} catch (exception) {
console.error('Failed to check has privateWindow or not. Code: ' + JSON.stringify(exception));
};
......@@ -243,7 +245,7 @@ on(type: 'add'|'remove'|'change', callback: Callback&lt;number&gt;): void
```js
let callback = (data) => {
console.info('Listening enabled. Data: ' + JSON.stringify(data));
}
};
try {
display.on("add", callback);
} catch (exception) {
......@@ -445,8 +447,9 @@ getCutoutInfo(callback: AsyncCallback&lt;CutoutInfo&gt;): void
**示例:**
```js
let displayClass = null;
try {
let displayClass = display.getDefaultDisplaySync();
displayClass = display.getDefaultDisplaySync();
} catch (exception) {
console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception));
};
......@@ -483,8 +486,9 @@ getCutoutInfo(): Promise&lt;CutoutInfo&gt;
**示例:**
```js
let displayClass = null;
try {
let displayClass = display.getDefaultDisplaySync();
displayClass = display.getDefaultDisplaySync();
} catch (exception) {
console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception));
};
......
......@@ -29,7 +29,7 @@ write(info: [AppEventInfo](#appeventinfo), callback: AsyncCallback&lt;void&gt;):
**错误码:**
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errcode-hiviewdfx-hiappevent.md)
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errorcode-hiappevent.md)
| 错误码ID | 错误信息 |
| -------- | --------------------------------------------- |
......@@ -83,7 +83,7 @@ write(info: [AppEventInfo](#appeventinfo)): Promise&lt;void&gt;
**错误码:**
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errcode-hiviewdfx-hiappevent.md)
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errorcode-hiappevent.md)
| 错误码ID | 错误信息 |
| -------- | --------------------------------------------- |
......@@ -142,7 +142,7 @@ configure(config: [ConfigOption](configoption)): void
**错误码:**
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errcode-hiviewdfx-hiappevent.md)
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errorcode-hiappevent.md)
| 错误码ID | 错误信息 |
| -------- | -------------------------------- |
......@@ -195,7 +195,7 @@ addWatcher(watcher: [Watcher](#watcher)): [AppEventPackageHolder](#appeventpacka
**错误码:**
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errcode-hiviewdfx-hiappevent.md)
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errorcode-hiappevent.md)
| 错误码ID | 错误信息 |
| -------- | ------------------------------- |
......@@ -272,7 +272,7 @@ removeWatcher(watcher: [Watcher](#watcher)): void
**错误码:**
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errcode-hiviewdfx-hiappevent.md)
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errorcode-hiappevent.md)
| 错误码ID | 错误信息 |
| -------- | --------------------- |
......@@ -373,7 +373,7 @@ setSize(size: number): void
**错误码:**
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errcode-hiviewdfx-hiappevent.md)
以下错误码的详细介绍请参见[应用事件打点错误码](../errorcodes/errorcode-hiappevent.md)
| 错误码ID | 错误信息 |
| -------- | ------------------- |
......
......@@ -719,7 +719,7 @@ delete(callback: AsyncCallback&lt;boolean&gt;): void
**需要权限**:ohos.permission.INTERNET
**系统能力**: 以下各项对应的系统能力均为SystemCapability.MiscServices.Upload。
**系统能力**: 以下各项对应的系统能力均为SystemCapability.MiscServices.Download。
| 名称 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
......@@ -733,7 +733,7 @@ delete(callback: AsyncCallback&lt;boolean&gt;): void
**需要权限**:ohos.permission.INTERNET
**系统能力**: 以下各项对应的系统能力均为SystemCapability.MiscServices.Upload。
**系统能力**: 以下各项对应的系统能力均为SystemCapability.MiscServices.Download。
| 名称 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
......
......@@ -39,7 +39,7 @@ getAllScreens(callback: AsyncCallback&lt;Array&lt;Screen&gt;&gt;): void
**示例:**
```js
var screenClass = null;
let screenClass = null;
screen.getAllScreens((err, data) => {
if (err.code) {
console.error('Failed to get all screens . Cause: ' + JSON.stringify(err));
......@@ -75,7 +75,7 @@ getAllScreens(): Promise&lt;Array&lt;Screen&gt;&gt;
**示例:**
```js
var screenClass = null;
let screenClass = null;
let promise = screen.getAllScreens();
promise.then((data) => {
screenClass = data[0];
......
......@@ -6,6 +6,7 @@
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 本模块首批接口从API version 6开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
> - 本模块接口为系统接口。
> - 由于系统参数都是各个系统服务的内部信息和控制参数,每个系统参数都有各自不同的DAC和MAC访问控制权限,三方应用不能使用此类接口。
......@@ -248,4 +249,4 @@ try {
}catch(e){
console.log("set unexpected error: " + e);
}
```
\ No newline at end of file
```
# 系统参数
系统参数(SystemParameter)是为各系统服务提供的简单易用的键值对访问接口,各个系统服务可以定义系统参数来描述该服务的状态信息,或者通过系统参数来改变系统服务的行为。其基本操作原语为get和set,通过get可以查询系统参数的值,通过set可以修改系统参数的值。
详细的系统参数设计原理及定义可参考
[系统参数](../../../device-dev/subsystems/subsys-boot-init-sysparam.md)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 本模块首批接口从API version 9开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
> - 本模块接口为系统接口。
> - 由于系统参数都是各个系统服务的内部信息和控制参数,每个系统参数都有各自不同的DAC和MAC访问控制权限,三方应用不能使用此类接口。
## 导入模块
```ts
import systemparameter from '@ohos.systemParameterV9'
```
## systemparameter.getSync
getSync(key: string, def?: string): string
获取系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待查询的系统参数Key。 |
| def | string | 否 | 默认值。 |
**返回值:**
| 类型 | 说明 |
| -------- | -------- |
| string | 系统参数值,若key不存在,返回默认值。若未指定默认值,返回空字符串。 |
**示例:**
```ts
try {
var info = systemparameter.getSync("const.ohos.apiversion");
console.log(JSON.stringify(info));
}catch(e){
console.log("getSync unexpected error: " + e);
}
```
## systemparameter.get
get(key: string, callback: AsyncCallback&lt;string&gt;): void
获取系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待查询的系统参数Key。 |
| callback | AsyncCallback&lt;string&gt; | 是 | 回调函数。 |
**示例:**
```ts
try {
systemparameter.get("const.ohos.apiversion", function (err, data) {
if (err == undefined) {
console.log("get test.parameter.key value success:" + data)
} else {
console.log(" get test.parameter.key value err:" + err.code)
}});
}catch(e){
console.log("get unexpected error: " + e);
}
```
## systemparameter.get
get(key: string, def: string, callback: AsyncCallback&lt;string&gt;): void
获取系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待查询的系统参数Key。 |
| def | string | 是 | 默认值。 |
| callback | AsyncCallback&lt;string&gt; | 是 | 回调函数。 |
**示例:**
```ts
try {
systemparameter.get("const.ohos.apiversion", "default", function (err, data) {
if (err == undefined) {
console.log("get test.parameter.key value success:" + data)
} else {
console.log(" get test.parameter.key value err:" + err.code)
}
});
}catch(e){
console.log("get unexpected error:" + e)
}
```
## systemparameter.get
get(key: string, def?: string): Promise&lt;string&gt;
获取系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待查询的系统参数Key。 |
| def | string | 否 | 默认值。 |
**返回值:**
| 类型 | 说明 |
| -------- | -------- |
| Promise&lt;string&gt; | Promise示例,用于异步获取结果。 |
**示例:**
```ts
try {
var p = systemparameter.get("const.ohos.apiversion");
p.then(function (value) {
console.log("get test.parameter.key success: " + value);
}).catch(function (err) {
console.log("get test.parameter.key error: " + err.code);
});
}catch(e){
console.log("get unexpected error: " + e);
}
```
## systemparameter.setSync
setSync(key: string, value: string): void
设置系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待设置的系统参数Key。 |
| value | string | 是 | 待设置的系统参数值。 |
**示例:**
```ts
try {
systemparameter.setSync("test.parameter.key", "default");
}catch(e){
console.log("set unexpected error: " + e);
}
```
## systemparameter.set
set(key: string, value: string, callback: AsyncCallback&lt;void&gt;): void
设置系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待设置的系统参数Key。 |
| value | string | 是 | 待设置的系统参数值。 |
| callback | AsyncCallback&lt;void&gt; | 是 | 回调函数。 |
**示例:**
```ts
try {
systemparameter.set("test.parameter.key", "testValue", function (err, data) {
if (err == undefined) {
console.log("set test.parameter.key value success :" + data)
} else {
console.log("set test.parameter.key value err:" + err.code)
}});
}catch(e){
console.log("set unexpected error: " + e);
}
```
## systemparameter.set
set(key: string, value: string): Promise&lt;void&gt;
设置系统参数Key对应的值。
**系统能力:** SystemCapability.Startup.SystemInfo
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| key | string | 是 | 待设置的系统参数Key。 |
| value| string | 是 | 待设置的系统参数值。 |
**返回值:**
| 类型 | 说明 |
| -------- | -------- |
| Promise&lt;void&gt; | Promise示例,用于异步获取结果。 |
**示例:**
```ts
try {
var p = systemparameter.set("test.parameter.key", "testValue");
p.then(function (value) {
console.log("set test.parameter.key success: " + value);
}).catch(function (err) {
console.log(" set test.parameter.key error: " + err.code);
});
}catch(e){
console.log("set unexpected error: " + e);
}
```
......@@ -592,6 +592,7 @@ minimizeAll(id: number): Promise&lt;void&gt;
import display from '@ohos.display'
import window from '@ohos.window'
let displayClass = null;
try {
displayClass = display.getDefaultDisplaySync();
} catch (exception) {
......@@ -923,7 +924,7 @@ create(ctx: BaseContext, id: string, type: WindowType, callback: AsyncCallback&l
```js
let windowClass = null;
window.create(this.context, 'alertWindow', window.WindowType.TYPE_SYSTEM_ALERT, (err, data) => {
window.create(this.context, 'alertWindow', window.WindowType.TYPE_SYSTEM_ALERT, (err, data) => {
if (err.code) {
console.error('Failed to create the window. Cause: ' + JSON.stringify(err));
return;
......@@ -998,13 +999,13 @@ find(id: string, callback: AsyncCallback&lt;Window&gt;): void
```js
let windowClass = null;
window.find('alertWindow', (err, data) => {
if (err.code) {
console.error('Failed to find the Window. Cause: ' + JSON.stringify(err));
return;
}
windowClass = data;
console.info('Succeeded in finding the window. Data: ' + JSON.stringify(data));
window.find('alertWindow', (err, data) => {
if (err.code) {
console.error('Failed to find the Window. Cause: ' + JSON.stringify(err));
return;
}
windowClass = data;
console.info('Succeeded in finding the window. Data: ' + JSON.stringify(data));
});
```
......@@ -1038,7 +1039,7 @@ find(id: string): Promise&lt;Window&gt;
let windowClass = null;
let promise = window.find('alertWindow');
promise.then((data)=> {
windowClass = data;
windowClass = data;
console.info('Succeeded in finding the window. Data: ' + JSON.stringify(data));
}).catch((err)=>{
console.error('Failed to find the Window. Cause: ' + JSON.stringify(err));
......@@ -1105,7 +1106,7 @@ getTopWindow(): Promise&lt;Window&gt;
let windowClass = null;
let promise = window.getTopWindow();
promise.then((data)=> {
windowClass = data;
windowClass = data;
console.info('Succeeded in obtaining the top window. Data: ' + JSON.stringify(data));
}).catch((err)=>{
console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(err));
......@@ -2348,25 +2349,20 @@ loadContent(path: string, storage: LocalStorage, callback: AsyncCallback&lt;void
**示例:**
```ts
class myAbility extends Ability {
storage : LocalStorage
onWindowStageCreate(windowStage) {
this.storage = new LocalStorage();
this.storage.setOrCreate('storageSimpleProp',121);
console.log('onWindowStageCreate');
try {
windowStage.loadContent('pages/page2',this.storage,(err) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
});
} catch (exception) {
console.error('Failed to load the content. Cause:' + JSON.stringify(exception));
};
}
}
let storage = new LocalStorage();
storage.setOrCreate('storageSimpleProp',121);
console.log('onWindowStageCreate');
try {
windowClass.loadContent('pages/page2', storage, (err) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
});
} catch (exception) {
console.error('Failed to load the content. Cause:' + JSON.stringify(exception));
};
```
### loadContent<sup>9+</sup>
......@@ -2404,26 +2400,19 @@ loadContent(path: string, storage: LocalStorage): Promise&lt;void&gt;
**示例:**
```ts
class myAbility extends Ability {
storage : LocalStorage
onWindowStageCreate(windowStage) {
this.storage = new LocalStorage();
this.storage.setOrCreate('storageSimpleProp',121);
console.log('onWindowStageCreate');
let windowClass = null;
try {
let promise = windowStage.loadContent('pages/page2',this.storage);
promise.then(()=> {
windowClass = data;
console.info('Succeeded in loading the content.');
}).catch((err)=>{
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
});
} catch (exception) {
console.error('Failed to load the content. Cause:' + JSON.stringify(exception));
};
}
}
let storage = new LocalStorage();
storage.setOrCreate('storageSimpleProp',121);
console.log('onWindowStageCreate');
try {
let promise = windowClass.loadContent('pages/page2', storage);
promise.then(() => {
console.info('Succeeded in loading the content.');
}).catch((err) => {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
});
} catch (exception) {
console.error('Failed to load the content. Cause:' + JSON.stringify(exception));
};
```
### isWindowShowing<sup>9+</sup>
......@@ -2719,7 +2708,7 @@ off(type: 'screenshot', callback?: Callback&lt;void&gt;): void
```js
let callback = ()=>{
console.info('screenshot happened');
}
};
try {
windowClass.on('screenshot', callback);
} catch (exception) {
......@@ -3745,13 +3734,13 @@ snapshot(callback: AsyncCallback&lt;image.PixelMap&gt;): void
**示例:**
```js
windowClass.snapshot((err, data) => {
windowClass.snapshot((err, pixelMap) => {
if (err.code) {
console.error('Failed to snapshot window. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in snapshotting window. Pixel bytes number: ' + pixelMap.getPixelBytesNumber());
data.release(); // PixelMap使用完后及时释放内存
pixelMap.release(); // PixelMap使用完后及时释放内存
});
```
......@@ -3855,9 +3844,9 @@ scale(scaleOptions: ScaleOptions): void
let obj : window.ScaleOptions = {
x : 2.0,
y : 1.0,
pivotX = 0.5;
pivotY = 0.5;
}
pivotX : 0.5,
pivotY : 0.5
};
try {
windowClass.scale(obj);
} catch (exception) {
......@@ -3897,9 +3886,9 @@ let obj : window.RotateOptions = {
x : 1.0,
y : 1.0,
z : 45.0,
pivotX = 0.5;
pivotY = 0.5;
}
pivotX : 0.5,
pivotY : 0.5
};
try {
windowClass.rotate(obj);
} catch (exception) {
......@@ -3939,7 +3928,7 @@ let obj : window.TranslateOptions = {
x : 100.0,
y : 0.0,
z : 0.0
}
};
try {
windowClass.translate(obj);
} catch (exception) {
......@@ -3977,7 +3966,7 @@ try {
```js
let controller = windowClass.getTransitionController(); // 获取属性转换控制器
controller.animationForHidden = (context : window.TransitionContext) => {
let toWindow = context.toWindow
let toWindow = context.toWindow;
animateTo({
duration: 1000, // 动画时长
tempo: 0.5, // 播放速率
......@@ -3993,7 +3982,7 @@ controller.animationForHidden = (context : window.TransitionContext) => {
x : 100.0,
y : 0.0,
z : 0.0
}
};
toWindow.translate(obj); // 设置动画过程中的属性转换
console.info('toWindow translate end');
}
......@@ -4108,7 +4097,7 @@ setBackdropBlurStyle(blurStyle: BlurStyle): void
```js
try {
windowClass.setBackdropBlurStyle(window.BlurType.THIN);
windowClass.setBackdropBlurStyle(window.BlurStyle.THIN);
} catch (exception) {
console.error('Failed to set backdrop blur style. Cause: ' + JSON.stringify(exception));
};
......@@ -6525,7 +6514,7 @@ completeTransition(isCompleted: boolean): void
```js
let controller = windowClass.getTransitionController();
controller.animationForShown = (context : window.TransitionContext) => {
let toWindow = context.toWindow
let toWindow = context.toWindow;
animateTo({
duration: 1000, // 动画时长
tempo: 0.5, // 播放速率
......@@ -6538,7 +6527,7 @@ controller.animationForShown = (context : window.TransitionContext) => {
x : 100.0,
y : 0.0,
z : 0.0
}
};
toWindow.translate(obj);
console.info('toWindow translate end');
}
......@@ -6577,7 +6566,7 @@ animationForShown(context: TransitionContext): void
```js
let controller = windowClass.getTransitionController();
controller.animationForShown = (context : window.TransitionContext) => {
let toWindow = context.toWindow
let toWindow = context.toWindow;
animateTo({
duration: 1000, // 动画时长
tempo: 0.5, // 播放速率
......@@ -6593,7 +6582,7 @@ controller.animationForShown = (context : window.TransitionContext) => {
x : 100.0,
y : 0.0,
z : 0.0
}
};
toWindow.translate(obj);
console.info('toWindow translate end');
}
......@@ -6623,7 +6612,7 @@ animationForHidden(context: TransitionContext): void
```js
let controller = windowClass.getTransitionController();
controller.animationForHidden = (context : window.TransitionContext) => {
let toWindow = context.toWindow
let toWindow = context.toWindow;
animateTo({
duration: 1000, // 动画时长
tempo: 0.5, // 播放速率
......@@ -6639,7 +6628,7 @@ controller.animationForHidden = (context : window.TransitionContext) => {
x : 100.0,
y : 0.0,
z : 0.0
}
};
toWindow.translate(obj);
console.info('toWindow translate end');
}
......
......@@ -16,7 +16,7 @@
## 接口
Web(options: { src: ResourceStr, controller: WebController })
Web(options: { src: ResourceStr, controller: WebController | WebviewController})
> **说明:**
>
......@@ -27,7 +27,7 @@ Web(options: { src: ResourceStr, controller: WebController })
| 参数名 | 参数类型 | 必填 | 参数描述 |
| ---------- | ------------------------------- | ---- | ------- |
| src | [ResourceStr](ts-types.md) | 是 | 网页资源地址。 |
| controller | [WebController](#webcontroller) | 否 | 控制器。 |
| controller | [WebController](#webcontroller) [WebviewController](../apis/js-apis-webview.md#webviewcontroller) |是 | 控制器。 |
**示例:**
......@@ -45,6 +45,21 @@ Web(options: { src: ResourceStr, controller: WebController })
}
}
```
```ts
// xxx.ets
import web_webview from '@ohos.web.webview'
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController();
build() {
Column() {
Web({ src: 'www.example.com', controller: this.controller })
}
}
}
```
加载本地网页
```ts
......@@ -193,7 +208,7 @@ imageAccess(imageAccess: boolean)
### javaScriptProxy
javaScriptProxy(javaScriptProxy: { object: object, name: string, methodList: Array\<string\>,
controller: WebController })
controller: WebController | WebviewController})
注入JavaScript对象到window对象中,并在window对象中调用该对象的方法。所有参数不支持更新。
......@@ -204,7 +219,7 @@ javaScriptProxy(javaScriptProxy: { object: object, name: string, methodList: Arr
| object | object | 是 | - | 参与注册的对象。只能声明方法,不能声明属性。 |
| name | string | 是 | - | 注册对象的名称,与window中调用的对象名一致。 |
| methodList | Array\<string\> | 是 | - | 参与注册的应用侧JavaScript对象的方法。 |
| controller | [WebController](#webcontroller) | 否 | - | 控制器。 |
| controller | [WebController](#webcontroller) [WebviewController](../apis/js-apis-webview.md#webviewcontroller) | 是 | - | 控制器。 |
**示例:**
......@@ -239,6 +254,39 @@ javaScriptProxy(javaScriptProxy: { object: object, name: string, methodList: Arr
}
}
```
```ts
// xxx.ets
import web_webview from '@ohos.web.webview'
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController();
testObj = {
test: (data1, data2, data3) => {
console.log("data1:" + data1);
console.log("data2:" + data2);
console.log("data3:" + data3);
return "AceString";
},
toString: () => {
console.log('toString' + "interface instead.");
}
}
build() {
Column() {
Web({ src: 'www.example.com', controller: this.controller })
.javaScriptAccess(true)
.javaScriptProxy({
object: this.testObj,
name: "objName",
methodList: ["test", "toString"],
controller: this.controller,
})
}
}
}
```
### javaScriptAccess
......
......@@ -27,8 +27,8 @@ Grid(scroller?: Scroller)
| 名称 | 参数类型 | 描述 |
| -------- | -------- | -------- |
| columnsTemplate | string | 设置当前网格布局列的数量,不设置时默认1列。<br/>例如,&nbsp;'1fr&nbsp;1fr&nbsp;2fr'&nbsp;是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。<br/>默认值:'1fr' |
| rowsTemplate | string | 设置当前网格布局行的数量,不设置时默认1行。<br/>例如,&nbsp;'1fr&nbsp;1fr&nbsp;2fr'是将父组件分三行,将父组件允许的高分为4等份,第一行占1份,第二行占一份,第三行占2份。<br/>默认值:'1fr' |
| columnsTemplate | string | 设置当前网格布局列的数量,不设置时默认1列。<br/>例如,&nbsp;'1fr&nbsp;1fr&nbsp;2fr'&nbsp;是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。|
| rowsTemplate | string | 设置当前网格布局行的数量,不设置时默认1行。<br/>例如,&nbsp;'1fr&nbsp;1fr&nbsp;2fr'是将父组件分三行,将父组件允许的高分为4等份,第一行占1份,第二行占一份,第三行占2份。 |
| columnsGap | Length | 设置列与列的间距。<br/>默认值:0 |
| rowsGap | Length | 设置行与行的间距。<br/>默认值:0 |
| scrollBar | [BarState](ts-appendix-enums.md#barstate) | 设置滚动条状态。<br/>默认值:BarState.Off |
......@@ -37,12 +37,32 @@ Grid(scroller?: Scroller)
| cachedCount | number | 设置预加载的GridItem的数量。具体使用可参考[减少应用白块说明](../../ui/ts-performance-improvement-recommendation.md#减少应用滑动白块)<br/>默认值:1 |
| editMode <sup>8+</sup> | boolean | 设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部[GridItem](ts-container-griditem.md)<br/>默认值:flase |
| layoutDirection<sup>8+</sup> | [GridDirection](#griddirection8枚举说明) | 设置布局的主轴方向。<br/>默认值:GridDirection.Row |
| maxCount<sup>8+</sup> | number | 当layoutDirection是Row/RowReverse时,表示可显示的最大行数<br/>当layoutDirection是Column/ColumnReverse时,表示可显示的最大列数。<br/>默认值:1 |
| minCount<sup>8+</sup> | number | 当layoutDirection是Row/RowReverse时,表示可显示的最小行数。<br/>当layoutDirection是Column/ColumnReverse时,表示可显示的最小列数。<br/>默认值:1 |
| cellLength<sup>8+</sup> | number | 当layoutDirection是Row/RowReverse时,表示一行的高度。<br/>当layoutDirection是Column/ColumnReverse时,表示一列的宽度。<br/>默认值:0 |
| maxCount<sup>8+</sup> | number | 当layoutDirection是Row/RowReverse时,表示可显示的最大列数<br/>当layoutDirection是Column/ColumnReverse时,表示可显示的最大行数。<br/>默认值:Infinity |
| minCount<sup>8+</sup> | number | 当layoutDirection是Row/RowReverse时,表示可显示的最小列数。<br/>当layoutDirection是Column/ColumnReverse时,表示可显示的最小行数。<br/>默认值:1 |
| cellLength<sup>8+</sup> | number | 当layoutDirection是Row/RowReverse时,表示一行的高度。<br/>当layoutDirection是Column/ColumnReverse时,表示一列的宽度。<br/>默认值:第一个元素的大小 |
| multiSelectable<sup>8+</sup> | boolean | 是否开启鼠标框选。<br/>默认值:false<br/>-&nbsp;false:关闭框选。<br/>-&nbsp;true:开启框选。 |
| supportAnimation<sup>8+</sup> | boolean | 是否支持动画。<br/>默认值:false |
Grid组件根据rowsTemplate、columnsTemplate属性的设置情况,可分为以下三种布局模式:
1、rowsTemplate、columnsTemplate同时设置:
Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。例如rowsTemplate、columnsTemplate都设置为"1fr 1fr"时,则仅展示两行两列,共4个元素,其他元素不展示。
此模式下以下属性不生效:layoutDirection、maxCount、minCount、cellLength。
2、rowsTemplate、columnsTemplate仅设置其中的一个:
元素按照设置的方向进行排布,超出的元素可通过滚动的方式展示。例如Grid有十个元素,且设置columnsTemplate为"1fr 1fr 1fr",则Grid有三列,元素先填满一行,再填充下一行。在Grid区域外的元素,可通过竖直方向的滚动,进行展示。
此模式下以下属性不生效:layoutDirection、maxCount、minCount、cellLength。
3、rowsTemplate、columnsTemplate都不设置:
元素在layoutDirection方向上排布,列数由Grid的宽度、首个元素的宽度、minCount、maxCount、columnsGap共同决定;行数由Grid高度、首个元素高度、cellLength、rowsGap共同决定。超出行列容纳范围的元素不显示,也不能通过滚动进行展示。
此模式下仅生效以下属性:layoutDirection、maxCount、minCount、cellLength、editMode、columnsGap、rowsGap。
## GridDirection<sup>8+</sup>枚举说明
| 名称 | 描述 |
......
......@@ -138,4 +138,49 @@ struct LineExample1 {
}
```
![zh-cn_image1_0000001219982725](figures/zh-cn_image1_0000001219982725.png)
\ No newline at end of file
![zh-cn_image1_0000001219982725](figures/zh-cn_image1_0000001219982725.png)
### 示例3
```ts
// xxx.ets
@Entry
@Component
struct LineExample {
build() {
Column() {
Line()
.startPoint([50, 30])
.endPoint([300, 30])
.strokeWidth(10)
// 设置strokeDashArray的数组间隔为 50
Line()
.startPoint([50, 20])
.endPoint([300, 20])
.strokeWidth(10)
.strokeDashArray([50])
// 设置strokeDashArray的数组间隔为 50, 10
Line()
.startPoint([50, 20])
.endPoint([300, 20])
.strokeWidth(10)
.strokeDashArray([50, 10])
// 设置strokeDashArray的数组间隔为 50, 10, 20
Line()
.startPoint([50, 20])
.endPoint([300, 20])
.strokeWidth(10)
.strokeDashArray([50, 10, 20])
// 设置strokeDashArray的数组间隔为 50, 10, 20, 30
Line()
.startPoint([50, 20])
.endPoint([300, 20])
.strokeWidth(10)
.strokeDashArray([50, 10, 20, 30])
}
}
}
```
![zh-cn_image2_0000001219982725](figures/zh-cn_image2_0000001219982725.PNG)
\ No newline at end of file
......@@ -401,7 +401,7 @@ setOrCreate\<T>(propName: string, newValue: T): boolean
| 类型 | 描述 |
| ------- | ------------------------------------------------------------ |
| boolean | 如果已存在与给定键名字相同的属性,更新其值且返回true。如果不存在具有给定名称的属性,在LocalStorage中创建具有给定默认值的新属性,默认值必须是T类型。不允许undefined 或 null 返回true。 |
| boolean | 如果已存在与给定键名字相同的属性,更新其值且返回true。如果不存在具有给定名称的属性,在LocalStorage中创建具有给定默认值的新属性,默认值必须是T类型,不允许undefined 或 null 。 |
```ts
this.storage = new LocalStorage();
......
......@@ -10,7 +10,7 @@
| 名称 | 参数说明 | 描述 |
| ---------- | ---------------------------------------- | ---------------------------------------- |
| flexBasis | number \| string | 设置组件在父容器主轴方向上的基准尺寸。<br/>默认值:'auto'(表示组件在主轴方向上的基准尺寸为组件原本的大小) |
| flexBasis | number \| string | 设置组件在父容器主轴方向上的基准尺寸。<br/>默认值:'auto'(表示组件在主轴方向上的基准尺寸为组件原本的大小)<br/>不支持百分比设置。 |
| flexGrow | number | 设置父容器的剩余空间分配给此属性所在组件的比例。<br/>默认值:0 |
| flexShrink | number | 设置父容器压缩尺寸分配给此属性所在组件的比例。<br/>父容器为Row、Column时,默认值:0<br/> 父容器为flex时,默认值:1 |
| alignSelf | [ItemAlign](ts-appendix-enums.md#itemalign) | 子组件在父容器交叉轴的对齐格式,覆盖Flex布局容器中alignItems默认配置。<br/>默认值:ItemAlign.Auto |
......
# 系统参数错误码
## 14700101 系统参数查找失败
**错误信息**
System parameter can not be found.
**错误描述**
workspace中没有相应节点,或者没有设置key值,系统会报此错误码。
**可能原因**
参数没有设置,或设置失败。
**处理步骤**
设置合法的参数。
## 14700102 系统参数值无效
**错误信息**
System parameter value is invalid.
**错误描述**
当系统参数value值为空字符、非法字符或长度超出范围时,系统会报此错误码。
**可能原因**
接口的参数值超出设置范围或者含有特殊字符,比如,"const..param.xxx"。
**处理步骤**
修改value值为合法字符串。
## 14700103 系统权限操作权限被拒绝
**错误信息**
System permission operation permission denied.
**错误描述**
系统参数没有DAC或MAC权限时,系统会报此错误码。
**可能原因**
没有配置DAC或MAC权限。
**处理步骤**
添加相应的DAC或MAC权限。
## 14700104 系统内部错误,包括内存不足,死锁等
**错误信息**
System internal error including out of memory, deadlock etc.
**错误描述**
当试图修改const属性参数、socket连接失败、内存拷贝失败等错误时,系统会报此错误码。
**可能原因**
当socket连接异常,添加节点或获取节点失败。
**处理步骤**
1. 内存不足,需要分析整个进程的内存占用情况,是否有内存泄露的情况。
2. 死锁,多出现在多线程场景下,需要通过错误堆栈查看是否有死锁的场景。
\ No newline at end of file
# 色彩管理错误码
## 18600001 参数值异常
**错误信息**
Parameter value is abnormal.
**错误描述**
当参数值不符合接口调用要求时,系统会报此错误码。
**可能原因**
参数值超出接口调用范围会报错,如枚举值超出定义范围。
**处理步骤**
在定义接口参数前,确保参数值符合接口参数要求。
\ No newline at end of file
# 屏幕错误码
## 1400001 无效虚拟屏
### 错误信息
**错误信息**<br>
This is invalid screen.
### 错误描述
**错误描述**<br>
当操作无效的虚拟屏时,会报此错误码。
### 可能原因
**可能原因**
1. 虚拟屏未创建。
2. 虚拟屏已销毁。
### 处理步骤
**处理步骤**
1. 在操作虚拟屏前,检查该虚拟屏是否已经存在,确保已创建该虚拟屏。
2. 在操作虚拟屏前,检查虚拟屏是否已被销毁,确保其未被销毁,再进行相关操作。
## 1400002 无权限操作
### 错误信息
**错误信息**<br>
This operation is not access.
### 错误描述
**错误描述**<br>
当对无操作权限的对象进行操作时,会报此错误码。
### 可能原因
**可能原因**<br>
操作了其它进程的虚拟屏对象。
### 处理步骤
**处理步骤**<br>
请检查是否非法操作了别的进程的对象,删除相关非法操作。
## 1400003 系统服务工作异常
### 错误信息
**错误信息**<br>
This window manager service work abnormally.
### 错误描述
**错误描述**<br>
当系统服务工作异常时,会报此错误码。
### 可能原因
**可能原因**
1. 窗口内部服务没有正常启动。
2. 底层图形图像合成渲染异常。
### 处理步骤
**处理步骤**<br>
系统服务内部工作异常,请稍候重试,或者重启设备尝试。
......@@ -2,75 +2,75 @@
## 12900001 索引超过范围
### 错误信息
**错误信息**
The index is out of range.
### 错误描述
**错误描述**
当调用getRecord等涉及索引的接口时,索引超过范围时,系统会报此错误码。
### 可能原因
**可能原因**
接口的参数索引值超出当前PasteData中的记录数,比如,getRecord传入index值过大。
### 处理步骤
**处理步骤**
检查参数索引值是否在正确范围,使用恰当的索引值重新进行开发。
## 12900002 Record数量超过最大限制
### 错误信息
**错误信息**
The number of record exceeds the maximum limit.
### 错误描述
**错误描述**
当添加Record时,若当前PasteData记录数已达到最大值,系统会报此错误码。
### 可能原因
**可能原因**
当前PasteData记录数已达到最大值,未进行相关Record的删除或数目检查,直接继续添加Record导致。
### 处理步骤
**处理步骤**
1. 检查判断当前PasteData记录数是否已达最大值。
2. 若当前PasteData记录数已达最大值,删除相关Record后,再重新添加Record进行开发。
## 12900003 另外一个复制或粘贴正在进行
### 错误信息
**错误信息**
Another copy or paste is in progress.
### 错误描述
**错误描述**
上次的复制/粘贴动作还未结束时,再次调用相关接口,系统会报此错误码。
### 可能原因
**可能原因**
复制粘贴均为异步接口,当复制/粘贴的数据内容较大,需要时间较长时,在此期间再次执行复制/粘贴则会出错。
### 处理步骤
**处理步骤**
1. 再次进行复制/粘贴时,首先判断上次复制/粘贴的状态。
2. 当上次复制/粘贴动作完成后,再进行后续操作。
## 12900004 禁止复制
### 错误信息
**错误信息**
Replication is prohibited.
### 错误描述
**错误描述**
当对不支持复制的数据内容进行复制操作时,系统会报此错误码。
### 可能原因
**可能原因**
数据内容不支持复制,比如只读类型的数据内容。
### 处理步骤
**处理步骤**
1. 在对相关数据内容进行复制时,首先判断其数据类型是否支持复制。
2. 若数据内容不支持复制,不对此类数据内容进行复制操作。
\ No newline at end of file
......@@ -48,7 +48,7 @@ Task manager service error.
**可能原因**
该错误码表示服务异常,可能原因任务创建失败
该错误码表示服务异常,可能原因任务创建失败
**处理步骤**
......
......@@ -4,8 +4,8 @@
- 快速开始
- 快速入门
- [开发准备](quick-start/start-overview.md)
- [使用eTS语言开发(Stage模型)](quick-start/start-with-ets-stage.md)
- [使用eTS语言开发(FA模型)](quick-start/start-with-ets-fa.md)
- [使用ArkTS语言开发(Stage模型)](quick-start/start-with-ets-stage.md)
- [使用ArkTS语言开发(FA模型)](quick-start/start-with-ets-fa.md)
- [使用JS语言开发(FA模型)](quick-start/start-with-js-fa.md)
- 开发基础知识
- [应用包结构说明(FA模型)](quick-start/package-structure.md)
......@@ -14,7 +14,7 @@
- [HarmonyAppProvision配置文件](quick-start/app-provision-structure.md)
- 学习ArkTS语言
- [初识ArkTS语言](quick-start/arkts-get-started.md)
- eTS语法(声明式UI)
- ArkTS语法(声明式UI)
- [基本UI描述](quick-start/arkts-basic-ui-description.md)
- 状态管理
- [基本概念](quick-start/arkts-state-mgmt-concepts.md)
......@@ -994,7 +994,7 @@
- [full-SDK替换指南](quick-start/full-sdk-switch-guide.md)
- [Ability框架开发常见问题](faqs/faqs-ability.md)
- [UI框架(JS)开发常见问题](faqs/faqs-ui-js.md)
- [UI框架(eTS)开发常见问题](faqs/faqs-ui-ets.md)
- [UI框架(ArkTS)开发常见问题](faqs/faqs-ui-ets.md)
- [图形图像开发常见问题](faqs/faqs-graphics.md)
- [文件管理开发常见问题](faqs/faqs-file-management.md)
- [网络与连接开发常见问题](faqs/faqs-connectivity.md)
......
# 隐私与安全<a name="ZH-CN_TOPIC_0000001111199450"></a>
- **[隐私保护](security-privacy-protection.md)**
- **[安全指南](security-guidelines-overall.md)**
# 电话服务
- **[电话服务概述](subsys-tel-overview.md)**
- **[电话服务开发指导](subsys-tel-guide.md)**
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册