首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发应用实例

鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发应用实例

作者头像
varin
发布2025-09-28 12:32:53
发布2025-09-28 12:32:53
13900
代码可运行
举报
文章被收录于专栏:/root/root
运行总次数:0
代码可运行

一、ArkTS语言-Class类

Class类
  • 简介:类是用于创建对象模板,同时类声明也会引入一个新类型,可定义其示例属性、方法和构造函数。
  • 扩展:
代码语言:javascript
代码运行次数:0
运行
复制
// ?. 表示可选连操作符,
基本语法
代码语言:javascript
代码运行次数:0
运行
复制
class 类名{
  // 属性
  // 构造方法
  // 方法
}
// 实例化对象
const class1:类名= new 类名()
对象-属性
代码语言:javascript
代码运行次数:0
运行
复制
class   Person {
   name:string=""
   age :number=0
    like?:string
}
const user1 :Person = new Person();
console.log(JSON.stringify(user1))
// 可选链操作符,存在打印,不存在也不会报错。
console.log("like>>>",user1?.like)
image.png
image.png
对象-构造方法
代码语言:javascript
代码运行次数:0
运行
复制
class   Person {
   name:string
   age :number
    like?:string

  constructor(name:string,age:number,like?:string) {
    this.name = name
    this.age =age
    this.like= like
  }
}
const user1 :Person = new Person("张三",33);
console.log(JSON.stringify(user1))
const user2 :Person = new Person("李四",12,"运动");
console.log(JSON.stringify(user2))
image.png
image.png
对象-方法
代码语言:javascript
代码运行次数:0
运行
复制
class   Person {
   name:string
   age :number
    like?:string

  constructor(name:string,age:number,like?:string) {
    this.name = name
    this.age =age
    this.like= like
  }
  // 方法
  play(){
    console.log(`${this.name}喜欢${this.like}`)
  }
}
const user1 :Person = new Person("张三",33);
console.log(JSON.stringify(user1))
const user2 :Person = new Person("李四",12,"运动");
user2.play()
console.log(JSON.stringify(user2))
image.png
image.png
对象-静态属性和静态方法
代码语言:javascript
代码运行次数:0
运行
复制
// 类直接调用,不用new

class Tools{
  static version:number=1.1
  static show (){
    console.log("此类的作用是提供工具")
  }
}
console.log(Tools.version.toString())
Tools.show()
image.png
image.png
  • 对象-继承extends和super关键字
代码语言:javascript
代码运行次数:0
运行
复制
import { componentSnapshot } from '@kit.ArkUI';
class Animal{
  name:string
  voice :string

  constructor(name:string,voice:string) {
    this.name = name
    this.voice = voice
  }
  animalVOice(){
    console.log("动物声音:",this.voice)
  }
}
class Cat extends  Animal{
  color:string;
  constructor(name:string,voice:string,color:string) {
  super(name,voice)
    this.color=color
  }
}
class Dog extends  Animal{
}
const  cat1:Cat = new Cat("猫","喵","white")
console.log(`${cat1.name}的颜色是:${cat1.color}`)
cat1.animalVOice()
const  dog1:Dog = new Dog("狗","汪")
dog1.animalVOice()
image.png
image.png
对象-判断类型:instanceof
代码语言:javascript
代码运行次数:0
运行
复制
class Person{
}
class  Student extends  Person{
}
let stu1:Person = new Student()
console.log("result=>>>>>",stu1 instanceof Person)
console.log("result=>>>>>",stu1 instanceof Student)
let arr1:number[]=[]
console.log("result=>>>>>",arr1 instanceof  Array?arr1.length:null)
image.png
image.png
对象-访问修饰符
代码语言:javascript
代码运行次数:0
运行
复制
/*
readonly:只读,(只能读取不能修改) 例:Math.PI
private :私有的(只能在自己的类中使用)
protected :在自己和子类中可以访问
public (默认)
*/
剩余参数

说明:不定数量的参数

代码语言:javascript
代码运行次数:0
运行
复制
// 求和
function sum (num1:number,num2:number,...nums:number[]):number{
  let result = num1+num2
  for (let numsElement of nums) {
    result+=numsElement
  }
  return result
}
console.log("result>>>>",sum(1,2,3,4,5,3,56))
console.log("result>>>>",sum(1,2))
image.png
image.png
展开运算符
代码语言:javascript
代码运行次数:0
运行
复制
// 只能用在数组上
// 功能:合并数组

function sum (num1:number,num2:number,nums?:number[]):number{
  let result = num1+num2
  if(nums instanceof Array){
    for (let numsElement of nums) {
      result+=numsElement
    }
  }
  return result
}
let arr1:number[]=[123,33]
let arr2:number[]=[23,32,32]
console.log("result>>>>",sum(1,2,[...arr1,...arr2]))
console.log("result>>>>",sum(1,2))
image.png
image.png
接口继承

