赞
踩
列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
仅支持<list-item-group>和<list-item>。
除支持通用属性外,还支持如下属性:
除支持通用样式外,还支持如下样式:
除支持通用事件外,还支持如下事件:
支持通用方法外,还支持如下方法:
表1 currentOffset返回对象属性说明
- <!-- index.hml -->
- <div class="container">
- <list class="todo-wrapper">
- <list-item for="{{todolist}}" class="todo-item">
- <div style="flex-direction: column;align-items: center;justify-content: center;">
- <text class="todo-title">{{$item.title}}</text>
- <text class="todo-title">{{$item.date}}</text>
- </div>
- </list-item>
- </list>
- </div>
- /* index.css */
- .container {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
- height: 100%;
- }
- .todo-wrapper {
- width: 100%;
- height: 300px;
- }
- .todo-item {
- width: 100%;
- height: 120px;
- justify-content:center;
- }
- .todo-title {
- width: 100%;
- height: 80px;
- text-align: center;
- }

- // index.js
- export default {
- data: {
- todolist: [{
- title: '刷题',
- date: '2021-12-31 10:00:00'
- }, {
- title: '看电影',
- date: '2021-12-31 20:00:00'
- }],
- },
- }
<list>的子组件,用来展示列表具体item。由于父元素list组件的align-items默认样式为stretch,该组件宽度默认充满list组件。设置父元素list组件的align-items样式为非stretch来生效自定义宽度。
支持单个子组件。
除支持通用属性外,还支持如下属性:
除支持通用样式外,还支持如下样式:
除支持通用事件外,还支持如下事件:
支持通用方法。
详见List示例。
自定义组件是用户根据业务需求,将已有的组件组合,封装成的新组件,可以在工程中多次调用,从而提高代码的可读性。自定义组件通过element引入到宿主页面,使用方法如下:
- <element name='comp' src='../../common/component/comp.hml'></element>
- <div>
- <comp prop1='xxxx' @child1="bindParentVmMethod"></comp>
- </div>
结合if-else使用自定义组件的示例,showComp1为true时显示自定义组件comp1,否则显示comp2:
- <element name='comp1' src='../../common/component/comp1/comp1.hml'></element>
- <element name='comp2' src='../../common/component/comp2/comp2.hml'></element>
- <div>
- <comp1 if="{{showComp1}}" prop1='xxxx' @child1="bindParentVmMethodOne"></comp1>
- <comp2 else prop1='xxxx' @child1="bindParentVmMethodTwo"></comp2>
- </div>
自定义组件的name属性指自定义组件名称(非必填),组件名称对大小写不敏感,默认使用小写。src属性指自定义组件hml文件路径(必填),若没有设置name属性,则默认使用hml文件名作为组件名。
父组件中绑定自定义子组件的事件使用(on|@)event-name="bindParentVmMethod"语法,子组件中通过this.$emit(‘eventName’, { params: ‘传递参数’ })触发事件并向上传递参数,父组件执行bindParentVmMethod方法并接收子组件传递的参数。
说明:
子组件中使用驼峰命名法命名的事件,在父组件中绑定时需要使用短横线分隔命名形式,例如:@children-event表示绑定子组件的childrenEvent事件。
示例1:无参数传递
子组件comp定义如下:
- <!-- comp.hml -->
- <div class="item">
- <text class="text-style" onclick="childClicked">点击这里查看隐藏文本</text>
- <text class="text-style" if="{{showObj}}">hello world</text>
- </div>
- /* comp.css */
- .item {
- width: 700px;
- flex-direction: column;
- height: 300px;
- align-items: center;
- margin-top: 100px;
- }
- .text-style {
- font-weight: 500;
- font-family: Courier;
- font-size: 40px;
- }
- // comp.js
- export default {
- data: {
- showObj: false,
- },
- childClicked () {
- this.$emit('eventType1');
- this.showObj = !this.showObj;
- },
- }
引入子组件comp的父组件示例如下:
- <!-- xxx.hml -->
- <element name='comp' src='../../common/component/comp.hml'></element>
- <div class="container">
- <comp @event-type1="textClicked"></comp>
- </div>
- /* xxx.css */
- .container {
- background-color: #f8f8ff;
- flex: 1;
- flex-direction: column;
- align-content: center;
- }
- // xxx.js
- export default {
- textClicked () {}
- }
示例2:有参数传递
子组件comp定义如下:
- <!-- comp.hml -->
- <div class="item">
- <text class="text-style" onclick="childClicked">点击这里查看隐藏文本</text>
- <text class="text-style" if="{{ showObj }}">hello world</text>
- </div>
- // comp.js
- export default {
- childClicked () {
- this.$emit('eventType1', { text: '收到子组件参数' });
- this.showObj = !this.showObj;
- },
- }
子组件向上传递参数text,父组件接收时通过e.detail来获取该参数:
- <!-- xxx.hml -->
- <element name='comp' src='../../common/comp/comp.hml'></element>
- <div class="container">
- <text>父组件:{{text}}</text>
- <comp @event-type1="textClicked"></comp>
- </div>
- // xxx.js
- export default {
- data: {
- text: '开始',
- },
- textClicked (e) {
- this.text = e.detail.text;
- },
- }
自定义组件的js文件中可以通过声明data、props、computed等字段完成数据的定义、传递与处理,其中props与computed的具体使用请参考数据传递与处理章节。
表1 自定义组件数据
自定义组件可以通过props声明属性,父组件通过设置属性向子组件传递参数,props支持类型包括:String,Number,Boolean,Array,Object,Function。camelCase (驼峰命名法) 的 prop 名,在外部父组件传递参数时需要使用 kebab-case (短横线分隔命名) 形式,即当属性compProp在父组件引用时需要转换为comp-prop。给自定义组件添加props,通过父组件向下传递参数的示例如下:
- <!-- comp.hml -->
- <div class="item">
- <text class="title-style">{{compProp}}</text>
- </div>
- // comp.js
- export default {
- props: ['compProp'],
- }
- <!-- xxx.hml -->
- <element name='comp' src='../../common/component/comp/comp.hml'></element>
- <div class="container">
- <comp comp-prop="{{title}}"></comp>
- </div>
说明:
自定义属性命名时禁止以on、@、on:、grab: 等保留关键字为开头。
子组件可以通过固定值default设置默认值,当父组件没有设置该属性时,将使用其默认值。此情况下props属性必须为对象形式,不能用数组形式,示例如下:
- <!-- comp.hml -->
- <div class="item">
- <text class="title-style">{{title}}</text>
- </div>
- // comp.js
- export default {
- props: {
- title: {
- default: 'title',
- },
- },
- }
本示例中加入了一个text组件显示标题,标题的内容是一个自定义属性,显示用户设置的标题内容,当用户没有设置时显示默认值title。在引用该组件时添加该属性的设置:
- <!-- xxx.hml -->
- <element name='comp' src='../../common/component/comp/comp.hml'></element>
- <div class="container">
- <comp title="自定义组件"></comp>
- </div>
父子组件之间数据的传递是单向的,只能从父组件传递给子组件,子组件不能直接修改父组件传递下来的值,可以将props传入的值用data接收后作为默认值,再对data的值进行修改。
- // comp.js
- export default {
- props: ['defaultCount'],
- data() {
- return {
- count: this.defaultCount,
- };
- },
- onClick() {
- this.count = this.count + 1;
- },
- }
如果需要观察组件中属性变化,可以通过$watch方法增加属性变化回调。使用方法如下:
- // comp.js
- export default {
- props: ['title'],
- onInit() {
- this.$watch('title', 'onPropertyChange');
- },
- onPropertyChange(newV, oldV) {
- console.info('title 属性变化 ' + newV + ' ' + oldV);
- },
- }
自定义组件中经常需要在读取或设置某个属性时进行预先处理,提高开发效率,此种情况就需要使用computed计算属性。computed字段中可通过设置属性的getter和setter方法在属性读写的时候进行触发,使用方式如下:
- // comp.js
- export default {
- props: ['title'],
- data() {
- return {
- objTitle: this.title,
- time: 'Today',
- };
- },
- computed: {
- message() {
- return this.time + ' ' + this.objTitle;
- },
- notice: {
- get() {
- return this.time;
- },
- set(newValue) {
- this.time = newValue;
- },
- },
- },
- onClick() {
- console.info('get click event ' + this.message);
- this.notice = 'Tomorrow';
- },
- }

