【鸿蒙开发】英语单词页的开发–实现详细代码高亮和单词发音
文章目录
前言
本文主要介绍英语单词单词页开发,点击英语单词会播放单词发音,点击详细代码会对关键字高亮显示。
效果展示
一、提前学习几个小知识
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)
}
}