关键字:extends

代码语言:javascript
代码运行次数:0
运行
复制
interface  IAnimal{
  name:string,

}
interface ICat extends IAnimal{
  color:string
}
let cat1:ICat = {
  name:'cat',
  color:'red'
}
console.log(JSON.stringify(cat1))
image.png
image.png
接口实现

关键字:implements

代码语言:javascript
代码运行次数:0
运行
复制
interface  IAnimal{
  // 限制,实现该该接口,必须有该 接口中的属性和方法
  show():void
}
class  Animal  implements  IAnimal{
  name:string

  constructor(name:string) {
    this.name =name
  }
  show(){
    console.log("show")
  }
}
class  Cat extends Animal{
  show(){
    console.log("cat")
  }
}
let cat1 :Animal = new Cat("cat")
cat1.show()
image.png
image.png
泛型
泛型函数
代码语言:javascript
代码运行次数:0
运行
复制
/*
语法:
function 函数名 <Type>(temp:Type):Type{
  return temp
}
*/ 
function isType<Type>(temp:Type):void{
  console.log(typeof  temp)
}
isType("1")
isType(1)
isType(false)
image.png
image.png
泛型约束
代码语言:javascript
代码运行次数:0
运行
复制
// 给传递的类型参数,添加限制
interface  ISize{
  size():number;
}
function fn <T extends  ISize >(item :T){
  console.log("result>>",item.size())
}
class ISizeClass implements  ISize{
  size(): number {
    return 1
  }
}
let iSizeClass:ISize = new ISizeClass();
fn(iSizeClass)
image.png
image.png
多个泛型约束
代码语言:javascript
代码运行次数:0
运行
复制
interface  ISize{
  size():number;
}
function fn <T extends  ISize,T2 >(item :T,num:T2){
  console.log("result>>",item.size())
  console.log("result>>>",num)
}
class ISizeClass implements  ISize{
  size(): number {
    return 1
  }
}
let iSizeClass:ISize = new ISizeClass();
fn<ISize,number>(iSizeClass,1)
image.png
image.png
泛型接口
代码语言:javascript
代码运行次数:0
运行
复制
interface  IUser<T>{
    id:()=>T
}

let user1:IUser<number>= {
  id(){
    return 1;
  }
}
console.log("result>>>>",user1.id())
image.png
image.png
泛型类
代码语言:javascript
代码运行次数:0
运行
复制
class Person<T>{
  id:T

  constructor(id:T) {
    this.id =id
  }
  setId (id:T){
    this.id=id
  }
  getId():T{
    return this.id
  }
}
let user1:Person<number> = new Person<number>(1)
console.log("result>>>>>",user1.getId())
image.png
image.png
模块化

认识:一个ets文件就是一个模块,且每个模块之间都是独立的。

默认导入和导出

重点:只能导出一个值

代码语言:javascript
代码运行次数:0
运行
复制
/*
默认导出:指一个模块,只能默认导出的一个值或对象。使用时,可以自定义导入名称。
*/
 // 导出语法:
export default 需要导出的内容
// 默认导入语法:
import 自定义名称 from "模块路径"
代码语言:javascript
代码运行次数:0
运行
复制
// index2.ets
exprot default 1
// Index.ets
import num from "./index2"
console.log("result>>",num)
image.png
image.png
image.png
image.png
按需导入导出

重点:按照需要可导出导入多个值 注意:导入的变量名需要和导出的一致,如需要更改使用as关键字

  • 方式一:单个逐一导出
代码语言:javascript
代码运行次数:0
运行
复制
//导出 
export  let num1:number=1
export  let num2:number=2
// 导入
import {num1 as num11,num2} from "./index2" // 需要什么导入什么,
console.log("result>>>",num11)
console.log("result>>>",num2)
image.png
image.png
  • 方式一:统一导出
代码语言:javascript
代码运行次数:0
运行
复制
// 导出
let num1:number=1
let num2:number=2
export {num1,num2}
// 导出和方法一一致
全部导入

重点:使用*号

代码语言:javascript
代码运行次数:0
运行
复制
//  导出
let num1:number=1
let num2:number=2
export {num1,num2}

// 导入
import * as nums from "./index2"
console.log("result>>>",nums.num1)
console.log("result>>>",nums.num2)
image.png
image.png

二、自定义组件

基本使用
代码语言:javascript
代码运行次数:0
运行
复制
// 自定义
@Component
struct Header {
  build() {
    Row(){
    Text("首页")
    }.width("100%").height(50).backgroundColor("#fff59a9a").justifyContent(FlexAlign.Center)
  }
}

