# 【鸿蒙开发】英语单词页的开发--实现详细代码高亮和单词发音

【鸿蒙开发】英语单词页的开发–实现详细代码高亮和单词发音



前言

本文主要介绍英语单词单词页开发,点击英语单词会播放单词发音,点击详细代码会对关键字高亮显示。


效果展示

在这里插入图片描述

一、提前学习几个小知识

1.怎么拿到对象的属性名称的数组

例如:我们怎么拿到[‘HTML5’,‘CSS3’,‘鸿蒙’]用来做筛选标题的显示

words: Record<string, WordItem[]> = {
  'HTML5': [
    {
      "en": "strong",
      "zh": "加粗标签",
      "code": "<strong>加粗内容</strong>"
    }
  ],
  'CSS3': [
    {
      "en": "color",
      "zh": "字体颜色",
      "code": "color: red;"
    }
  ],
  '鸿蒙': [
    {
      "en": "color",
      "zh": "字体颜色",
      "code": "color: red;"
    }
  ]
}
我们可以通过Object.keys(对象)=>对象的属性名组成的一个数组
Obkect.keys(this.words)=>['HTML5','CSS3','鸿蒙']

2.怎么读取本地rawfile文件-资源管理模块

//   通过资源管理模块读取rawfile下的文件
const mgr = getContext(this).resourceManager
//如果文件的根路径是rawfile,传文件的名字,如果不是则传路径
const res = mgr.getRawFileContentSync('word.json')

3.将二进制解码成字符串

const decode = new util.TextDecoder()
const str = decode.decodeToString(res)
this.words = JSON.parse(str)

二、完整代码

1.单词页代码

import { util } from '@kit.ArkTS'
import { webview } from '@kit.ArkWeb'
import { WordSoundDialog } from '../views/WordSoundDialog'

export interface WordItem {
  zh: string
  en: string
  code: string
}

@Entry
@Component
export struct WordPage {
  @State
  showTypeSheet: boolean = false // 控制当前阶段分类弹框
  @State
  showCodeSheet: boolean = false // 控制当前单词详细代码弹框
  @State
  currentType: string = 'HTML5' // 当前阶段名称
  @State
  loading: boolean = false
  // 单词数据
  @State
  words: Record<string, WordItem[]> = {}
  currentCode: string = ''
  scroller = new Scroller()

  aboutToAppear(): void {
    //   通过资源管理模块读取rawfile下的文件
    const mgr = getContext(this).resourceManager
    const res = mgr.getRawFileContentSync('word.json')
    //   将二进制解码成字符串
    const decode = new util.TextDecoder()
    const str = decode.decodeToString(res)
    this.words = JSON.parse(str)
    
  }

