鸿蒙NEXT项目实战-百得知识库03

代码仓地址,大家记得点个star

IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点: 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三方库的使用和封装 8、头像上传 9、应用软件更新等https://gitee.com/xt1314520/IbestKnowTeach

Home页面开发

设计图

需求分析

Home页面一共可以分为三块部分

1、头部-最新、热门

2、搜索框

3、内容主体

搭建Home页面布局

1、头部-最新、热门

最新、热门可以用Text文本组件,下面下划线用Divider组件

复制代码
// 标题栏
Row({ space: 10 }) {
  Column() {
    Text($r('app.string.article_best_new'))
      .textStyles()
    // 选中标题会出现下划线
    if (this.newDividerShow) {
      Divider().dividerStyles()
    }
  }
  .onClick(() => {
    // 展示下划线
    this.hotDividerShow = false
    this.newDividerShow = true
    // 查询最新文章数据
    this.isShow = false
    this.page = 1
    this.getArticleNewDataList(true, true)
  })

  Column() {
    Text($r('app.string.article_best_hot'))
      .textStyles()
    // 选中标题会出现下划线
    if (this.hotDividerShow) {
      Divider().dividerStyles()
    }
  }
  .onClick(() => {
    this.newDividerShow = false
    this.hotDividerShow = true
    // 查询最热门文章数据
    this.isShow = false
    this.page = 1
    this.getArticleHotDataList(true, true)
  })

}.justifyContent(FlexAlign.Start)
  .margin({ top: 10, bottom: 20 })
  .width(CommonConstant.WIDTH_FULL)
2、搜索框

搜索框可以使用鸿蒙原生组件Search

复制代码
// 搜索
Search({ placeholder: '请输入关键字', value: $$this.keyword })
  .placeholderFont({ size: 14 })
  .textFont({ size: 14 })
  .onSubmit(() => {
    // 处理标题
    this.title = encodeURIComponent(this.keyword)
    // 分页查询文章内容
    this.isShow = false
    this.page = 1
    this.getArticleDataList(true)
  })
  .width(CommonConstant.WIDTH_FULL)
  .height(30)
3、内容主体

内容主体相当于我们把文章单条内容封装成一个组件,然后使用List组件进行布局嵌套使用Foreach进行循环遍历文章数组对象数据

整体大家看一条文章数据,分为三行,行使用的是Row布局,整体三行布局从上到下是列所以组件整体用Column进行包裹

封装单条文章组件(在ets下面创建component目录然后创建ArticleComponent.ets文件)

复制代码
import { ArticleContentData } from '../api/ArticleContentApi.type'
import { CommonConstant } from '../contants/CommonConstant'

@Component
  export struct ArticleComponent {
    // 文章数据
    @Prop articleContentData: ArticleContentData

    build() {
      Column() {
        Row({ space: 10 }) {
          // 头像
          Image(this.articleContentData.avatarUri)
            .width($r('app.float.common_width_tiny'))
            .aspectRatio(1)
            .borderRadius(10)
          // 姓名
          Text(this.articleContentData.nickname)
            .fontSize($r('app.float.common_font_size_medium'))
            .fontColor($r('app.color.common_gray'))
            .width('70%')
            .maxLines(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
        }.width(CommonConstant.WIDTH_FULL)

        Row() {
          // 内容标题
          Text(this.articleContentData.title)
            .fontSize($r('app.float.common_font_size_small'))
            .width('80%')
            .maxLines(3)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
          Image(this.articleContentData.coverUrl)
            .width($r('app.float.common_width_medium'))
            .aspectRatio(1)
            .objectFit(ImageFit.Contain)
            .borderRadius(5)
        }.width(CommonConstant.WIDTH_FULL)
          .justifyContent(FlexAlign.SpaceBetween)

        // 展示阅读、点赞、收藏
        Row({ space: 3 }) {
          Text(this.articleContentData.readCount + '阅读')
            .textStyles()
          Text('|')
            .textStyles()
          Text(this.articleContentData.time)
            .textStyles()
          Text('|')
            .textStyles()
          // 文章内容标签
          if (this.articleContentData.contentCategory === '1') {
            Text('鸿蒙')
              .textLabelStyles()
          } else if (this.articleContentData.contentCategory === '2') {
            Text('Java')
              .textLabelStyles()
          } else if (this.articleContentData.contentCategory === '3') {
            Text('Web前端')
              .textLabelStyles()
          } else if (this.articleContentData.contentCategory === '4') {
            Text('运维')
              .textLabelStyles()
          } else {
            Text('未知级别')
              .textLabelStyles()
          }
          Text('|')
            .textStyles()
          // 文章难度分类标签
          if (this.articleContentData.difficultyCategory === '1') {
            Text(this.articleContentData.platformCategory === '1' ? '基础知识' : '简单面试题')
              .textLabelStyles()
          } else if (this.articleContentData.difficultyCategory === '2') {
            Text(this.articleContentData.platformCategory === '1' ? '进阶知识' : '中等面试题')
              .textLabelStyles()
          } else if (this.articleContentData.difficultyCategory === '3') {
            Text(this.articleContentData.platformCategory === '1' ? '高级知识' : '困难面试题')
              .textLabelStyles()
          } else {
            Text('未知级别')
              .textLabelStyles()
          }
        }.width(CommonConstant.WIDTH_FULL)

      }
      .padding(10)
        .width(CommonConstant.WIDTH_FULL)
        .height(110)
        .margin({ top: 13 })
    .backgroundColor($r('app.color.common_white'))
    .justifyContent(FlexAlign.SpaceBetween)
    .borderRadius(10)

  }
}

@Extend(Text)
function textStyles() {
  .fontColor($r('app.color.common_gray'))
  .fontSize($r('app.float.common_font_size_tiny'))
}

@Extend(Text)
function textLabelStyles() {
  .fontSize($r('app.float.common_font_size_tiny'))
  .fontColor(Color.Black)
}

然后我们整体在Home页面里面展示我们的文章内容数组数据

复制代码
if (this.isShow) {
  Refresh({ refreshing: $$this.isRefreshing }) {
    // 内容组件
    List() {
      ForEach(this.articleContentList, (item: ArticleContentData) => {
        ListItem() {
          ArticleComponent({ articleContentData: item })
            .onClick(() => {
              // 路由到内容详情页
              router.pushUrl({
                url: RouterConstant.VIEWS_HOME_ARTICLE_INFO, params: {
                  "articleId": item.id
                }
              })
            })
        }
      })
      if (this.textShow) {
        ListItem() {
          Text($r('app.string.no_have_article'))
            .fontColor($r('app.color.common_gray'))
            .fontSize($r('app.float.common_font_size_small'))
            .width(CommonConstant.WIDTH_FULL)
            .textAlign(TextAlign.Center)
            .margin({ top: 80 })
        }
      }
    }
    .width(CommonConstant.WIDTH_FULL)
      .height(CommonConstant.HEIGHT_FULL)
      .scrollBar(BarState.Off)
      .onReachEnd(() => {
        if (!this.isLoad) {
          if (this.total > this.page * this.pageSize) {
            this.isLoad = true
            this.page++
            if (this.newDividerShow) {
              // 分页查询最新文章数据
              this.getArticleNewDataList(false, false)
            }
            if (this.hotDividerShow) {
              // 分页查询最热门文章数据
              this.getArticleHotDataList(false, false)
            }
          } else {
            this.textShow = true
          }

        }
      })
  }
  .onRefreshing(() => {
    if (!this.isLoad) {
      this.isLoad = true
      this.textShow = false
      // 页面恢复到1
      this.page = 1
      if (this.newDividerShow) {
        // 分页查询最新文章数据
        this.getArticleNewDataList(true, true)
      }
      if (this.hotDividerShow) {
        // 分页查询最热门文章数据
        this.getArticleHotDataList(true, true)
      }

    }
  })
} else {
  // 加载组件
  LoadingComponent()
}

加载组件 LoadingComponent()是我们自己进行封装的,因为我们的数据可能因为网络原因还没在服务端查询出来,界面为了不要展示长时间空白让用户误会,所以展示我们数据正在加载中

复制代码
import { CommonConstant } from '../contants/CommonConstant'

@Component
  export struct LoadingComponent {
    @State message: string = '数据正在加载中'

    build() {
      Row() {
        LoadingProgress()
          .width(30).height(30).color(Color.Gray)
        Text(this.message)
          .fontSize((14)).fontColor(Color.Gray)
      }.height("80%")
        .width(CommonConstant.WIDTH_FULL)
        .justifyContent(FlexAlign.Center)
    }
  }
4、整体Home页面代码
复制代码
import { router } from '@kit.ArkUI'
import { RouterConstant } from '../../contants/RouterConstant'
import { CommonConstant } from '../../contants/CommonConstant'
import { ArticleComponent } from '../../components/ArticleComponent'
import articleContentApi from '../../api/ArticleContentApi'
import { LoadingComponent } from '../../components/LoadingComponent'
import { ArticleContentData } from '../../api/ArticleContentApi.type'
import { showToast } from '../../utils/Toast'

@Entry
  @Component
  export struct Home {
    // 是否展示最新标题的下划线
    @State newDividerShow: boolean = true
    // 是否展示热门标题的下划线
    @State hotDividerShow: boolean = false
    // 搜索词
    @State keyword: string = ''
    // 标题
    @State title: string = ''
    // 文章数据数组
    @State articleContentList: ArticleContentData[] = []
    // 学习打卡总记录数
    @State total: number = 0
    // 当前页
    @State page: number = 1
    // 每一页大小
    @State pageSize: number = 7
    // 控制当前页面展示
    @State isShow: boolean = false
    // 定义一个状态属性,用来和Refresh组件进行双向数据绑定
    @State isRefreshing: boolean = false
    // 节流, false表示未请求, true表示正在请求
    isLoad: boolean = false
    // 是否展示文本,列表到底
    @State textShow: boolean = false

    /**
   * 生命周期函数
   */
    async aboutToAppear() {
      // 默认获取首页最新文章内容
      this.getArticleNewDataList(true, false)
    }

    /**
   * 分页查询最新文章数据
   */
    async getArticleNewDataList(isFlushed: boolean, isUpdate: boolean) {
      // 分页查询最新文章数据
      const articleDataList =
        await articleContentApi.getNewArticle({ page: this.page, pageSize: this.pageSize, title: this.title })
      isFlushed ? this.articleContentList = articleDataList.records :
        this.articleContentList.push(...articleDataList.records)
      this.total = articleDataList.total
      // 判断总数据
      if (this.total > this.page * this.pageSize) {
        this.textShow = false
      } else {
        this.textShow = true
      }
      // 页面展示
      this.isShow = true
      // 节流,防止用户重复下拉
      this.isLoad = false
      this.isRefreshing = false
      // 是否刷新
      if (isUpdate) {
        showToast("已更新")
      }
    }

    /**
   * 分页查询最热门文章数据
   */
    async getArticleHotDataList(isFlushed: boolean, isUpdate: boolean) {
      // 分页查询最热门文章数据
      const articleDataList =
        await articleContentApi.getHotArticle({ page: this.page, pageSize: this.pageSize, title: this.title })
      isFlushed ? this.articleContentList = articleDataList.records :
        this.articleContentList.push(...articleDataList.records)
      this.total = articleDataList.total
      // 判断总数据
      if (this.total > this.page * this.pageSize) {
        this.textShow = false
      } else {
        this.textShow = true
      }
      // 页面展示
      this.isShow = true
      // 节流,防止用户重复下拉
      this.isLoad = false
      this.isRefreshing = false
      // 是否刷新
      if (isUpdate) {
        showToast("已更新")
      }
    }

    /**
   * 分页查询文章数据
   */
    async getArticleDataList(isFlushed: boolean) {
      // 分页查询文章数据
      if (this.newDividerShow) {
        this.getArticleNewDataList(isFlushed, true)
      }
      if (this.hotDividerShow) {
        this.getArticleHotDataList(isFlushed, true)
      }
    }

    build() {
      Column() {
      // 标题栏
      Row({ space: 10 }) {
        Column() {
          Text($r('app.string.article_best_new'))
            .textStyles()
          // 选中标题会出现下划线
          if (this.newDividerShow) {
            Divider().dividerStyles()
          }
        }
        .onClick(() => {
          // 展示下划线
          this.hotDividerShow = false
          this.newDividerShow = true
          // 查询最新文章数据
          this.isShow = false
          this.page = 1
          this.getArticleNewDataList(true, true)
        })

        Column() {
          Text($r('app.string.article_best_hot'))
            .textStyles()
          // 选中标题会出现下划线
          if (this.hotDividerShow) {
            Divider().dividerStyles()
          }
        }
        .onClick(() => {
          this.newDividerShow = false
          this.hotDividerShow = true
          // 查询最热门文章数据
          this.isShow = false
          this.page = 1
          this.getArticleHotDataList(true, true)
        })

      }.justifyContent(FlexAlign.Start)
      .margin({ top: 10, bottom: 20 })
      .width(CommonConstant.WIDTH_FULL)

      // 搜索
      Search({ placeholder: '请输入关键字', value: $$this.keyword })
        .placeholderFont({ size: 14 })
        .textFont({ size: 14 })
        .onSubmit(() => {
          // 处理标题
          this.title = encodeURIComponent(this.keyword)
          // 分页查询文章内容
          this.isShow = false
          this.page = 1
          this.getArticleDataList(true)
        })
        .width(CommonConstant.WIDTH_FULL)
        .height(30)

      if (this.isShow) {
        Refresh({ refreshing: $$this.isRefreshing }) {
          // 内容组件
          List() {
            ForEach(this.articleContentList, (item: ArticleContentData) => {
              ListItem() {
                ArticleComponent({ articleContentData: item })
                  .onClick(() => {
                    // 路由到内容详情页
                    router.pushUrl({
                      url: RouterConstant.VIEWS_HOME_ARTICLE_INFO, params: {
                        "articleId": item.id
                      }
                    })
                  })
              }
            })
            if (this.textShow) {
              ListItem() {
                Text($r('app.string.no_have_article'))
                  .fontColor($r('app.color.common_gray'))
                  .fontSize($r('app.float.common_font_size_small'))
                  .width(CommonConstant.WIDTH_FULL)
                  .textAlign(TextAlign.Center)
                  .margin({ top: 80 })
              }
            }
          }
          .width(CommonConstant.WIDTH_FULL)
          .height(CommonConstant.HEIGHT_FULL)
          .scrollBar(BarState.Off)
          .onReachEnd(() => {
            if (!this.isLoad) {
              if (this.total > this.page * this.pageSize) {
                this.isLoad = true
                this.page++
                if (this.newDividerShow) {
                  // 分页查询最新文章数据
                  this.getArticleNewDataList(false, false)
                }
                if (this.hotDividerShow) {
                  // 分页查询最热门文章数据
                  this.getArticleHotDataList(false, false)
                }
              } else {
                this.textShow = true
              }

            }
          })
        }
        .onRefreshing(() => {
          if (!this.isLoad) {
            this.isLoad = true
            this.textShow = false
            // 页面恢复到1
            this.page = 1
            if (this.newDividerShow) {
              // 分页查询最新文章数据
              this.getArticleNewDataList(true, true)
            }
            if (this.hotDividerShow) {
              // 分页查询最热门文章数据
              this.getArticleHotDataList(true, true)
            }

          }
        })
      } else {
        // 加载组件
        LoadingComponent()
      }

    }.padding($r('app.float.common_padding'))
    .height(CommonConstant.HEIGHT_FULL)
    .width(CommonConstant.WIDTH_FULL)

  }
}

@Extend(Text)
function textStyles() {
  .fontSize($r('app.float.common_font_size_huge'))
  .fontWeight(FontWeight.Medium)
}

@Extend(Divider)
function dividerStyles() {
  .color(Color.Black)
  .width($r('app.float.common_width_tiny'))
  .strokeWidth(3)
}
5、数据渲染,接口封装

查询最新文章数据,这个函数里面有个 articleContentApi.getNewArticle方法,这个方法是作者封装的接口

复制代码
/**
 * 分页查询最新文章数据
 */
async getArticleNewDataList(isFlushed: boolean, isUpdate: boolean) {
  // 分页查询最新文章数据
  const articleDataList =
    await articleContentApi.getNewArticle({ page: this.page, pageSize: this.pageSize, title: this.title })
  isFlushed ? this.articleContentList = articleDataList.records :
    this.articleContentList.push(...articleDataList.records)
  this.total = articleDataList.total
  // 判断总数据
  if (this.total > this.page * this.pageSize) {
    this.textShow = false
  } else {
    this.textShow = true
  }
  // 页面展示
  this.isShow = true
  // 节流,防止用户重复下拉
  this.isLoad = false
  this.isRefreshing = false
  // 是否刷新
  if (isUpdate) {
    showToast("已更新")
  }
}

大家可以根据东林提供的接口文档,将我们的调用接口封装成方法

这是涉及到文章的所有接口

复制代码
import http from '../request/Request'
import {
  ArticleContentData,
  ArticleContentHotPageParam,
  ArticleContentNewPageParam,
  ArticleContentPageParam,
  PageVo
} from './ArticleContentApi.type'

/**
 * 文章接口
 */
class ArticleContentApi {
  /**
   * 分页查询文章内容
   */
  pageListArticleContent = (data: ArticleContentPageParam): Promise<PageVo<ArticleContentData>> => {
    return http.get('/v1/article/page?page=' + data.page + '&&pageSize=' + data.pageSize + '&&title=' + data.title +
                    '&&contentCategory=' + data.contentCategory + '&&platformCategory=' + data.platformCategory +
                    '&&difficultyCategory=' + data.difficultyCategory)
  }
  /**
   * 根据文章id查询文章详情
   */
  getArticleContentInfo = (data: number): Promise<ArticleContentData> => {
    return http.get('/v1/article/info?id=' + data)
  }
  /**
   *  用户点赞/取消点赞文章
   */
  likeArticleContent = (data: number) => {
    return http.put('/v1/article/like?id=' + data)
  }
  /**
   *  用户收藏/取消收藏文章
   */
  collectArticleContent = (data: number) => {
    return http.put('/v1/article/collect?id=' + data)
  }
  /**
   * 查看我的点赞,最近100条
   */
  getUserLike = (): Promise<Array<ArticleContentData>> => {
    return http.get('/v1/article/myLike')
  }
  /**
   *查看我的收藏,最近100条
   */
  getUserCollect = (): Promise<Array<ArticleContentData>> => {
    return http.get('/v1/article/myCollect')
  }
  /**
   *分页查看最新文章
   */
  getNewArticle = (data: ArticleContentNewPageParam): Promise<PageVo<ArticleContentData>> => {
    return http.get('/v1/article/new?page=' + data.page + '&&pageSize=' + data.pageSize + '&&title=' + data.title)
  }
  /**
   *分页查看最热文章
   */
  getHotArticle = (data: ArticleContentHotPageParam): Promise<PageVo<ArticleContentData>> => {
    return http.get('/v1/article/hot?page=' + data.page + '&&pageSize=' + data.pageSize + '&&title=' + data.title)
  }
}

const articleContentApi = new ArticleContentApi();

export default articleContentApi as ArticleContentApi;

/**
 * 时间
 */
export interface BaseTime {
  /**
   * 创建时间
   */
  createTime?: Date
  /**
   * 更新时间
   */
  updateTime?: Date
}

/**
 * 分页参数
 */
export interface PageParam {
  /**
   * 当前页
   */
  page?: number
  /**
   * 每一页展示的数据条数
   */
  pageSize?: number
}


/**
 * 分页响应参数
 */
export interface PageVo<T> {
  current: number,
  size: number,
  total: number,
  records: Array<T>
}

/**
 * 分页查询文章内容
 */
export interface ArticleContentPageParam extends PageParam {
  /**
   * 标题
   */
  title?: string
  /**
   * 内容分类:1鸿蒙 2 Java 3 web 4 运维
   */
  contentCategory?: string
  /**
   * 平台分类:1学习平台 2面试题
   */
  platformCategory?: string
  /**
   * 难度分类:1 简单 2 中等 3 困难
   */
  difficultyCategory?: string
}

/**
 * 分页查询最新文章内容入参
 */
export interface ArticleContentNewPageParam extends PageParam {
  /**
   * 标题
   */
  title: string

}

/**
 * 分页查询最热文章内容入参
 */
export interface ArticleContentHotPageParam extends PageParam {
  /**
   * 标题
   */
  title: string

}

/**
 * 文章内容数据
 */
export interface ArticleContentData extends BaseTime {
  /**
   * 文章id
   */
  id: number
  /**
   * 用户头像
   */
  avatarUri: string
  /**
   * 用户昵称
   */
  nickname: string
  /**
   * 文章标题
   */
  title: string
  /**
   * 文章内容
   */
  content: string
  /**
   * 阅读数
   */
  readCount: number
  /**
   * 点赞数
   */
  likeCount: number
  /**
   * 收藏数
   */
  collectCount: number
  /**
   * 封面url
   */
  coverUrl: string
  /**
   * 内容分类:1鸿蒙 2 Java 3 web 4 运维
   */
  contentCategory: string
  /**
   * 平台分类:1学习平台 2面试题
   */
  platformCategory: string
  /**
   * 难度分类:1 简单 2 中等 3 困难
   */
  difficultyCategory: string
  /**
   * 用户是否点赞
   */
  isLike: boolean
  /**
   * 用户是否收藏
   */
  isCollect: boolean
  /**
   * 创建时间字符串格式
   */
  time: string
}

文章详情界面布局

当我们点击文章的话会跳转到文章详情页面,携带当前点击的文章id

这边路由我们使用的是router.push()

1、新建文章详情页面

在ets/views/Home下面新建ArticleInfo.ets文件

2、设计图
3、需求分析

整个文章详情页面呈现的是使用Column布局的,里面分为多行,其他最上面标题我们可以使用Navigation组件做,鸿蒙官方推荐的,下面的文章内容按理说是渲染的html格式(富文本)的,所以我们使用RichText组件,还有点赞和收藏按理说有两种状态(未点赞、点赞,未收藏、收藏),整体文章数据也是根据路由跳转传过来的文章id进行查询的文章数据。

4、封装富文本组件

在components目录下面新建LearnRichText.ets文件

复制代码
@Component
  export struct LearnRichText {
    // 富文本
    @Prop richTextContent: string = ""

    build() {
      Scroll() {
        RichText(`
                      <html>
                        <body>
                          <div style="font-size:54px">${this.richTextContent}</div>
                        <body>
                      </html>
                      `)
      }
      .layoutWeight(1)

    }
  }
5、整体代码
复制代码
import { ArticleContentData } from '../../api/ArticleContentApi.type';
import { ArticleExtraInfoComponent } from '../../components/ArticleExtraInfoComponent'
import { LearnRichText } from '../../components/LearnRichText';
import { LoadingComponent } from '../../components/LoadingComponent';
import { CommonConstant } from '../../contants/CommonConstant'
import { router } from '@kit.ArkUI';
import articleContentApi from '../../api/ArticleContentApi';
import { showToast } from '../../utils/Toast';

@Entry
  @Component
  struct ArticleInfo {
    // 文章数据数组
    @Prop articleInfo: ArticleContentData
    // 控制当前页面展示
    @State isShow: boolean = false
    // 文章id
    @State articleId: number = 1
    // 节流,防止用户重复点击
    isLoad: boolean = false

    /**
    * 生命周期函数
    */
    async aboutToAppear() {
      // 获取路由传递的文章id
      const param = router.getParams() as object
      if (param) {
        this.articleId = param["articleId"] as number
        // 根据文章id查询文章数据
        this.articleInfo = await articleContentApi.getArticleContentInfo(this.articleId)
        // 展示数据
        this.isShow = true
      }
    }

    /**
   * 点赞
   * @param id
   */
    async likeArticle(id: number) {
      // 点赞或者取消点赞
      if (this.articleInfo.isLike) {
        // 取消点赞
        await articleContentApi.likeArticleContent(id)
        this.articleInfo.isLike = false
        this.articleInfo.likeCount--
        this.isLoad = false
        showToast('取消点赞成功')
      } else {
        // 点赞
        await articleContentApi.likeArticleContent(id)
        this.articleInfo.isLike = true
        this.articleInfo.likeCount++
        this.isLoad = false
        showToast('点赞成功')
      }
    }

    /**
   * 收藏
   * @param id
   */
    async collectArticle(id: number) {
      // 收藏或者取消收藏
      if (this.articleInfo.isCollect) {
        // 取消收藏
        await articleContentApi.collectArticleContent(id)
        this.articleInfo.isCollect = false
        this.articleInfo.collectCount--
        this.isLoad = false
        showToast('取消收藏成功')
      } else {
        // 收藏
        await articleContentApi.collectArticleContent(id)
        this.articleInfo.isCollect = true
        this.articleInfo.collectCount++
        this.isLoad = false
        showToast('收藏成功')
      }
    }

    build() {
      Navigation() {
        if (this.isShow) {
          Column({ space: 15 }) {
            Flex() {
              Text(this.articleInfo.title)
                .fontSize($r('app.float.common_font_size_medium'))
                .maxLines(3)
                .textOverflow({ overflow: TextOverflow.Ellipsis })
                .fontColor(Color.Black)
                .fontWeight(FontWeight.Medium)
            }

            Row({ space: 10 }) {
              // 头像
              Image(this.articleInfo.avatarUri)
                .width(30)
                .aspectRatio(1)
                .borderRadius(20)
              // 昵称
              Text(this.articleInfo.nickname)
                .fontSize($r('app.float.common_font_size_medium'))
                .width('80%')
                .maxLines(1)
                .textOverflow({ overflow: TextOverflow.Ellipsis })
            }.width(CommonConstant.WIDTH_FULL)

          // 展示阅读、点赞、收藏数
          Row() {
            // 文章额外信息组件
            ArticleExtraInfoComponent({ articleInfo: this.articleInfo })
            Row({ space: 15 }) {
              // 点赞
              Image(this.articleInfo.isLike ? $r('app.media.icon_like_selected') : $r('app.media.icon_like_default'))
                .width(15)
                .onClick(() => {
                  // 点赞
                  if (!this.isLoad) {
                    this.isLoad = true
                    this.likeArticle(this.articleInfo.id)
                  }
                })
              // 收藏
              Image(this.articleInfo.isCollect ? $r('app.media.icon_collect_selected') :
              $r('app.media.icon_collect_default')).width(15)
                .onClick(() => {
                  // 收藏
                  if (!this.isLoad) {
                    this.isLoad = true
                    this.collectArticle(this.articleInfo.id)
                  }
                })
            }
          }.width(CommonConstant.WIDTH_FULL)
          .justifyContent(FlexAlign.SpaceBetween)

        }.padding($r('app.float.common_padding'))

        // 分割线
        Divider()
          .strokeWidth((4))
          .color('#e6f2fe')
        // 内容正文
        LearnRichText({ richTextContent: this.articleInfo.content })
          .padding($r('app.float.common_padding'))
      } else {
        // 加载组件
        LoadingComponent()
      }
    }
    .height(CommonConstant.HEIGHT_FULL)
    .width(CommonConstant.WIDTH_FULL)
    .title($r('app.string.article_info_title'))
    .titleMode(NavigationTitleMode.Mini)
    .mode(NavigationMode.Stack)
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])

  }
}
6、注意事项

当前系统除了登录、分页查询文章等部分接口,其他接口功能都是需要登录之后才可以使用的,这就是系统的权限控制,当前查询文章详情、收藏、点赞功能是需要登录得,未登录状态下使用是报错的。

相关推荐
Bruce_Liuxiaowei5 小时前
HarmonyOS Next~鸿蒙系统架构设计解析:分层、模块化与智慧分发的技术革新
华为·harmonyos
幽蓝计划6 小时前
鸿蒙Next开发实战教程-使用WebSocket实现即时聊天
harmonyos·鸿蒙
鸿蒙布道师8 小时前
鸿蒙NEXT开发问题大全(不断更新中.....)
华为·harmonyos·鸿蒙·鸿蒙系统·huawei
二流小码农10 小时前
鸿蒙开发:远场通信服务rcp拦截器问题
android·ios·harmonyos
冬冬小圆帽10 小时前
鸿蒙保姆级教学
华为·harmonyos
别说我什么都不会10 小时前
OpenHarmony深度解读之分布式软总线:authmanager模块(4)/设备身份认证过程
分布式·嵌入式·harmonyos
BensionLZ14 小时前
ArkUI的样式二
harmonyos
别说我什么都不会14 小时前
OpenHarmony深度解读之分布式软总线:authmanager模块(3)/设备身份认证过程
分布式·嵌入式·harmonyos
AriesHoo15 小时前
Freadhub 适配原生鸿蒙(Harmony OS NEXT)
android·harmonyos