@Entry
@Component
struct Index {
  build() {
    Column(){
      Header()
    }.width("100%").height("100%")
  }
}
image.png
image.png
组件拆分
image.png
image.png
代码语言:javascript
代码运行次数:0
运行
复制
// header.ets
@Component
export   struct Header {
  build() {
    Row(){
      Text("首页")
    }.width("100%").height(50).backgroundColor("#fff59a9a").justifyContent(FlexAlign.Center)
  }
}
代码语言:javascript
代码运行次数:0
运行
复制
// Index.ets
import {Header} from "../component/Header"
@Entry
@Component
struct Index {
  build() {
    Column(){
      Header()
    }.width("100%").height("100%")
  }
}
image.png
image.png
成员变量和成员函数
代码语言:javascript
代码运行次数:0
运行
复制
import {Header} from "../component/Header"
@Component
struct navItem {
  // 成员变量
  title:string="标题"
  message:string="消息"
  // 成员方法
  show=()=>{
    AlertDialog.show({message:this.message})
  }
  // 普通方法 ,内部用,不能外部修改
  show1 (){}
  build() {
    Column(){
      Row(){
        Text(this.title)
        Text("更多》").fontColor("#ff5d5b5b").onClick(()=>{
          this.show()
        })


      }.border({width:{bottom:1}}).width("100%").height(40).padding({left:5,right:5}).justifyContent(FlexAlign.SpaceBetween)
      Column(){
       Text("内容")
      }.padding(5)

    }
      .width("100%").height(150).backgroundColor("#fff8c6c6").borderRadius(10)
  }
}
@Entry
@Component
struct Index {
  build() {
    Column(){
      Header()
      navItem({title:"新闻",message:'新闻'}).width("100%").padding(10)
      navItem({title:"娱乐",message:"娱乐"}).width("100%").padding(10)
    }.width("100%").height("100%")
  }
}
image.png
image.png
BuilderParam 传递UI
代码语言:javascript
代码运行次数:0
运行
复制
import {Header} from "../component/Header"
@Component
struct navItem {
  // 成员变量
  title:string="标题"
  message:string="消息"
  // 成员方法
  show=()=>{
    AlertDialog.show({message:this.message})
  }
  // 普通方法 ,内部用,不能外部修改
  show1 (){}
  // 定义BuilderParam 接收外部传入的ui,并设置默认值
  @BuilderParam  ContentBuilder :()=>void = this.defaultBuilder
  @Builder
  defaultBuilder(){
    // 默认UI
    Text("默认")
  }
  build() {
    Column(){
      Row(){
        Text(this.title)
        Text("更多》").fontColor("#ff5d5b5b").onClick(()=>{
          this.show()
        })
      }.border({width:{bottom:1}}).width("100%").height(40).padding({left:5,right:5}).justifyContent(FlexAlign.SpaceBetween)
      Column(){
       this.ContentBuilder()
      }.padding(5)

    }
      .width("95%").height(150).backgroundColor("#fff8c6c6").borderRadius(10).margin(10)
  }
}
@Entry
@Component
struct Index {
  build() {
    Column(){
      Header()
      navItem({title:"新闻",message:'新闻'}){
             // 外部UI
        Text("新闻1")
      }
      navItem({title:"娱乐",message:"娱乐"}){
        // 外部UI
        Button("娱乐1")
      }
    }.width("100%").height("100%")
  }
}
image.png
image.png
多个BuilderParam 传递UI
代码语言:javascript
代码运行次数:0
运行
复制
/*
多个和单个的区别就是:多个需要使用参数的方式来传递参数
*/

@Component
struct CardItem {

  @BuilderParam TitleBuild :()=>void = this.titleDefaultBuild
  @BuilderParam ContentBuild :()=>void = this.ContentDefaultBuild

  @Builder
  titleDefaultBuild(){
  Text("a")
}
  @Builder
  ContentDefaultBuild(){
    Text("b")
  }

  build() {
    Column(){
      Row(){
        this.TitleBuild()
      }.width("100%").height(40).border({width:{bottom:1}}).padding(5)
      Column(){
        this.ContentBuild()

      }.layoutWeight(1).width("100%").alignItems(HorizontalAlign.Start).padding(10)
    }.width("100%").height(150).borderRadius(10).backgroundColor("#fff8cccc")
  }
}
@Entry
@Component
struct Index {
  @Builder
  TitleBuild(){
    Text("新闻")
  }
  @Builder
  ContentBuild(){
    Text("新闻内容")
  }
  build() {
    Column(){
      CardItem({
        TitleBuild:this.TitleBuild,
        ContentBuild:this.ContentBuild
      }).margin({bottom:10})
      CardItem()

    }.width("100%").height("100%").padding(10)
  }
}
image.png
image.png

三、状态管理

概述

当运行时的状态变量变化时,带来UI的重新渲染,在ArkUI中统称为状态管理机制。 状态变量特征:被装饰器修饰。

image.png
image.png
@State
  • @State修饰简单类型的数据,数据修改时会实时的刷新页面。
  • 但是修饰复杂类型的数据时,虽然数据也能够被修改,但是页面只会刷新全部刷新一次后,后续只刷新复杂类型的第一层数据。
  • 解决办法就是将内容的变量整个重新赋值。
  • 使用Object.key(Object)可以知道复杂数据类型的第一层数据的变量值
代码语言:javascript
代码运行次数:0
运行
复制
/*

*/ 
interface  Cat{
  name:string
  age:number
}

interface  Person{
  name:string
  cat:Cat
}

@Entry
@Component
struct Index {
  @State message:string ="hello"
   @State user:Person={
     name:"小明",
     cat:{
       name:'cat1',
       age:1
     }
   }

  build() {
    Column(){
      Text(Object.keys(this.user).toString())
      Text(this.message)
      Text(JSON.stringify(this.user))
      Text(this.user.cat.name)
      Text(this.user.cat.age.toString())
      Button("修改").onClick(()=>{
        this.message="小小"
        this.user.name="a"
        this.user.cat.name="cat2"
        this.user.cat.age++
        console.log(JSON.stringify(this.user))

      })


    }.width("100%").height("100%").padding(10)
  }
}
image.png
image.png
@Prop
  • prop可以接收父组件传递的数据。但是不能修改父组件的数据
  • 如果子组件想要修改父组件的数据,需要父组件定义一个成员方法并传递给子组件尽心修改(其作用还是父组件自己修改自己的值,只是将修改的操作给了子组件。)
代码语言:javascript
代码运行次数:0
运行
复制
@Component
struct SItem {
   @Prop SMessage:string=''
  change=()=>{}
  build() {

  Column(){
    Text(`子组件》》》${this.SMessage}`).width(100).height(100).backgroundColor("#fff")
    Button("a1").onClick(()=>{
      this.change()
    })

  }
  }
}
@Entry
@Component
struct Index {
  @State FMessage:string="f"
  build() {

    Column(){
      Text(`父组件>>${this.FMessage}`)
      Button("F").onClick(()=>{
        this.FMessage="ff"
      })

    SItem({SMessage:this.FMessage,change:()=>{
      this.FMessage="fff"
    }})
      
    }.width(200).height(200).backgroundColor("#fff3b1b1")
  }
}
image.png
image.png
案例-父子传值
代码语言:javascript
代码运行次数:0
运行
复制
@Component
struct numItem {
  @Prop num:number=0
  sub=()=>{}
  add=()=>{}
  build() {
    Row({space:10}){
      Button("-").onClick(()=>{
        this.sub()
      })
      Text(this.num.toString())
      Button("+").onClick(()=>{
        this.add()
      })

    }.width("100%").height(60)
  }
}
@Entry
@Component
struct Index {
  @State num:number=0
  build() {
    Column(){
      numItem({
        num:this.num,
        sub:()=>{
        this.num--
      },
        add:()=>{this.num++}
      })
    }.width("100%").height("100%").backgroundColor("#ffefefef")
  }
}
image.png
image.png
@Link双向同步
代码语言:javascript
代码运行次数:0
运行
复制
// 子组件和父组件可以同时修改数据并同步


@Component
struct Sitem {
  @Link s:number
  build() {
    Column(){
      Text(this.s.toString())
      Button("a").onClick(()=>{
        this.s++
      })
    }
  }
}


@Entry
@Component
struct Index3 {
  @State message:number=0
  build() {
    Column(){
      Text(this.message.toString())
      Button("a").onClick(()=>{
          this.message++
      })
      Sitem({s:this.message})
    }.width("100%").height("100%")

  }
}
@Provide和@Consume后代组件
代码语言:javascript
代码运行次数:0
运行
复制
// 不需要传参
// 父组件使用@Component
// 子组件使用:@Provide 
// 使用条件:父组件和子组件绑定的变量名需要一致。

@Component
struct Sitem {
  @Consume message:number
  build() {
    Column(){
      Text(this.message.toString())
      Button("a").onClick(()=>{
        this.message++
      })
    }
  }
}
@Entry
@Component
struct Index3 {
  @Provide message:number=0
  build() {
    Column(){
      Text(this.message.toString())
      Button("a").onClick(()=>{
          this.message++
      })
      Sitem()
    }.width("100%").height("100%")

  }
}
@ Observed&@ ObjectLink嵌套数组属性变化

