一、ArkTS语言-Class类
Class类
- 简介:类是用于创建对象模板,同时类声明也会引入一个新类型,可定义其示例属性、方法和构造函数。
- 扩展:
// ?. 表示可选连操作符,
基本语法
class 类名{
// 属性
// 构造方法
// 方法
}
// 实例化对象
const class1:类名= new 类名()
对象-属性
class Person {
name:string=""
age :number=0
like?:string
}
const user1 :Person = new Person();
console.log(JSON.stringify(user1))
// 可选链操作符,存在打印,不存在也不会报错。
console.log("like>>>",user1?.like)
对象-构造方法
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))
对象-方法
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))
对象-静态属性和静态方法
// 类直接调用,不用new
class Tools{
static version:number=1.1
static show (){
console.log("此类的作用是提供工具")
}
}
console.log(Tools.version.toString())
Tools.show()
- 对象-继承extends和super关键字
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()
对象-判断类型:instanceof
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)
对象-访问修饰符
/*
readonly:只读,(只能读取不能修改) 例:Math.PI
private :私有的(只能在自己的类中使用)
protected :在自己和子类中可以访问
public (默认)
*/
剩余参数
说明:不定数量的参数
// 求和
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))
展开运算符
// 只能用在数组上
// 功能:合并数组
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))
接口继承
关键字:extends
interface IAnimal{
name:string,
}
interface ICat extends IAnimal{
color:string
}
let cat1:ICat = {
name:'cat',
color:'red'
}
console.log(JSON.stringify(cat1))
接口实现
关键字:implements
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()
泛型
泛型函数
/*
语法:
function 函数名 <Type>(temp:Type):Type{
return temp
}
*/
function isType<Type>(temp:Type):void{
console.log(typeof temp)
}
isType("1")
isType(1)
isType(false)
泛型约束
// 给传递的类型参数,添加限制
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)
多个泛型约束
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)
泛型接口
interface IUser<T>{
id:()=>T
}
let user1:IUser<number>= {
id(){
return 1;
}
}
console.log("result>>>>",user1.id())
泛型类
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())
模块化
认识:一个ets文件就是一个模块,且每个模块之间都是独立的。
默认导入和导出
重点:只能导出一个值
/*
默认导出:指一个模块,只能默认导出的一个值或对象。使用时,可以自定义导入名称。
*/
// 导出语法:
export default 需要导出的内容
// 默认导入语法:
import 自定义名称 from "模块路径"
// index2.ets
exprot default 1
// Index.ets
import num from "./index2"
console.log("result>>",num)
按需导入导出
重点:按照需要可导出导入多个值
注意:导入的变量名需要和导出的一致,如需要更改使用as关键字
- 方式一:单个逐一导出
//导出
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)
- 方式一:统一导出
// 导出
let num1:number=1
let num2:number=2
export {num1,num2}
// 导出和方法一一致
全部导入
重点:使用*号
// 导出
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)
二、自定义组件
基本使用
// 自定义
@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%")
}
}
组件拆分
// header.ets
@Component
export struct Header {
build() {
Row(){
Text("首页")
}.width("100%").height(50).backgroundColor("#fff59a9a").justifyContent(FlexAlign.Center)
}
}
// Index.ets
import {Header} from "../component/Header"
@Entry
@Component
struct Index {
build() {
Column(){
Header()
}.width("100%").height("100%")
}
}
成员变量和成员函数
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%")
}
}
BuilderParam 传递UI
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%")
}
}
多个BuilderParam 传递UI
/*
多个和单个的区别就是:多个需要使用参数的方式来传递参数
*/
@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)
}
}
三、状态管理
概述
当运行时的状态变量变化时,带来UI的重新渲染,在ArkUI中统称为状态管理机制。
状态变量特征:被装饰器修饰。
@State
- @State修饰简单类型的数据,数据修改时会实时的刷新页面。
- 但是修饰复杂类型的数据时,虽然数据也能够被修改,但是页面只会刷新全部刷新一次后,后续只刷新复杂类型的第一层数据。
- 解决办法就是将内容的变量整个重新赋值。
- 使用Object.key(Object)可以知道复杂数据类型的第一层数据的变量值
/*
*/
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)
}
}
@Prop
- prop可以接收父组件传递的数据。但是不能修改父组件的数据
- 如果子组件想要修改父组件的数据,需要父组件定义一个成员方法并传递给子组件尽心修改(其作用还是父组件自己修改自己的值,只是将修改的操作给了子组件。)
@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")
}
}
案例-父子传值
@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")
}
}
@Link双向同步
// 子组件和父组件可以同时修改数据并同步
@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后代组件
// 不需要传参
// 父组件使用@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修饰的组件中。
// 页面可以刷新多层对象的嵌套,
// 注意:只是针对@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%")
}
}
四、路由管理
创建多个页面
- 方法一
- 方法二:
/*
第一步:创建一个新的ets文件
第二步:找到main_pages.json文件
路径:src/main/resources/base/profile/main_pages.json
第三步:配置
*/
{
"src":[
"pages/Index",
"pages/Index2" // 新加的
]
}
页面跳转和后退
// 可以返回用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个页面。
// 获取页面栈长度
router.getLength()
// 清空页面栈
router.clear()
路由模式
Standard(默认,一直添加页面栈)
Single:如果页面已存在,会将最近同URL页面移到栈顶
路由传参
// 传递
router.pushUrl({
url:"地址,
params:{
// 数据
}
})
// 获取
const amessage = router.getParams() as Obj;
console.log(JSON.stringify(router.getParams()))
案例:
// 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%")
}
}
// 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%')
}
}
五、生命周期
六、Stage模型
简介
应用模型是系统为开发者提供的应用程序所需能力的抽象提炼,它提供了应用程序必备的组件和运行机制
简而言之:应用模型就是应用的施工图纸,他规范化了:程序运行流程,项目结构,文件功能等。
Stage模型-目录
app.Json5应用配置
{
"app": {
"bundleName": "cn.varin.myapplication", // 包名
"vendor": "example", // 描述
"versionCode": 1000000, // 版本号
"versionName": "1.0.0", // 给用户看的版本号
"icon": "$media:app_icon",// 应用图标
"label": "$string:app_name" //应用名
}
}
UIAbility组件
七、常用组件及案例
扩展-List组件
- 简介:列表是一种容器,当列表项达到一定数量时,超过List容器组件大小时,会自动滚动
- 语法:
扩展-将图标当做字体引入
步骤一:https://www.iconfont.cn/寻找图标添加到项目中,完成后下载,解压后将解压后的文件添加
到app项目中。
// 步骤二:注册
// 导入模块:
import font from '@ohos.font'
// 在生命周期函数类注册字体
aboutToAppear(): void {
font.registerFont({
familyName:"fontIcons", // 名称任意
familySrc:'/fontIcons/iconfont.ttf' // 步骤一存放的位置
})
}
// 步骤三:使用
// 文本框中填写的值,参考icon网站打包中的html文件
// fontFamily 填写自定义字体名称
Text("\ue651").fontFamily("fontIcons").fontSize(20).fontColor("#ffea2222")
效果:
掘金评论案例
结构
实体类
// 准备评论的数据类
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
}
首页
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")
}
}
头部区组件
@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
内容区组价
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
底部组件
@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
效果图: