@Entry
@Component
struct ObjectLinkZhiHu {
@State commentList: ReplyItemClass[] = [
new ReplyClass({
id: 1,
avatar: 'https://picx.zhimg.com/027729d02bdf060e24973c3726fea9da_l.jpg?source=06d4cd63',
author: '偏执狂-妄想家',
content: '更何况还分到一个摩洛哥[惊喜]',
time: '11-30',
area: '海南',
likeNum: 34
}),
new ReplyClass({
id: 2,
avatar: 'https://pic1.zhimg.com/v2-5a3f5190369ae59c12bee33abfe0c5cc_xl.jpg?source=32738c0c',
author: 'William',
content: '当年希腊可是把1:0发挥到极致了',
time: '11-29',
area: '北京',
likeNum: 58
}),
new ReplyClass({
id: 3,
avatar: 'https://picx.zhimg.com/v2-e6f4605c16e4378572a96dad7eaaf2b0_l.jpg?source=06d4cd63',
author: 'Andy Garcia',
content: '欧洲杯其实16队球队打正赛已经差不多,24队打正赛意味着正赛阶段在小组赛一样有弱队。',
time: '11-28',
area: '上海',
likeNum: 10
}),
new ReplyClass({
id: 4,
avatar: 'https://picx.zhimg.com/v2-53e7cf84228e26f419d924c2bf8d5d70_l.jpg?source=06d4cd63',
author: '正宗好鱼头',
content: '确实眼红啊,亚洲就没这种球队,让中国队刷',
time: '11-27',
area: '香港',
likeNum: 139
}),
new ReplyClass({
id: 5,
avatar: 'https://pic1.zhimg.com/v2-eeddfaae049df2a407ff37540894c8ce_l.jpg?source=06d4cd63',
author: '柱子哥',
content: '我是支持扩大的,亚洲杯欧洲杯扩到32队,世界杯扩到64队才是好的,世界上有超过200支队伍,欧洲区55支队伍,亚洲区47支队伍,即使如此也就六成出现率',
time: '11-27',
area: '旧金山',
likeNum: 29
}),
new ReplyClass({
id: 6,
avatar: 'https://picx.zhimg.com/v2-fab3da929232ae911e92bf8137d11f3a_l.jpg?source=06d4cd63',
author: '飞轩逸',
content: '禁止欧洲杯扩军之前,应该先禁止世界杯扩军,或者至少把亚洲名额一半给欧洲。',
time: '11-26',
area: '里约',
likeNum: 100
})
]
changeLike(obj:ReplyItemClass) {
if (obj.likeFlag) {
obj.likeFlag = false
obj.likeNum--
} else {
obj.likeFlag = true
obj.likeNum++
}
// State数据只能监听到第一层的变化
// 怎么让数据具备驱动型
const index = this.commentList.findIndex(item => item.id === obj.id)
// this.commentList[index] = {...obj} // 禁用延展运算符,next不支持
this.commentList.splice(index,1,obj) // splice表示从哪个位置删除,删除几个,使用obj来替换
}
addComment(item:ReplyItemClass) {
this.commentList.unshift(item) // 在数组的头部添加元素
}
build() {
Stack({alignContent:Alignment.Bottom}) {
Scroll() { //只能放置一个子组件
Column() {
NavBar()
CommentItem({
item: {
id: 1,
avatar: $r('app.media.icon'),
author: '周杰伦',
content: '意大利拌面应该使用42号钢筋混凝土再加上量子力学缠绕最后通过不畏浮云遮望眼',
time: '11-30',
area: '海南',
likeNum: 100
}
})
// 分割线
Divider()
.strokeWidth(6)
.color("#f4f4f4")
Row() {
Text("回复7")
.width('100%')
.fontWeight(FontWeight.Bold)
}.height(40).padding({left:20})
ForEach(this.commentList,(item:ReplyClass) => {
// CommentItem({item:item}) // 在实例化子组件时,给子组件的属性赋值
// CommentItem({item}) // 在es6中,当属性和值相同时可以简写
// CommentItem({item,changLike:this.changeLike.bind(this)}) // 写法错误,
CommentItem({item:item})
},(item: ReplyItemClass) => JSON.stringify({ id: item.id, flag: item.likeFlag, num: item.likeNum }))
}
}
.padding({
bottom:60
})
ReplyInput({add: (item:ReplyItemClass) => {
this.addComment(item)
}})
}
}
}
// 回复评论组件
@Component
struct ReplyInput {
@State commentStr:string = ""
// 在回复组件中声明了一个变量add,它的类型是函数,给了一个初始值是函数
add: (item:ReplyItemClass) => void = () => {}
build() {
Row() {
TextInput({placeholder:'回复~', text:this.commentStr})
.layoutWeight(1) // 占据除'发布'按钮的所有空间
.backgroundColor('#4f5f6')
.onChange((value) => {
this.commentStr = value
})
Text('发布')
.fontColor('#6ecff6')
.margin({
left:10
})
.onClick(() => {
// AlertDialog.show({message:this.commentStr}) // alert弹窗
// 告诉父组件,我拿到值,你给我个方法我来调一下
// 要传入一个新的评论对象
if (this.commentStr !== "") {
let obj:ReplyItemClass = {
id: Date.now(),
content: this.commentStr,
avatar: $r("app.media.icon"),
likeNum:0,
likeFlag:false,
author:"高大的绿地",
time:`${ new Date().getMonth() + 1}-${ new Date().getDate()}`,
area:'上海'
}
this.add(obj)
this.commentStr = ""
}
})
}
.border({
color:'#f4f5f6',
width: {
top:1
}
})
.height(50)
.backgroundColor(Color.White)
.width('100%')
.padding({
left:10,
right:10
})
}
}
@Component
struct NavBar {
build() {
Row() {
Row() {
Image($r("app.media.ic_public_arrow_left"))
.fillColor("#848484")
.width(16)
.height(16)
}
.justifyContent(FlexAlign.Center)
.width(24)
.aspectRatio(1)
.backgroundColor("#f5f5f5")
.borderRadius(12)
.margin({
left:15
})
Text("评论回复")
.layoutWeight(1)
.textAlign(TextAlign.Center)
.fontSize(18)
.padding({
right:39
})
}
.height(40)
.border({
color:"#f4f4f4",
width:{
bottom:0.5
}
})
}
}
@Component
struct CommentItem {
// 父组件给子组件传参数,在子组件中定义一个属性即可,非响应式数据
// item:ReplyItem = {id:0,avatar:"",....}
// 默认public属性
@ObjectLink
item:ReplyClass //Partial是个泛型工具,把类型中的所有属性都变成可选;等价于在类中的属性 id ?: number = 0
build() {
Row() {
Image(this.item.avatar)
.width(32)
.aspectRatio(1)
.borderRadius(16)
Column({space:10}) {
Text(this.item.author)
.fontWeight(FontWeight.Bold)
Text(this.item.content)
.fontSize(16)
.fontColor("#565656")
.lineHeight(20)
Row() {
Text(`${this.item.time} .ip属地${this.item.area}`).fontSize(12).fontColor("#c3c4c5")
Row() {
Image($r("app.media.favorite_block"))
.width(12)
.aspectRatio(1)
.fillColor(this.item.likeFlag ? 'red' : '#c3c4c5')
.margin({
right:5
})
Text(this.item.likeNum?.toString()) // ?表示可选,如果取不到,后面的不执行
.fontSize(12)
.fontColor('#c3c4c5')
}
.onClick(() => {
// 点赞
// this.item属性都是可选的
if (this.item.likeFlag) {
this.item.likeFlag = false
this.item.likeNum--
} else {
this.item.likeFlag = true
this.item.likeNum++
}
})
}.justifyContent(FlexAlign.SpaceBetween)
.width("100%")
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
.margin({left:10})
}.padding(15)
.alignItems(VerticalAlign.Top)
}
}
export class ReplyItemClass {
// next版本在定义属性时需要初始值
id: number = 0
avatar: string | Resource = "" // 联合类型,可以是类型中的一个
author: string = ""
content: string = ""
time: string = ""
area: string = ""
likeNum: number = 0
likeFlag?: boolean = false
}
// extends代表继承类,实现父类,也可以调用this.parent()实现父类初始化。而且会覆盖父类定义的变量或者函数,
// implements实现接口,子类不可以覆盖父类的方法或者变量,相同的变量或者函数,会被父类取代掉
@Observed
export class ReplyClass extends ReplyItemClass{
constructor(obj:ReplyItemClass) {
super() // 调用父类的构造函数
this.id = obj.id
this.avatar = obj.avatar
this.content = obj.content
this.time = obj.time
this.area = obj.area
this.likeNum = obj.likeNum
this.likeFlag = obj.likeFlag
}
}
注意点:
- ObjectLink只能修饰被Observed修饰的class类型
- Observed修饰的class的数据如果是复杂数据类型,需要采用赋值的方式才可以具备响应式特性-因为它监听的是该属性的set和get
- 如果出现复杂类型嵌套,只需要Observed我们需要的class即可,至于用于类型的class可以用type或者interface
网友评论