针对:因为装饰器仅能观察到第一层的变化,对于数据对象操作麻烦。 作用:用于在涉及嵌套对象或数组的场景中进行双向数据同步 注意:ObjectLink修饰符不能使用在Entry修饰的组件中。

image.png
image.png
代码语言:javascript
代码运行次数:0
运行
复制
// 页面可以刷新多层对象的嵌套,
// 注意:只是针对@ObjectLink的,没有加ObjectLink的的不会刷新

interface  IPerson{
  id:number
  name:string
  age:number

}

@Observed
class Person{
  id:number
  name:string
  age:number

  constructor(obj:IPerson) {
    this.id =obj.id
    this.name = obj.name
    this.age = obj.age

  }
}
@Component
struct Pitem {
  @ObjectLink info :Person
  build() {
    Row(){
      Text(JSON.stringify(this.info))
      Button("+").onClick(()=>{
        this.info.age++
      })
    }

  }
}
@Entry
@Component
struct Index3 {
  @State persons:Person[] = [
    new Person({
      id:1,
      name:"varin",
      age:1
    })
  ]
  build() {
    Column(){
      Pitem({info:this.persons[0]})
    }.width("100%").height("100%")

  }
}

四、路由管理

创建多个页面
  • 方法一
image.png
image.png
  • 方法二:
代码语言:javascript
代码运行次数:0
运行
复制
/*
第一步:创建一个新的ets文件
第二步:找到main_pages.json文件
路径:src/main/resources/base/profile/main_pages.json
第三步:配置
*/
{
  "src":[
    "pages/Index",
    "pages/Index2" // 新加的
  ]
}
image.png
image.png
页面跳转和后退
代码语言:javascript
代码运行次数:0
运行
复制
// 可以返回用pushUrl
// 不可以返回用replaceUrl()
import { router } from '@kit.ArkUI'

@Entry
@Component
struct Login {
  build() {
    Column(){
      Text("login")
      Button("跳转到首页,可以回退").onClick(()=>{
        router.pushUrl({
          url:"pages/Index"
        })

      })
      Button("跳转到首页,不能回退").onClick(()=>{
        router.replaceUrl({
          url:"pages/Index"
        })

      }).margin({top:10})
    }.width("100%").height("100%")
  }
}
页面栈

说明:页面栈是用来存储程序运行时页面的一种数据结构,遵循先进后出的原则。 页面栈的最大容量为32个页面。

代码语言:javascript
代码运行次数:0
运行
复制
// 获取页面栈长度
router.getLength()
// 清空页面栈
router.clear()
路由模式
代码语言:javascript
代码运行次数:0
运行
复制
Standard(默认,一直添加页面栈)
Single:如果页面已存在,会将最近同URL页面移到栈顶
路由传参
代码语言:javascript
代码运行次数:0
运行
复制
// 传递
router.pushUrl({

  url:"地址,
    params:{
  // 数据
    }
})
// 获取
 const amessage = router.getParams() as Obj;
    console.log(JSON.stringify(router.getParams()))

案例:

代码语言:javascript
代码运行次数:0
运行
复制
// Login.ets

import { router } from '@kit.ArkUI'

@Entry
@Component
struct Login {
  build() {
    Column(){
      Text("login")
      Button("跳转到首页,可以回退").onClick(()=>{
        router.pushUrl({
          url:"pages/Index",
          params:{
            name:'abc'
          }
        })

      })
      Button("跳转到首页,不能回退").onClick(()=>{
        router.replaceUrl({
          url:"pages/Index"
        })

      }).margin({top:10})
    }.width("100%").height("100%")
  }
}
image.png
image.png
代码语言:javascript
代码运行次数:0
运行
复制
// Index.ets
import { router } from '@kit.ArkUI'

interface  Obj{
  name:string
}

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  aboutToAppear(): void {
    // 拿到的默认是一个对象,需要取值要设置参数的类型
    const amessage = router.getParams() as Obj;
    console.log(JSON.stringify(router.getParams()))
    this.message = amessage.name
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}
image.png
image.png

五、生命周期

image.png
image.png

六、Stage模型

简介

应用模型是系统为开发者提供的应用程序所需能力的抽象提炼,它提供了应用程序必备的组件和运行机制 简而言之:应用模型就是应用的施工图纸,他规范化了:程序运行流程,项目结构,文件功能等。

Stage模型-目录
image.png
image.png
app.Json5应用配置
代码语言:javascript
代码运行次数:0
运行
复制
{
  "app": {
    "bundleName": "cn.varin.myapplication", // 包名
    "vendor": "example", // 描述
    "versionCode": 1000000, // 版本号
    "versionName": "1.0.0", // 给用户看的版本号
    "icon": "$media:app_icon",// 应用图标
    "label": "$string:app_name" //应用名
  }
}
UIAbility组件
image.png
image.png