这里声明的第一个计算属性message默认只有getter函数,message的值会取决于objTitle的值的变化。getter函数只能读取不能改变参数值,例如data中初始化定义的time,当需要赋值给计算属性的时候可以提供一个setter函数,如示例中的notice。
说明:
从API version 9开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
自定义组件具有inherit-class属性,定义如下:
可以通过设置inherit-calss属性来继承父组件的样式。
父组件的hml文件,其中自定义组件comp通过inherit-class属性来指定继承其父组件的样式,即parent-class1和parent-class2:
- <!-- xxx.hml -->
- <element name='comp' src='../../common/component/comp.hml'></element>
-
- <div class="container">
- <comp inherit-class="parent-class1 parent-class2" ></comp>
- </div>
父组件的css文件:
- /* xxx.css */
- .parent-class1 {
- background-color:red;
- border:2px;
- }
- .parent-class2 {
- background-color:green;
- border:2px;
- }
自定义组件的hml文件,其中parent-class1和parent-class2是从父组件继承的样式:
- <!--comp.hml-->
- <div class="item">
- <text class="parent-class1">继承父组件的样式1</text>
- <text class="parent-class2">继承父组件的样式2</text>
- </div>
说明:
从API Version 7 开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
自定义组件中通过slot标签来承载父组件中定义的内容,使用slot标签可以更加灵活的控制自定义组件的内容元素,使用方式如下:
- <!-- comp.hml -->
- <div class="item">
- <text class="text-style">下面使用父组件定义的内容</text>
- <slot></slot>
- </div>
引用该自定义组件方式如下:
- <!-- xxx.hml -->
- <element name='comp' src='../../common/component/comp.hml'></element>
- <div class="container">
- <comp>
- <text class="text-style">父组件中定义的内容</text>
- </comp>
- </div>
当自定义组件中需要使用多个插槽时,可通过对插槽命名的方式进行区分,当填充插槽内容时,通过声明插槽名称,将内容加到对应的插槽中。
- <!-- comp.hml -->
- <div class="item">
- <text class="text-style">下面使用父组件定义的内容</text>
- <slot name="first"></slot>
- <slot name="second"></slot>
- </div>
引用该自定义组件方式如下:
- <!-- xxx.hml -->
- <element name='comp' src='../../common/component/comp.hml'></element>
- <div class="container">
- <comp>
- <text class="text-style" slot="second">插入第二个插槽中</text>
- <text class="text-style" slot="first">插入第一个插槽中</text>
- </comp>
- </div>
说明:
name 和 slot 属性不支持绑定动态数据。
说明:
从API Version 5 开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
我们为自定义组件提供了一系列生命周期回调方法,便于开发者管理自定义组件的内部逻辑。生命周期主要包括:onInit,onAttached,onDetached,onLayoutReady,onDestroy,onShow和onHide。下面我们依次介绍一下各个生命周期回调的时机。
- <!-- comp.hml -->
- <div class="item">
- <text class="text-style">{{ value }}</text>
- </div>
- //comp.js
- export default {
- data: {
- value: "组件创建"
- },
- onInit() {
- console.log("组件创建")
- },
- onAttached() {
- this.value = "组件挂载",
- console.log("组件挂载")
- },
- onShow() {
- console.log("Page显示")
- },
- onHide() {
- console.log("Page隐藏")
- }
- }

