App
package for real machine debugging.Node
environment, use npm i
or yarn
to install the dependencies.Note: If the running result of the developer tool is inconsistent with the running result of the real machine, please refer to the debugging operation of the real machine.
❣️ Basic TYML, TYSS, and related syntax of Smart MiniApp.
❣️ Smart MiniApp page, component, combination development.
❣️ Introduction and usage of some APIs.
❣️ The built-in Smart MiniApp extension capability is supplemented, including theme adaptation, multi-language, etc.
❣️ Other extension capabilities, including component library, gesture library, chart library, animation library, etc.
├── project.tuya.json
├── app.js
├── app.json
├── app.tyss
├── assets
│ └── images
│ └── tab
│ └─ component.png
├── i18n
│ └── strings.json
├── components
│ └── foo
│ ├── index.js
│ ├── index.json
│ ├── index.tyml
│ └── index.tyss
├── pages
│ └── page
│ ├── index.js
│ ├── index.json
│ ├── index.tyml
│ └── index.tyss
├── theme.json
├── package.json
└── node_modules
index.less
file is required, index.tyss
only supports CSS
.data
corresponding to Page
Mustache
syntax (double curly brackets) to wrap variables, which can act on content, component properties (required within double quotes), control properties (required within double quotes), keywords (required within double quotes) within double quotation marks), operations, ternary operations, arithmetic operations, logical judgments, string operations, etc. See more.<!--tyml-->
<view> {{message}} </view>
// page.js
Page({
data: {
message: "Hello MINA!",
},
});
<!--tyml-->
<view ty:for="{{array}}"> {{item}} </view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5],
},
});
<!--tyml-->
<view ty:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view ty:elif="{{view == 'APP'}}"> APP </view>
<view ty:else="{{view == 'MINA'}}"> MINA </view>
// page.js
Page({
data: {
view: "MINA",
},
});
<!--tyml-->
<template name="staffName">
<view>
FirstName: {{firstName}}, LastName: {{lastName}}
</view>
</template>
<template is="staffName" data="{{...staffA}}"></template>
<template is="staffName" data="{{...staffB}}"></template>
<template is="staffName" data="{{...staffC}}"></template>
// page.js
Page({
data: {
staffA: { firstName: "Hulk", lastName: "Hu" },
staffB: { firstName: "Shang", lastName: "You" },
staffC: { firstName: "Gideon", lastName: "Lin" },
},
});
##Apps
Register the Miniapp. Accepts an Object parameter, which specifies the Miniapp's lifecycle callback, etc.
App()
** must be called in ** app.js
**, must be called and can only be called once. Otherwise, unexpected effects will occur. **
onLaunch
: Triggered when the Miniapp initialization is completed, and only triggered once globally.onShow
: Triggered when the Miniapp starts or enters the foreground display from the background.onHide
: Triggered when the Miniapp enters the background from the foreground.onError
: Triggered when a script error or API call error occurs in the Miniapp.onPageNotFound
: Triggered when the page to be opened by the Miniapp does not exist.onThemeChange
: Triggered when the system switches themes.Sample code
App({
onLaunch(options) {
// Do something initial when launch.
},
onShow(options) {
// Do something when show.
},
onHide() {
// Do something when hide.
},
onError(msg) {
console.log(msg);
},
globalData: "I am global data",
});
App
instance of the Miniapp through the getApp
method in js
(page
or component
).Sample code
//other.js
var appInstance = getApp();
console.log(appInstance.globalData); // I am global data
##Page
Object
type parameter, which specifies the initial data of the page, lifecycle callbacks, event handlers, etc.data
is the initial data used by the first render of the page.
Sample code
<view>{{text}}</view>
<view>{{array[0].msg}}</view>
Page({
data: {
text: "init data",
array: [{ msg: "1" }, { msg: "2" }],
},
});
Page
.setData
. setData
is asynchronous.Sample code
<view bind:tap="viewTap">{{num}}</view>
Page({
data: {
num: 0,
},
viewTap: function () {
this.setData({
num: this.data.num + 1,
});
},
});
onLoad
: Fired when the page loads. A page will only be called once, and the parameters in the path to open the current page can be obtained in the parameters of onLoad.onShow
: Triggered when the page is displayed/switched to the foreground.onReady
: Triggered when the page's initial rendering is complete. A page will only be called once, indicating that the page is ready to interact with the view layer.onHide
: Triggered when the page is hidden/cut into the background.onUnload
: Triggered when the page is unloaded.onPullDownRefresh
: Listen to user pull down refresh events.onReachBottom
: Listen to the user's bottom-up event.Sample code
//index.js
Page({
data: {
text: "This is page data.",
},
onLoad: function (options) {
// Do some initialize when page load.
},
onShow: function () {
// Do something when page show.
},
onReady: function () {
// Do something when page ready.
},
onHide: function () {
// Do something when page hide.
},
onUnload: function () {
// Do something when page close.
},
onPullDownRefresh: function () {
// Do something when pull down.
},
onReachBottom: function () {
// Do something when page reach bottom.
},
});
Object
to describe the logical interaction behavior of the component. See more.// file /components/foo/index.js
Component({
options: Object,
properties: Object,
observers: Object,
data: Object,
methods: Object,
behaviors: Array,
lifetimes: Object,
pageLifetimes: Object,
relations: Array,
});
type
. See more.properties
can listen for changes in property values through observer()
.Sample code
Component({
properties: {
myName: {
type: String,
value: "smart",
observer: function (newValue, oldValue) {
// do something
},
},
},
});
properties
) and data (data
) fields. See more.Component({
observers: {
"value1, value2": function (value1, value2) {
// trigger when this.setData corresponds to data
},
"some.subfield": function (subfield) {
// Triggered when this.data.some.subfield is set using setData
// (Other than that, setting this.data.some with setData will also fire)
subfield === this.data.some.subfield;
},
"arr[12]": function (arr12) {
// Triggered when this.data.arr[12] is set using setData
// (Other than that, setting this.data.arr with setData will also fire)
arr12 === this.data.arr[12];
},
"some.field.**": function (field) {
// Triggered when this.data.some.field itself or any sub-data fields under it are set using setData
// (Other than that, setting this.data.some with setData will also fire)
field === this.data.some.field;
},
"**": function () {
// every time setData fires
},
},
});
page
.<view>{{name}}: {{age}}</view>
Component({
properties: {
'name': {
type: String,
value: 'smart'
}
}
data: { age: 18 },
});
created
: Executed when the component instance has just been created.attached
: Executed when the component instance enters the page node tree.ready
: Executed after the component is laid out in the view layer.moved
: Executed when the component instance is moved to another location in the node tree.detached
: Executed when the component instance is removed from the page node tree.error
: Executed whenever a component method throws an error.Sample code
Component({
lifetimes: {
attached: function () {
// Executed when the component instance enters the page node tree
},
},
});
show
: Executed when the page the component is on is shown.hide
: Executed when the page the component is on is hidden.resize
: Executed when the size of the page where the component is located changes.Sample code
Component({
pageLifetimes: {
show: function () {
// Executed when the page where the component is located is displayed
},
},
});
There are two common communication methods between components.
TYML
data binding: used to set data from the parent component to the specified property of the child component, only JSON compatible data can be set.<!-- When the custom component triggers the "myevent" event, the "onMyEvent" method is called -->
<component-tag-name bind:myevent="onMyEvent" />
Page({
onMyEvent: function (e) {
e.detail; // The detail object provided when the custom component triggers the event
},
});
<!-- in custom component -->
<button bind:tap="onTap">Clicking this button will trigger the "myevent" event</button>
Component({
properties: {},
methods: {
onTap: function () {
var myEventDetail = {}; // detail object, provided to the event listener function
var myEventOption = {}; // option to trigger event
this.triggerEvent("myevent", myEventDetail, myEventOption);
},
},
});
slot
node can be included in a component's tyml
to host the tyml
structure provided by the component user.tyml
supports one slot
or multiple slot
s.slot
s in a component's tyml
, use different name
s to distinguish them.slot
property to insert nodes into different slot
s.<!-- Component template -->
<view class="wrapper">
<slot name="before"></slot>
<view>here are the internal details of the component</view>
<slot name="after"></slot>
</view>
<!-- The page template of the referenced component -->
<view>
<component-tag-name>
<!-- This part of the content will be placed in the position of the component <slot name="before"> -->
<view slot="before">here is the content inserted into the component slot name="before"</view>
<!-- This part of the content will be placed in the position of the component <slot name="after"> -->
<view slot="after">here is the content inserted into the component slot name="after"</view>
</component-tag-name>
</view>
tyss
. Except in the following two cases: app.tyss
or the page's tyss
to specify styles directly. These selectors affect the page and all components. Normally this is not recommended practice.iconfont
in a project, since the style file of iconfont
is global, you should turn off style isolation when you need to use iconfont
in custom components.Component({
options: {
styleIsolation: "isolated",
},
});
isolated
: Enable style isolation (default).apply-shared
: The style of the page tyss
will affect the custom component, but the style specified in the custom component tyss
will not affect the page.shared
: The style of the page tyss
will affect the custom component, and the style specified in the custom component tyss
will also affect the page and other settings.Sample code
<!-- component custom-component.tyml -->
<text class="red-text">The color of this text is determined by the style definitions in `app.tyss` and the page `tyss`</text>
/* app.tyss */
.red-text {
color: red;
}
/* component custom-component.js */
Component({
options: {
addGlobalClass: true,
},
});
url
should be an absolute path.ty.navigateTo
API documentation<navigator open-type="navigateTo"/>
ty.redirectTo
API documentation<navigator open-type="redirectTo"/>
ty.navigateBack
API documentation<navigator open-type="navigateBack"/>
ty.switchTab
API documentation<navigator open-type="switchTab"/>
ty.reLaunch
API documentation<navigator open-type="reLaunch"/>
url
, and the parameters can be obtained in the life cycle.Sample code
ty.navigateTo({
url: 'test?id=1',
events: {
// Add a listener for the specified event to get the data sent from the opened page to the current page
acceptDataFromOpenedPage: function(data) {
console.log(data)
},
someEvent: function(data) {
console.log(data)
}
...
},
success: function(res) {
// Send data to the opened page through eventChannel
res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
}
})
//test.js
Page({
onLoad: function (option) {
console.log(option.query);
const eventChannel = this.getOpenerEventChannel();
eventChannel.emit("acceptDataFromOpenedPage", { data: "test" });
eventChannel.emit("someEvent", { data: "test" });
// Listen to the acceptDataFromOpenerPage event, and get the data sent from the previous page to the current page through eventChannel
eventChannel.on("acceptDataFromOpenerPage", function (data) {
console.log(data);
});
},
});
The API provided by the basic library, including basic/application-level events, interface animation related, map, audio and video, canvas, interface and other capabilities. View more.
TTT
capability is a kind of Tuya's ability to give basic capabilities to businesses (developers), to achieve quick access to Tuya ecology, and to achieve interconnection. TTT
related API
is the capability provided for TTT
.TTT
capability is the minimum set of public capabilities that all App
of Tuya series must integrate. These capabilities are provided to Miniapp, RN
, H5
, etc. through plug-ins, so that cross-end business can run in any Tuya series App (IoT
device).TTT
capability on the terminal is the constraint and guarantee for the interconnection and interoperability of software capabilities on the user terminal.Note: To use some API
, such as navigateTo
, showToast
, showModal
, you need to integrate the corresponding Kit
plugin capability.
/assets
.iconfont
, utils
, etc.The multi-language Smart MiniApp has been integrated into the framework, and there is no need to introduce additional packages or methods.
Multilingual key values need to be added in the Mini Program Developer Platform. After selecting the corresponding Mini Program, click Multilingual Management on the sidebar.
<text>{{I18n.t('TYTimer_day2')}}</text>
<text>{{i18n.t('TYTimer_day2')}}</text>
console.log(I18n.t("TYTimer_day2"));
console.log(i18n.t("TYTimer_day2"));
tyss/less
, it is supported to switch themes through the selector theme='dark' | 'light'
.css variables
.:root {
--main-bg-color: rgb(255, 255, 255); /* light background */
--main-text-color: rgb(54, 54, 54); /* dark text */
}
:root[theme="dark"] {
--main-bg-color: rgb(47, 58, 68); /* dark background */
--main-text-color: rgb(197, 197, 197); /* light text */
}
Dialog
, Loading
, Tabs
, Cell
, etc.npm
, the npm
package name is @tuya-miniapp/miniapp-components-plus
usingComponents
configuration field in the json
file of the page, usingComponents must be the full path.tyml
of the corresponding page.// index.json
"usingComponents": {
"mpdialog": "@tuya-miniapp/miniapp-components-plus/dialog/index"
}
<mpdialog title="test" show="{{true}}" bind:buttontap="tapDialogButton" buttons="{{[{text: 'Cancel'}, {text: 'Confirm'}]}}">
<view>test content</view>
</mpdialog>
form
form component, which will input the user input in the component textarea, checkbox-group, radio-group, input, picker, switch, slider Submit. See more form usage.form
in the outermost layer and add bind:submit
and bind:reset
attributes.Property Name | Type | Default Value | Required | Description |
bind:submit | eventhandle | - | No | Carry the data in the form to trigger the submit event, and you can get the value of the form item corresponding to the name in event.detail |
bind:reset | eventhandle | - | no | reset event is fired when the form is reset |
Sample code
<form bind:submit="handleSubmit" bind:reset="handleReset">
<switch name="switch"></switch>
<button form-type="submit" data-info="Submit button" type="primary" class="submit-btn">Submit</button>
<button form-type="reset" data-info="reset button" class="reset-btn">reset</button>
</form>
Page({
data: {
resultData: [
{
name: "switch",
value: "",
},
],
},
handleSubmit(ev) {
const value = ev.detail.value;
console.log(value);
},
handleReset(ev) {
const value = ev.detail.value;
console.log(value);
},
});
More sample code sample code experience effect.
We have provided several templates for developers to learn