七、常用组件及案例

扩展-List组件
  • 简介:列表是一种容器,当列表项达到一定数量时,超过List容器组件大小时,会自动滚动
  • 语法:
image.png
image.png
扩展-将图标当做字体引入
代码语言:javascript
代码运行次数:0
运行
复制
步骤一:https://www.iconfont.cn/寻找图标添加到项目中,完成后下载,解压后将解压后的文件添加
到app项目中。
image.png
image.png
代码语言:javascript
代码运行次数:0
运行
复制
// 步骤二:注册
// 导入模块:
import font from '@ohos.font'
// 在生命周期函数类注册字体
  aboutToAppear(): void {
    font.registerFont({
      familyName:"fontIcons", // 名称任意
      familySrc:'/fontIcons/iconfont.ttf' // 步骤一存放的位置
    })
  }
代码语言:javascript
代码运行次数:0
运行
复制
// 步骤三:使用
// 文本框中填写的值,参考icon网站打包中的html文件
// fontFamily 填写自定义字体名称
  Text("\ue651").fontFamily("fontIcons").fontSize(20).fontColor("#ffea2222")
image.png
image.png

效果:

image.png
image.png
掘金评论案例
结构
image.png
image.png
实体类
代码语言:javascript
代码运行次数:0
运行
复制
// 准备评论的数据类
export class CommentData {
  avatar: string; // 头像
  name: string; // 昵称
  level: number; //用户等级
  likeNum: number; //点赞数量
  commentTxt: string; //评论内容
  isLike: boolean; //是否喜欢
  levelIcon: Resource // level等级
  timeString: string // 发布时间-基于时间戳处理后,展示给用户看的属性(2天前)
  time: number // 时间戳-数字格式的日期

  constructor(avatar: string, name: string, time: number, level: number, lickNum: number, commentTxt: string, isLike: boolean, ) {
    this.avatar = avatar
    this.name = name
    this.timeString = this.convertTime(time) // 拿到的时间格式, 通常是时间戳的格式  1645820201123
    this.time = time
    this.level = level
    this.likeNum = lickNum
    this.commentTxt = commentTxt
    this.isLike = isLike
    this.levelIcon = this.convertLevel(this.level) // 基于等级数字, 转换成图片路径
  }

  convertTime(timestamp: number) {
    // 获取当前的时间戳
    const currentTimestamp = new Date().getTime();
    const timeDifference = (currentTimestamp - timestamp) / 1000; // 转换为秒

    if (timeDifference < 5 || timeDifference == 0) {
      return "刚刚";
    } else if (timeDifference < 60) {
      return `${Math.floor(timeDifference)}秒前`;
    } else if (timeDifference < 3600) {
      return `${Math.floor(timeDifference / 60)}分钟前`;
    } else if (timeDifference < 86400) {
      return `${Math.floor(timeDifference / 3600)}小时前`;
    } else if (timeDifference < 604800) {
      return `${Math.floor(timeDifference / 86400)}天前`;
    } else if (timeDifference < 2592000) {
      return `${Math.floor(timeDifference / 604800)}周前`;
    } else if (timeDifference < 31536000) {
      return `${Math.floor(timeDifference / 2592000)}个月前`;
    } else {
      return `${Math.floor(timeDifference / 31536000)}年前`;
    }
  }

  // 基于传入的level,转换成图片路径
  convertLevel(level: number) {
    const iconList = [
      $r('app.media.level_1'),
      $r('app.media.level_2'),
      $r('app.media.level_3'),
      $r('app.media.level_4'),
      $r('app.media.level_5'),
      $r('app.media.level_6'),
    ]
    return iconList[level]
  }
}