提供在页面中动态添加组件,并为动态添加的组件设置属性与样式的能力。
说明:
从API version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
createElement(tag: string): Element
创建一个组件对象。
参数:
let newImage = dom.createElement('image')
setAttribute(name: string, value: string): void
动态设置组件的属性。
参数:
newImage.setAttribute('src', 'common/testImage.jpg')
addChild(child: Element): void
将动态创建的组件添加到父组件当中。
参数:
newDiv.addChild(newImage)
- <!-- xxx.hml -->
- <div class="container">
- <div id="parentDiv" class="parent"></div>
- <button onclick="appendDiv" class="btn">动态创建div</button>
- <button onclick="appendImage" class="btn">动态创建image到创建的div中</button>
- </div>
- /* xxx.css */
- .container {
- flex-direction: column;
- align-items: center;
- width: 100%;
- }
-
- .parent {
- flex-direction: column;
- }
-
- .btn {
- width: 70%;
- height: 60px;
- margin: 15px;
- }

- // xxx.js
- let newDiv = null
- let newImage = null
-
- export default {
- appendDiv() {
- let parent = this.$element('parentDiv')
- newDiv = dom.createElement('div')
- newDiv.setStyle('width', '150px')
- newDiv.setStyle('height', '150px')
- newDiv.setStyle('backgroundColor', '#AEEEEE')
- newDiv.setStyle('marginTop', '15px')
- parent.addChild(newDiv)
- },
- appendImage() {
- newImage = dom.createElement('image')
- newImage.setAttribute('src', 'common/testImage.jpg')
- newImage.setStyle('width', '120px')
- newImage.setStyle('height', '120px')
- newDiv.addChild(newImage)
- }
- }

