页面与组件
template 模板
类似HTML的标签语言,结合基础组件、自定义组件、事件,构建出页面的结构。
模板中只能有1个根节点,如:div;请不要在 <template>
下存在多个根节点,也不要使用 block
作为根节点。
数据绑定
<template>
<text>{\{message}}</text>
</template>
<script>
module.exports = {
data: {
message: 'Hello World!'
}
}
</script>
事件绑定
<template>
<div>
<!-- 正常格式 -->
<div onclick="press"></div>
<!-- 缩写 -->
<div @click="press"></div>
</div>
</template>
<script>
module.exports = {
press: function(e) {
this.title = 'Hello'
}
}
</script>
事件回调支持的写法(其中花括号可以省略):
- "fn":fn为事件回调函数名(在
<script>
中有对应的函数实现)。 - "fn(a,b)":函数参数例如a,b可以是常量,或者是在
<script>
的data中定义的变量(前面不用写this.)。 - "a+b":表达式,其中a,b数据类型与上面相同。
回调函数被调用时,会在参数列表末尾自动添加一个 ev 参数,通过 evt 参数访问回调事件相关上下文数据(数据内容具体参看组件回调事件说明),例如点击事件的点击位置 x,y。
列表渲染
<template>
<div class="list-container">
<text for="{\{list}}" tid="id">
<text>{\{$idx}}<text>
<text>{\{$item.id}}<text>
</text>
</div>
</template>
<script>
module.exports = {
data: {
list: [{
id: 1
}, {
id: 2
}]
}
}
</script>
标签中的 tid 用于指定作为定义数组元素唯一 ID 的字段名,如果没有指定,则默认采用数组索引($idx)作为唯一 ID;tid 的作用是为了元素节点重用,优化 for 循环的重绘效率。
例如 tid="id"
表示 $item.id
作为数组元素的唯一 ID。
for 循环支持的写法(其中花括号可以省略):
- for="list":list 为数组对象,默认元素变量为 $item。
- for="value in list":value 为自定义的元素变量,默认元素索引为 $idx。
- for="(index,value) in list":index 为元素索引,value 为元素变量。
- tid 指定的数据属性必须存在,否则可能引起运行异常。
- tid 指定的数据属性要保证唯一,如果发生重复,可能会造成性能问题。
条件渲染
分为2种:if/elif/else 和 show。它们的区别在于:
- if 为 false 时,组件会从 VDOM 中移除,而 show 仅仅是渲染时不可见,组件依然存在于 VDOM 中。
- if/elif/else节点必须是相邻的兄弟节点,否则无法通过编译。
<template>
<div>
<text if="{\{show}}"> Hello-1 </text>
<text elif="{\{display}}"> Hello-2 </text>
<text else> Hello-3 </text>
</div>
</template>
<script>
module.exports = {
data: {
show: false
}
}
</script>
show 等同于 display=none
,目前只用于系统原生组件,对自定义组件不生效。自定义组件可以通过 props 传入参数,在自己内部使用 show 来控制是否可见。
<template>
<text show="{\{visible}}"> Hello </text>
</template>
<script>
module.exports = {
data: {
visible: false
}
}
</script>
逻辑控制块
可以使用
<template>
<list>
<block for="cities">
<list-item type="city">
<text>{\{$item.name}}</text>
</list-item>
<block for="$item.spots" if="false">
<list-item type="spot">
<text>{\{$item.address}}</text>
</list-item>
</block>
</block>
</list>
</template>
<script>
module.exports = {
data: {
cities: [{
name: "beijing",
spots: [{
name: "XXX",
address: "XXX"
}, {
name: "XXX",
address: "XXX"
}]
},
{
name: "shanghai",
spots: [{
name: "XXX",
address: "XXX"
}, {
name: "XXX",
address: "XXX"
}]
}
]
}
}
</script>
引入自定义组件
<import name='comp' src='./comp'></import>
<template>
<div>
<comp prop1='xxxx' onevent1="bindParentVmMethod1" @event-type1="bindParentVmMethod1"></comp>
</div>
</template>
如果没有设置 name 属性,则默认采用 src 的文件名作为组件名
src 属性指定组件 nml 文件位置,可以省略 .nml 后缀。
- 组件名不区分大小写,默认统一采用小写。
- 通过 (on|@)event1 语法绑定自定义子组件的 event1 事件,触发事件
childVm.$emit('event1', { params: '传递参数' })
时执行父组件的方法:bindParentVmMethod1。 - 标签上声明事件名称采用-连接,不要使用驼峰式,来做响应与方法的关联,即:使用 event-type1 表示绑定 eventType1 事件。
插入自定义组件
组件中通过标签来定义子组件插入位置,例如:
组件 com-a 的模板定义为:
<template>
<div>
<text>header</text>
<slot></slot>
<text>footer</text>
<div>
</template>
在页面使用组件 comA,定义如下:
<import name="comp-a" src="./comp-a"></import>
<template>
<com-a>
<text>body</text>
</com-a>
</template>
则在页面渲染时,组件 comA 变为:
<div>
<text>header</text>
<text>body</text>
<text>footer</text>
</div>
Style样式
用于描述 template 模板的组件样式,决定组件应该如何显示。
样式布局采用CSS Flexbox(弹性盒)样式,针对部分原生组件,对 CSS 进行了少量的扩充以及修改。
为了解决屏幕适配问题,所有与大小相关的样式(例如width、font-size)均以基准宽度(默认750px)为基础,根据实际屏幕宽度进行缩放,例如width:100px,在1500px宽度屏幕上,width实际上为200px。
文件导入
支持2种导入外部文件的方式:
<!-- 导入外部文件, 代替style内部样式 -->
<style src="./style.css"></style>
<!-- 合并外部文件 -->
<style>
@import './style.css';
a{
}
</style>
模板内部样式
支持使用style、class属性来控制组件的样式。
<!-- 内联inline -->
<div style="color:red; margin: 10px;" />
<!-- class声明 -->
<div class="normal append" />*
选择器
支持的选择器如下表所示。
选择器 | 样例 | 样例描述 |
---|---|---|
.class | .intro | 选择所有拥有 class="intro" 的组件。 |
#id | #firstname | 选择拥有 id="firstname" 的组件。 |
tag | div | 选择所有 div 组件。 |
, | .a, .b | 选择所有class=".a" 以及class=".b"的组件。 |
<style>
// 单个选择器
text {
}
.class-abc {
}
#idAbc {
}
// 同一样式适应多个选择器
.font-text,.font-comma {
}
</style>
选择器声明的变化可能会导致元素重新绘制。为了减少选择器变化引起的DOM更新数量,当前只支持:CSS声明的多个选择器中最后一个规则的变更对DOM的更新。
<template>
<div class="{\{docBody}}">
<text class="{\{rowDesc}}" value="描述内容"></text>
</div>
</template>
<style>
.row-desc1 {
color: #ff0000;
}
.row-desc2 {
color: #0000ff;
}
.row-desc1 {
color: #00ff00;
}
</style>
<script>
export default {
data: {
rowDesc: "row-desc1",
docBody: "doc-body"
}
}
</script>
以上的代码示例,当我们把 rowDesc 变量从 row-desc1 变为 row-desc2 时是通知 Native 更新节点样式,但是如果把 docBody 变量从 doc-body 变为 doc-body2,是不会通知 DOM 更新的。
因为 doc-body 不是最后一个选择器,非末尾的选择器变更有可能影响很多 DOM 元素,从而影响到渲染性能。
选择器优先级
当前样式的选择器的优先级计算保持与浏览器一致,是浏览器 CSS 渲染的一个子集(仅支持:inline,id,class,tag,后代,直接后代)
选择器优先级规则如下(假设多条 CSS 声明匹配到同一个元素 div),应用在该元素上的 CSS 声明总体优先级是:inline > #id > .class > tag
,这四大类匹配到该元素的多个 CSS 声明。
样式预编译
目前支持 less,sass 的预编译。
<!--导入外部文件, 代替style内部样式-->
<style lang="less" src="./lessFile.less">
</style>
<!--合并外部文件-->
<style lang="less">
@import './lessFile.less';
.page-less {
#testTag {
.less-font-text,
.less-font-comma {
font-size: 60px;
}
}
}
</style>
伪类
任何组件中,如果某个属性是boolean类型且默认值为false时,均可通过该属性名字来声明伪类,当属性变为true时伪类生效,例如所有组件的disabled属性、input组件的checked属性等。
另外部分组件会有其他形式的伪类支持,比如input组件可以通过主动调用focus方法,或者用户操作获得焦点,使得focus伪类生效,详情请参考各组件内部说明。
伪类写法举例:
<template>
<input type="button" class="btn" disabled="{\{btndisabled}}">Click</input>
</template>
<style>
.btn {
width: 360px;
height: 180px;
background-color: red;
}
.btn:disabled {
background-color: green;
}
</style>
当组件的disabled属性变为true时,disabled伪类的样式生效,叠加到原有样式上,例子中background-color会从红色变成绿色。
script脚本
用来定义页面数据和实现生命周期接口。
语法
支持ES6语法
代码引用
NJS 代码引用推荐使用 import
来导入,例如:
import utils from '../Common/utils.njs'
对象
自定义数据
属性 | 类型 | 描述 |
---|---|---|
data | Object/Function | 页面的数据模型,能够转换为JSON对象;属性名不能以$或_开头,不要使用for, if, show, tid等保留字。如果是函数,返回结果必须是对象,在页面初始时回执行函数获取结果作为data的值。 |
props | Array | 用于定义组件的公开属性列表(外部可见),可以通过 <tag xxxx='value'> 方式传递给到组件内部;属性名必须全部小写, 不能以$或_开头,不要使用for, if, show, tid等保留字。目前公开属性的数据类型不支持function。 |
公共对象
属性 | 类型 | 描述 |
---|---|---|
$app | Object | 应用对象。 |
$page | Object | 页面对象。 |
$valid | Boolean | 页面对象是否有效。 |
$visible | Boolean | 页面是否处于用户可见状态。 |
应用对象
可通过 $app
访问。
属性 | 类型 | 描述 |
---|---|---|
$def | Object | 使用this.$app.$def获取在app.ux中暴露的对象。 |
$data | Object | 使用this.$app.$data获取在manifest.json的config.data中声明的全局数据。 |
页面对象
可通过 $page
访问。
属性 | 类型 | 描述 |
---|---|---|
action | String | 获取打开当前页面的action。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined。参见"manifest文件"。 |
uri | String | 获取打开当前页面的uri。仅在当前页面是通过filter匹配的方式打开时有效,否则为undefined。参见"manifest文件"。 |
方法
数据方法
属性 | 类型 | 参数 | 描述 |
---|---|---|---|
$set | Function | key: String value: Any | 添加数据属性,必须在 onInit 函数中使用,否则 <template> 中数据绑定无法生效用法 this.$set('key', alue) this.$vm('id').$set('key',value) |
$delete | Function | key: String | 删除数据属性,如果在 onInit 函数中使用,会导致 <template> 中相应的数据绑定无法生效用法 this.$delete('key') this.$vm('id').$delete('key') |
公共方法
属性 | 类型 | 参数 | 描述 |
---|---|---|---|
$element | Function | id: String 组件id | 获取指定id的组件dom对象,如果没有指定id,则返回根组件dom对象用法 <template> <div id='xxx'></div></template> 。this.$element('xxx') 获取id为xxx的div组件实例对象。this.$element() 获取根组件实例对象。 |
$rootElement | Function | 无 | 获取根组件dom对象用法 this.$rootElement() ,获取根组件实例对象,等同于 this.$element() |
$vm | Function | id: String 组件id | 获取指定 id 的自定义组件的 ViewModel 用法 this.$vm('xxx') ,获取 id 为xxx的 div 组件 ViewModel。 |
$forceUpdate | Function | 无 | 强制页面刷新 |
事件方法
属性 | 类型 | 参数 | 描述 |
---|---|---|---|
$on | Function | type: String 事件名,handler: Function 事件句柄函数 | 添加事件处理句柄用法 this.$on('xxxx', this.fn) ,fn 是在 <script> 中定义的函数。 |
$off | Function | type: String 事件名,handler: Function 事件句柄函数 | 删除事件处理句柄用法 this.$off('xxxx', this.fn) ,this.$off('xxx') 删除指定事件的所有处理句柄。 |
$dispatch | Function | type: String 事件名 | 向上层组件发送事件通知用法 this.$dispatch('xxx') 正常情况下,会一直向上传递事件(冒泡),如果要停止冒泡,在事件句柄函数中调用 evt.stop() 即可。 |
$broadcast | Function | type: String 事件名 | 向子组件发送事件通知用法 this.$broadcast('xxx') 正常情况下,会一直向下传递事件,如果要停止传递,在事件句柄函数中调用 evt.stop() 即可。 |
$emit | Function | type: String 事件名,data: Object 事件参数 | 触发事件,对应的句柄函数被调用用法 this.$emit('xxx') ,this.$emit('xxx', {a:1}) 传递的事件参数可在事件回调函数中,通过 evt.detail 来访问,例如 evt.detail.a 。 |
$emitElement | Function | type: String 事件名,data: Object 事件参数,id: String 组件id (默认为-1 代表根元素) | 触发组件事件, 对应的句柄函数被调用用法 this.$emitElement('xxx', null, 'id') , this.$emitElement('xxx', {a:1}) 传递的事件参数可在事件回调函数中,通过 evt.detail 来访问,例如 evt.detail.a 。 |
$watch | Function | data: String 属性名, 支持'a.b.c'格式,不支持数组索引,handler: String 事件句柄函数名, 函数的第一个参数为新的属性值,第二个参数为旧的属性值 | 动态添加属性/事件绑定,属性必须在data中定义,handler函数必须在 <script> 定义;当属性值发生变化时事件才被触发用法 this.$watch('a','handler') |
页面方法
可通过 $page 访问。
属性 | 类型 | 参数 | 描述 |
---|---|---|---|
setTitleBar | Function | text: String 标题栏文字,textColor: String 文字颜色,backgroundColor: String 背景颜色,backgroundOpacity: Number 透明度,menu: Boolean 是否显示菜单按钮 | 设置当前页面的标题栏用法 this.$page.setTitleBar({text:'Hello', textColor:'#FF0000', backgroundColor:'#FFFFFF',backgroundOpacity :0.5,menu: false}) |
生命周期接口
页面生命周期
属性 | 类型 | 参数 | 返回值 | 描述 | 触发时机 |
---|---|---|---|---|---|
onInit | Function | 无 | 无 | 监听页面初始化 | 当页面完成初始化时调用,只触发一次。 |
onReady | Function | 无 | 无 | 监听页面创建完成 | 当页面完成创建可以显示时触发,只触发一次。 |
onShow | Function | 无 | 无 | 监听页面显示 | 当进入页面时触发 |
onHide | Function | 无 | 无 | 监听页面隐藏 | 当页面跳转离开时触发 |
onDestroy | Function | 无 | 无 | 监听页面退出 | 当页面跳转离开(不进入导航栈)时触发。 |
onBackPress | Function | 无 | Boolean | 监听返回按钮动作 | 当用户点击返回按钮时触发。返回true表示页面自己处理返回逻辑,返回false表示使用默认的返回逻辑,不返回值会作为false处理。 |
onMenuPress | Function | 无 | 无 | 监听菜单按钮动作 | 当用户点击 ActionBar 右边菜单按钮时触发 |
onOrientationChange | Function | 无 | 无 | 监听设备屏幕旋转 | 用户垂直或水平旋转移动设备时被触发,回调函数传入对象 ScreenOrientation 来描述当前屏幕转向信息。 |
ScreenOrientation.type
描述当前转向类型
- portraitprimary
- portraitsecondary
- landscapeprimary
- landscapesecondary
ScreenOrientation.angle
描述当前转向角度
页面的生命周期接口的调用顺序:
- 打开页面A:onInit() -> onReady() -> onShow()
- 在页面A打开页面B:onHide()
- 从页面B返回页面A:onShow()
- A页面返回:onBackPress() -> onHide() -> onDestroy()
应用生命周期
属性 | 类型 | 参数 | 返回值 | 描述 | 触发时机 |
---|---|---|---|---|---|
onCreate | Function | 无 | 无 | 监听应用创建 | 当应用创建时调用 |
onDestroy | Function | 无 | 无 | 监听应用销毁 | 当应用销毁时触发 |