// 封装一个方法, 创建假数据
export const createListRange = (): CommentData[] => {
  let result: CommentData[] = new Array()
  result = [
    new CommentData(`https://fastly.picsum.photos/id/770/600/600.jpg?hmac=tuK9EHg1ifTU3xKAiZj2nHSdWy4mk7enhylgOc2BW7E`, "雪山飞狐", 1645820201123, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '23年一年干完的事😂😂😂真的非常仓促', false),
    new CommentData(`https://fastly.picsum.photos/id/225/600/600.jpg?hmac=v97zt_t4mxeyMttX_m09pxhCvftiTxFR1MMBZi5HQxs`, "千纸鹤", 1677356201123, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), 'Netty对象池源码分析来啦!juejin.cn欢迎点赞[奸笑]', false),
    new CommentData(`https://fastly.picsum.photos/id/122/600/600.jpg?hmac=1oA93YbjYVt96DcJcGQ5PLthzjUsdtrnBQaM0USBozI`, "烟雨江南", 1688772201123, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '有一个不听劝的Stable Diffusion出图的小伙伴,找我给她装填脑。 一个资深的IT工程师不能受这个委屈。', false),
    new CommentData(`https://fastly.picsum.photos/id/654/600/600.jpg?hmac=ewnK6Bx_MKQLJa9waZOV1xNO7--K5oSwCShtz1JDYw8`, "魔法小精灵", 1697484201123, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '有一点可以确信 前后端开发界限越来越模糊。后端可以不写 但是不能不会。', false),
    new CommentData(`https://fastly.picsum.photos/id/345/600/600.jpg?hmac=EQflzbIadAglm0RzotyKXM2itPfC49fR3QE7eW_UaPo`, "独行侠", 1704067200000, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '今天看到一个帖子,挺有意思的。', false),
    new CommentData(`https://fastly.picsum.photos/id/905/600/600.jpg?hmac=DvIKicBZ45DEZoZFwdZ62VbmaCwkK4Sv7rwYzUvwweU`, "枫叶飘零", 1706745600000, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '我想了搞钱的路子, 1:投资理财, 后来发下,不投资就是最好的理财, 2:买彩票,后来发现彩票都是人家预定好的,根本不是随机的,卒, 3:开店创业,隔行如隔山,开店失败,卒。', false),
    new CommentData(`https://fastly.picsum.photos/id/255/600/600.jpg?hmac=-lfdnAl71_eAIy1OPAupFFPh7EOJPmQRJFg-y7lRB3s`, "星空漫步", 1707523200000, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '优胜劣汰,自然选择吧,没什么好怪的。都是crud,招个大学生就能干了。', false),
    new CommentData(`https://fastly.picsum.photos/id/22/600/600.jpg?hmac=QEZq7KUHwBZCt3kGSEHMwJlZfnzCxCeBgHjYj7iQ-UY`, "剑指苍穹", 1708300800000, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '白嫖ChatGPT4的功能。然后,抱着试一试的态度把玩了一下。发现真的好用。', false),
    new CommentData(`https://fastly.picsum.photos/id/439/600/600.jpg?hmac=LC9k_bzrN0NhKRyV62fou3ix3cRFZKNfAyXgxGs6zh8`, "黑暗王国", 1708646400000, Math.floor(Math.random()*6) , Math.floor(Math.random()*100), '字数越少,事情越大。', false),
  ]
  return result
}
首页
代码语言:javascript
代码运行次数:0
运行
复制
import InfoTop from "../components/InfoTop"
import InfoItem from "../components/InfoItem"
import font from '@ohos.font'
import InfoBtm from '../components/InfoBtn'
import {CommentData,createListRange} from  "../model/CommentData"
import data from '@ohos.telephony.data'
@Entry
@Component
struct Index {
  aboutToAppear(): void {
    font.registerFont({
      familyName:"fontIcons",
      familySrc:'/fontIcons/iconfont.ttf'
    })
  }
  // 列表数据
  @State commentList:CommentData[] = createListRange()

  handleLike(index:number){
    // AlertDialog.show({
    //   message:index.toString()
    // })
    let dataItem = this.commentList[index]
    if (dataItem.isLike) {

      dataItem.likeNum -=1
    }else{
      dataItem.likeNum +=1
    }
    dataItem.isLike = !dataItem.isLike
    this.commentList.splice(index,1,dataItem)
  }

  // 添加评论
  onAddComment(txt:string){
  const item:CommentData=
    new CommentData(`https://fastly.picsum.photos/id/439/600/600.jpg?hmac=LC9k_bzrN0NhKRyV62fou3ix3cRFZKNfAyXgxGs6zh8`, "Varin", new Date().getTime(), Math.floor(Math.random()*6) , Math.floor(Math.random()*100), txt, false)
   this.commentList= [item , ...this.commentList]
  }

