先放一下页面效果:
第一步我们先定义一下数据格式,创建一个数据模型,通过图片,可以看到每一条数据的字段应当包括:头像,姓名,最新消息内容和最新消息的时间,创建一个model文件夹,然后在里面新建一个_Chat.ets文件 这里我使用的是interface来定义,当然也有很多人习惯class,类和接口的区别大概就是,interface里不包括代码,只是定义了一种实现规范 代码如下:
javascript
export interface Info{
name:string
img:Resource
day:string
last:string
}
这里的头像img用的是Resource格式,因为我这里模拟演示的时候,用的是本地media文件夹里的图片,在实际项目中,也可以改成string,以对应网络url地址
第二步是模拟一组测试数据,我们在目录里创建一个data文件夹用来存放测试数据,然后创建一个_Chat.ets用来存放聊天的数据。因为是新的文件,所以在这个页面里,并没有对数据类型的定义,所以要先从刚才model文件那里把这个数据规范import过来,然后通过const创建一个数组,并通过as来确认这个数组里的每一个json数据都是同一个聊天数据的规范 代码如下:
javascript
import {Info} from '../model/_Chat'
export const Chatlist = [
{
name:"同学1",
img:$r("app.media.head1"),
day:"5月5日",
last:"今天上学怎么样?"
},
{
name:"同学2",
img:$r("app.media.head2"),
day:"5月5日",
last:"今天上学怎么样?"
}
] as Info[]
由于整体页面结构采用一个@Entry修改的页面+Tab来包裹的4个子组件的形式,因此继续在目录里创建一个views文件夹,用来存放表示一级页面的子组件,然后创建一个Home.ets作为首页 然后要通过import,来引入模拟数据和这个聊天的数据类型,代码如下
javascript
import {Chatlist} from '../data/_Chat'
import * as chat from '../model/_Chat'
然后创建一个@State描述的数据,作为数据列表
less
@State list:chat.Info[] = Chatlist;
最上面的首页标题,使用Row+Text来创建
scss
Row() {
Text('首页')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
}
.width('100%')
.height(56)
.justifyContent(FlexAlign.Center)
.backgroundColor('#f8f9fa')
.border({
width: { bottom: 1 },
color: '#e9ecef'
})
这里使用了justifyContent属性来进行居中,如果不加这个属性的话,那么100%宽度的row会让文字靠左显示。接下来是显示聊天数据的列表,这里采用ForEach列表渲染来实现。组件上的话,要考虑到多组数据的情况下是要上下滚动的,所以采用List+ListItem的组合比较合适,虽然说Scroll也能滚动,但是实际上我觉得套个List更加方便,我之前api6那会儿,写js开发鸿蒙的时候,也是用的这个方法。 然后页面中,最新的消息是给了一行的显示位置,然而实际上,很多情况下最新消息的字数可能会超过一行的限制,所以对于这个Text组件,要加上maxLines和textOverflow这两个属性,这两个属性表示最大行数和超出最大行数的话,内容如何显示,单独设置其中某一个是没有意义的。 这里的头像使用了圆形设计方案,当然这个头像的图片不可能直接上传成圆形的,这个是通过对于图片的borderRadius属性进行设置实现的,要把图片的宽度和高度设置成一样的数值,然后把borderRadius这个属性设置为高宽的一半 对于日期的设置上,可以看到日期是在每个组件的右上方的,但这不是通过position来固定的,而是和姓名在同一行里,然后通过设置这个row的justifyContent属性实现的,那么,这就要求,row的父组件的宽度,要正好是除了图片外的全部宽度,所以row的父组件即Column要加上layoutWeight属性,设置为1 这部分的代码如下:
scss
List() {
ForEach(this.list, (item: chat.Info, index: number) => {
ListItem() {
Column() {
Row() {
// 头像
Image(item.img)
.width(50)
.height(50)
.borderRadius(25)
.margin({ right: 12 })
// 中间内容区域
Column() {
Row() {
// 姓名
Text(item.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#1a1a1a')
// 日期
Text(item.day)
.fontSize(12)
.fontColor('#8e8e93')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.margin({ bottom: 4 })
// 最新消息
Text(item.last)
.fontSize(14)
.fontColor('#8e8e93')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.width('100%')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
.alignItems(VerticalAlign.Center)
// 分割线
if (index < this.list.length - 1) {
Divider()
.strokeWidth(0.5)
.color('#e5e5e7')
.margin({ left: 78 })
}
}
}
.backgroundColor('#ffffff')
.onClick(() => {
// 跳转到聊天页面,传递姓名参数
router.pushUrl({
url: 'pages/Chat',
params: {
name: item.name
}
})
})
})
}
.layoutWeight(1)
.backgroundColor('#ffffff')
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.Spring)