  // 单词分类弹窗
  @Builder
  typeSheetBuilder() {
    Column() {
      Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
        ForEach(Object.keys(this.words), (key: string, index) => {
          Button() {
            Text(key)
              .fontSize(14)
              .fontColor(key === this.currentType ? "#27AE60" : "#979797")
          }
          .backgroundColor("#f3f4f5")
          .padding({
            top: 6,
            right: 12,
            bottom: 6,
            left: 12
          })
          .margin({ right: 12, bottom: 12 })
          .onClick(() => {
            this.currentType = key
            this.showTypeSheet = false
            this.scroller.scrollTo({ yOffset: 0, xOffset: 0 })
          })
        })
      }
    }
    .padding({
      left: 16,
      right: 16,
      top: 8,
      bottom: 34
    })
  }

  controller = new webview.WebviewController()

  // 弹出单词用法弹窗
  @Builder
  codeSheetBuilder() {
    Stack() {
      Web({
        src: $rawfile('word.html'),
        controller: this.controller
      })
        .onPageEnd(() => {
        //实现关键字高亮
          this.controller.runJavaScript(`writeCode(${JSON.stringify(this.currentCode)})`)
        })
    }
    .padding({
      left: 16,
      right: 16,
      top: 8,
      bottom: 34
    })
  }

  wordEn = ''
  wordZh = ''
  dialog = new CustomDialogController({
    builder: WordSoundDialog({ wordEn: this.wordEn, wordZh: this.wordZh }),
    customStyle: true
  })

  build() {
    Navigation() {
      Column() {
        Row() {
          Column({ space: 4 }) {
            Text('词汇')
            Text(`${this.words[this.currentType]?.length} 个单词`)
              .fontSize(12)
              .fontColor("#666666")
          }
          .alignItems(HorizontalAlign.Start)

          Row() {
            Text(this.currentType)
              .fontSize(12)
              .fontColor("#979797")
            Image($r('sys.media.ohos_ic_public_arrow_down'))
              .width(16)
              .aspectRatio(1)
              .fillColor("#979797")
          }
          .onClick(() => this.showTypeSheet = true)
          .bindSheet($$this.showTypeSheet, this.typeSheetBuilder(), {
            height: 200,
            title: { title: '选择分类' }
          })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .padding(16)
        .border({ width: { top: 0.5 }, color: "#f3f4f5" })

        Divider()
          .strokeWidth(8)
          .color("#f3f4f5")

        List({ scroller: this.scroller }) {
          ForEach(this.words[this.currentType], (wordItem: WordItem) => {

            ListItem() {
              Row({ space: 6 }) {
                Image($r('sys.media.ohos_ic_public_sound'))
                  .width(20)
                  .aspectRatio(1)
                  .alignSelf(ItemAlign.Start)
                  .fillColor("#666666")
                  .onClick(() => {
                    this.wordEn = wordItem.en
                    this.wordZh = wordItem.zh
                    // 开启弹框读单词
                    this.dialog.open()
                  })
                Column({ space: 10 }) {
                  Text(wordItem.en)
                    .fontWeight(FontWeight.Bold)
                  Text(wordItem.zh)
                    .fontSize(14)
                    .fontColor("#666666")
                }
                .alignItems(HorizontalAlign.Start)
                .layoutWeight(1)

                Column({ space: 10 }) {
                  Row() {
                    Text('详细代码')
                      .fontSize(12)
                      .fontColor(wordItem.code ? "#979797" : '#dddddd')
                    Image($r('sys.media.ohos_ic_public_arrow_right'))
                      .width(16)
                      .aspectRatio(1)
                      .fillColor(wordItem.code ? "#979797" : '#dddddd')
                  }
                  // .alignSelf(ItemAlign.End)
                  .onClick(() => {
                    // 点击打开详细代码半模态框
                    this.showCodeSheet = true
                    this.currentCode = wordItem.code
                  })
                }
              }
              .padding(16)
            }
          })
        }
        .divider({
          strokeWidth: 0.5,
          color: "#f3f4f5"
        })
        .layoutWeight(1)
      }
      .width('100%')
      .height('100%')
      .bindSheet($$this.showCodeSheet, this.codeSheetBuilder, {
        height: 500,
        title: { title: '详细代码' }
      })
    }
    .title('单词页')
    .titleMode(NavigationTitleMode.Mini)
  }
}

2.播放单词弹出层

import { media } from "@kit.MediaKit"

@CustomDialog
export struct WordSoundDialog {
  controller: CustomDialogController // 必须要有的
  wordEn: string = '' // 英文单词
  wordZh: string = '' // 中文解释
  @State
  isGreen: boolean = false // 用来控制颜色切换的
  timer: number = -1
  streamId: number = -1
  player?: media.AVPlayer

  aboutToAppear() {
    this.startPlay()
  }

  aboutToDisappear(): void {
    this.stopPlay()
  }

  async startPlay() {
    //   创建一个播放器
    this.player = await media.createAVPlayer()
    //   监听播放状态
    this.player.on('stateChange', (state) => {
      if (state === 'initialized') {
        this.player!.prepare()
      }
      if (state === 'prepared') {
        this.player!.loop = true //循环播放
        this.player!.play()
      }
    })
    //   设置播放地址
    this.player.url = `https://dict.youdao.com/dictvoice?audio=${this.wordEn}&type=1`
  }

  stopPlay() {
    // this.player?.stop()
    this.player && this.player.stop()
  }

  build() {
    Column({ space: 10 }) {
      Row({ space: 10 }) {
        Text(this.wordEn)
          .fontSize(20)
          .fontColor(Color.White)
          .fontWeight(500)
        Image($r('app.media.icon_public_search'))
          .width(20)
          .aspectRatio(1)
          .fillColor(this.isGreen ? "#27AE60" : Color.White)
          .onAppear(() => {
            clearInterval(this.timer) // 清除之前的定时器
            this.timer = setInterval(() => { //新开一个定时器
              this.isGreen = !this.isGreen
            }, 500)
          })
          .onDisAppear(() => {
            clearInterval(this.timer) //清除定时器
          })
          .animation({ duration: 300 })
      }

      Text(this.wordZh)
        .fontColor(Color.White)
    }
    .constraintSize({ minWidth: 175 })
    .padding({ left: 16, right: 16 })
    .height(90)
    .borderRadius(45)
    .backgroundColor('#8f000000')
    .justifyContent(FlexAlign.Center)
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值