  // 排序
  handleSort(type:number){
    if(type==0){
      this.commentList.sort((a,b)=>{
        return b.time-a.time
      })
    }else if(type==1){
      this.commentList.sort((a,b)=>{
        return b.likeNum-a.likeNum
      })
    }

  }
  @State num:number=0
  build() {
    Column(){
      // 头
      InfoTop({
        onSort:(type:number)=>{
          this.handleSort(type)
        }

      })

      // 内容
        List(){
          ForEach(this.commentList,(item:CommentData,index)=>{
            ListItem(){
              InfoItem({
                itemObj:item,
                index:index,
              onHandleLike:(index:number)=>{
                // 在外层包一层箭头函数,让this指向父
                this.handleLike(index)
              }
              })
            }
          })
        }.layoutWeight(1)
      .padding({bottom:10})
      .divider({
        color: "#ffd9d9d9",
        startMargin:10,
        endMargin:10,
        strokeWidth:1
      })
      // 底
     InfoBtm({

       addComment:(txt:string)=>{
         this.onAddComment(txt)
       }

     })
    }.width("100%").height("100%").backgroundColor("#ffefefef")
  }
}
头部区组件
代码语言:javascript
代码运行次数:0
运行
复制
@Extend(Button)
function InfoTopBtn(isp:boolean){
  .width(46)
    .height(32)
    .fontSize(12)
    .padding({left:5,right:5})
    .backgroundColor(isp?"#fff":"#f7f8fa")
    .fontColor(isp?"#2f2e33":"#8e9298")
    .border({width:1,color:isp?'#e4e5e6':"#f7f8fa"})
}
@Component
struct InfoTop {
 @State isP:boolean = true
  onSort=(type:number)=>{}
  build() {
    Row(){
    Text("全部评论").fontSize(18).fontWeight(700)
      Row(){
        Button("最新",{stateEffect:false}).InfoTopBtn(this.isP).onClick(()=>{
          this.isP=true
          this.onSort(0)
        })

        Button("最热",{stateEffect:false}).InfoTopBtn(!this.isP).onClick(()=>{
          this.isP=false
          this.onSort(1)
        })
      }

    }.width("100%").height(60).backgroundColor("#f7f8fa").padding(15).justifyContent(FlexAlign.SpaceBetween)

  }
}
export  default InfoTop
内容区组价
代码语言:javascript
代码运行次数:0
运行
复制
import { defaultAppManager } from '@kit.AbilityKit'
import { CommentData } from '../model/CommentData'

@Component
struct InfoItem {
  @Prop itemObj:CommentData
  @Prop index:number
  onHandleLike=(index:number)=>{}
  build() {
    Column(){
      Row() {
        Image(this.itemObj.avatar).width(30).aspectRatio(1).borderRadius(15)
        Text(this.itemObj.name).fontSize(13).fontColor(Color.Gray).margin({left:8})
        Image(this.itemObj.levelIcon).width(20).aspectRatio(1).margin({left:8})

      }.margin({top:10})
      Text(this.itemObj.commentTxt).fontSize(13)
        .fontColor(Color.Black).margin({left:40,bottom:8})
      Row() {

        Text(this.itemObj.timeString).fontSize(13).fontColor(Color.Gray).margin({left:40})
        Row(){
          Image(this.itemObj.isLike?$r("app.media.like_select"):$r("app.media.like_unselect")).width(15)
          Text(this.itemObj.likeNum.toString()).fontSize(13).margin({left:8}).fontColor(this.itemObj.isLike?Color.Blue:Color.Gray)
        }.onClick(()=>{
  // AlertDialog.show({message:})
          this.onHandleLike(this.index)

        })


      }.width("100%").justifyContent(FlexAlign.SpaceBetween)

    }.padding({left:15,right:15,top:5,bottom:5}).alignItems(HorizontalAlign.Start)
  }
}
export  default  InfoItem
底部组件
代码语言:javascript
代码运行次数:0
运行
复制
@Component
struct InfoBtm {
  @State txt:string = ''
  addComment=(txt:string)=>{}
  build() {
    Row(){
      Row(){
        Text("\ue621").fontSize(18).fontFamily("fontIcons").margin({left:10})
          TextInput({placeholder:"写评论...",text:$$this.txt}).fontSize(18).backgroundColor(Color.Transparent)
            .onSubmit(()=>{
              // AlertDialog.show({message:this.txt})
              this.addComment(this.txt)
            })

      }.height(40).backgroundColor("#f5f6f5").borderRadius(20)
      .margin({left:15,right:20,top:10,bottom:10}).layoutWeight(1)
      Text("\ue651").fontSize(20).fontFamily("fontIcons").margin({left:6,right:6})
      Text("\ue6a7").fontSize(20).fontFamily("fontIcons").margin({left:6,right:6})


    }.height(60).backgroundColor("#ffffffff").width("100%")

  }
}
export  default InfoBtm

效果图:

image.png
image.png
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、ArkTS语言-Class类
    • Class类
    • 剩余参数
    • 展开运算符
    • 接口继承
    • 接口实现
    • 泛型
    • 模块化
  • 二、自定义组件
  • 三、状态管理
  • 四、路由管理
    • 创建多个页面
    • 页面跳转和后退
    • 页面栈
    • 路由模式
    • 路由传参
  • 五、生命周期
  • 六、Stage模型
    • 简介
    • Stage模型-目录
    • app.Json5应用配置
    • UIAbility组件
  • 七、常用组件及案例
    • 扩展-List组件
    • 扩展-将图标当做字体引入
    • 掘金评论案例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档