页面与组件

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>

逻辑控制块

可以使用 实现更为灵活的循环/条件渲染; 注意 目前只支持 for 和 if/elif/else 属性,如果没有指定任何属性, 则在构建时被当作"透明"节点对待,其子节点被添加到 的父节点上。

<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 监听应用销毁 当应用销毁时触发

results matching ""

    No results matching ""