表1 当前支持的颜色枚举
ArkTS也提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。
使用if/else进行条件渲染。
说明:
if/else条件语句可以使用状态变量。
使用if/else可以使子组件的渲染依赖条件语句。
必须在容器组件内使用。
某些容器组件限制子组件的类型或数量,将if/else用于这些组件内时,这些限制将同样应用于if/else语句内创建的组件。例如,Grid容器组件的子组件仅支持GridItem组件,在Grid内使用if/else时,则if/else语句内也仅允许使用GridItem组件。
- Column() {
- if (this.count < 0) {
- Text('count is negative').fontSize(14)
- } else if (this.count % 2 === 0) {
- Text('count is even').fontSize(14)
- } else {
- Text('count is odd').fontSize(14)
- }
- }
通过循环渲染(ForEach)从数组中获取数据,并为每个数据项创建相应的组件,可减少代码复杂度。
- ForEach(
- arr: any[],
- itemGenerator: (item: any, index?: number) => void,
- keyGenerator?: (item: any, index?: number) => string
- )
参数:
说明:
ForEach必须在容器组件内使用。
生成的子组件应当是允许包含在ForEach父容器组件中的子组件。
允许子组件生成器函数中包含if/else条件渲染,同时也允许ForEach包含在if/else条件渲染语句中。
itemGenerator函数的调用顺序不一定和数组中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正常工作:
- ForEach(anArray.map((item1, index1) => { return { i: index1 + 1, data: item1 }; }),
- item => Text(`${item.i}. item.data.label`),
- item => item.data.id.toString())
- // xxx.ets
- @Entry
- @Component
- struct MyComponent {
- @State arr: number[] = [10, 20, 30]
-
- build() {
- Column({ space: 5 }) {
- Button('Reverse Array')
- .onClick(() => {
- this.arr.reverse()
- })
-
- ForEach(this.arr, (item: number) => {
- Text(`item value: ${item}`).fontSize(18)
- Divider().strokeWidth(2)
- }, (item: number) => item.toString())
- }
- }
- }

通过数据懒加载(LazyForEach)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
- LazyForEach(
- dataSource: IDataSource,
- itemGenerator: (item: any) => void,
- keyGenerator?: (item: any) => string
- ): void
-
- interface IDataSource {
- totalCount(): number;
- getData(index: number): any;
- registerDataChangeListener(listener: DataChangeListener): void;
- unregisterDataChangeListener(listener: DataChangeListener): void;
- }
-
- interface DataChangeListener {
- onDataReloaded(): void;
- onDataAdd(index: number): void;
- onDataMove(from: number, to: number): void;
- onDataDelete(index: number): void;
- onDataChange(index: number): void;
- }

参数:
- // xxx.ets
- 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.png', '/path/image1.png', '/path/image2.png', '/path/image3.png']
-
- 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(50).height(50)
- Text(item).fontSize(20).margin({ left: 10 })
- }.margin({ left: 10, right: 10 })
- }
- .onClick(() => {
- // 每点击一次列表项,数据增加一项
- this.data.pushData('/path/image' + this.data.totalCount() + '.png')
- })
- }, item => item)
- }
- }
- }

说明:
LazyForEach必须在容器组件内使用,目前仅有List、Grid以及Swiper组件支持数据懒加载(即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有的数据。
LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。
允许LazyForEach包含在if/else条件渲染语句中。
为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,仅当itemGenerator中创建的子组件内使用了状态变量时,才会触发组件刷新。
itemGenerator函数的调用顺序不一定和数据源中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正常工作:
- LazyForEach(dataSource,
- item => Text(`${item.i}. item.data.label`),
- item => item.data.id.toString())
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。