HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页面业务逻辑实现》

发布于 1周前 作者 vueper 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页面业务逻辑实现》

在上一小节我们已经实现了搜索页的部分功能和UI并且都填充了本地数据,现在我们完善一下业务逻辑,把本地数据修改为接口请求

开发准备

我们已经完成了简单的数据加载,现在需要做的有:


1.接口请求,获取热门搜索数据
2.处理接口请求的数据,创建实体替换本地数据
3.完善业务逻辑,实现搜索记录的本地存储和记录清空

接口请求我们使用的依旧是axios,下面是本次使用到的接口

搜索热词

展示热门搜素模块的数据列表

https://www.wanandroid.com//hotkey/json

方法:GET 参数:无<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

搜索记录的处理我们选择使用mmkv 

在《OpenHarmony三方库中心仓》我们可以直接搜索到这个库

选择@tencent/mmkv

然后在项目entry包下的oh-package.json5的dependencies中引入mmkv库

“dependencies”: {
@tencent/mmkv”: “^1.3.9”,
}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

引入成功后点击sync now

cke_137419.png

这样我们就可以使用库了

ps:mmkv的简单使用,我们把记录转换成string字符串进行存储,实现如下

ability初始化mmkv

import { MMKV } from @tencent/mmkv’;

export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { let appCtx = this.context.getApplicationContext(); let mmkvRootDir = MMKV.initialize(appCtx); console.info(‘mmkv rootDir: ‘, mmkvRootDir); …… }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

首先在使用页面组件外引入和定义

import { MMKV } from ‘@tencent/mmkv’;
let mmkv = MMKV.defaultMMKV();

当我们执行搜索后,通过encodeString进行存储

private saveSearchTxt(txt:string){

mmkv.encodeString(‘searchTxt’, txt);
console.info(‘string = ‘, mmkv.decodeString(‘searchTxt’));
}
在搜索页面通过decodeString进行查询
mmkv.decodeString(‘searchTxt’) as string

点击清空调用removeValueForKey

mmkv.removeValueForKey(‘searchTxt’);

代码实现

首先我们进行搜索热词接口的处理,因为是get请求所以直接在浏览器进行接口测试

https://www.wanandroid.com/hotkey/json

拿到数据后生成对应的实体

export interface Category {
id: number;
link: string;
name: string;
order: number;
visible: boolean;
}


export interface CategoriesResponse {
data: Category[];
errorCode: number;
errorMsg: string;
}

接下来在搜索页面执行请求方法

先定义变量接收接口返回的数组数据

@State hotList:Category[]=[]

private getHotKey(){
axios.get<string, AxiosResponse<CategoriesResponse>, null>(BASE_URL+HOT_KEY)
.then((response: AxiosResponse<CategoriesResponse>)=> {
if (response.data.errorCode==0) {
this.hotList=response.data.data
}
})
.catch((error: AxiosError)=> {

console.info(JSON.stringify(error));
})
.then(()=> {

});
}

页面打开就要加载所以在生命周期方法中调用

aboutToAppear(): void {

  this.getHotKey()

}

执行效果如下

cke_349272.png

可以看到接口请求的数据已经成功显示

接下来我们实现搜索记录

我们已经定义

@State text: string = ‘’

点击搜索拿到text的值,放入搜索列表的数据源中,同时存入mmkv

private saveSearchTxt(txt:string){
this.txtList.push(txt)
let singleString: string = this.txtList.join(’,’);
mmkv.encodeString(‘searchTxt’, singleString);
}

在搜索处调用

Text(“搜索”)
.fontSize(16)
.fontColor("#1296db")
.backgroundColor(Color.White)
.padding({left:13,right:13,top:5,bottom:5})
.borderRadius(10)
.onClick(()=>{
if (this.text.trim()==’’) {
showToast(“搜索内容不能为空”)
}else {
this.saveSearchTxt(this.text)
}
})

实现如下效果

cke_496954.png

然后针对清空事件先实现清空数据源和mmkv的方法

private removeList(){
this.txtList.length=0
mmkv.removeValueForKey(‘searchTxt’);
}

清空操作是一个危险操作,用户可能存在误触所以点击清空时我们先用一个弹窗来提醒用户,二次确认后执行清空

AlertDialog.show(
{
title: ‘删除数据’,
subtitle: ‘’,
message: ‘确认要清空搜索记录吗?’,
autoCancel: true,
alignment: DialogAlignment.Bottom,
gridCount: 4,
offset: { dx: 0, dy: -20 },
primaryButton: {
value: ‘取消’,
action: () => {

}
},
secondaryButton: {
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
value: ‘确认’,
action: () => {
this.removeList()
}
},
cancel: () => {
console.info(‘弹窗被关闭’)
},
onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
dismissDialogAction.dismiss()
}
if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
dismissDialogAction.dismiss()
}
}
}
)

实现效果如下

cke_616790.png

添加和清空都实现之后当我们退出页面再进入,搜索记录还要保存,我们还需要一个初始化获取数据的方法

private initTxtList(){
let textList=mmkv.decodeString(‘searchTxt’) as string
if (textList!=undefined) {
let stringArray: string[] =textList.split(’,’);
this.txtList=stringArray
}
}

在生命周期里调用即可

aboutToAppear(): void {
this.initTxtList()

}

这样我们的搜索页面的业务逻辑就实现了
 

完整代码如下:

import axios, { AxiosError, AxiosResponse } from ‘@ohos/axios’
import { BASE_URL, HOT_KEY } from ‘./http/base_url’
import { CategoriesResponse, Category } from ‘./modle/HotKeyList’
import showToast from ‘./utils/ToastUtils’
import { MMKV } from ‘@tencent/mmkv’;
let mmkv = MMKV.defaultMMKV();

@Entry
@Component
struct SearchPage {
@State text: string = ‘’
controller: TextInputController = new TextInputController()
@State hotList:Category[]=[]
@State txtList:string[]=[]

aboutToAppear(): void {
this.getHotKey()
this.initTxtList()

}
build() {
Column(){
Row(){
Image($r(‘app.media.back’))
.height(25)
.width(25)

TextInput({ text: this.text, placeholder: ‘发现更多干货’, controller: this.controller })
.placeholderColor(Color.White)
.placeholderFont({ size: 16, weight: 400 })
.caretColor(Color.White)
.width(200)
.fontSize(16)
.fontColor(Color.White)
.onChange((value: string) => {
this.text = value
})
Text(“搜索”)
.fontSize(16)
.fontColor("#1296db")
.backgroundColor(Color.White)
.padding({left:13,right:13,top:5,bottom:5})
.borderRadius(10)
.onClick(()=>{
if (this.text.trim()==’’) {
showToast(“搜索内容不能为空”)
}else {
this.saveSearchTxt(this.text)
}
})

}
.justifyContent(FlexAlign.SpaceBetween)
.width(‘100%’)
.padding({top:10,bottom:10,left:15,right:15})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
.backgroundColor("#1296db")
Text(“热门搜索”)
.width(‘100%’)
.fontSize(18)
.fontColor("#ff25e0f8")
.padding({left:15,top:15})

Flex({wrap:FlexWrap.Wrap}){
ForEach(this.hotList,(item:Category,index:number)=>{
Text(item.name)
.backgroundColor("#ffe7e5e5")
.fontColor(this.generateRandomRGBColor())
.fontSize(16)
.padding(10)
.margin({top:10,left:10})
.borderRadius(5)

})
}

Row(){
Text(“搜索历史”)
.fontSize(18)
.fontColor("#ff25e0f8")

Text(“清空”)
.fontSize(18)
.fontColor("#ff989b9b")
.onClick(()=>{
AlertDialog.show(
{
title: ‘删除数据’,
subtitle: ‘’,
message: ‘确认要清空搜索记录吗?’,
autoCancel: true,
alignment: DialogAlignment.Bottom,
gridCount: 4,
offset: { dx: 0, dy: -20 },
primaryButton: {
value: ‘取消’,
action: () => {

}
},
secondaryButton: {
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
value: ‘确认’,
action: () => {
this.removeList()
}
},
cancel: () => {
console.info(‘弹窗被关闭’)
},
onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
dismissDialogAction.dismiss()
}
if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
dismissDialogAction.dismiss()
}
}
}
)
})
}
.width(‘100%’)
.justifyContent(FlexAlign.SpaceBetween)
.padding({left:15,right:15})
.margin({top:30})
List(){
ForEach(this.txtList,(item:string)=>{
ListItem(){
Text(item)
.fontColor("#ffa09a9a")
.padding({left:15})
.margin({top:10})
}

})
}

}


}
generateRandomRGBColor(minBrightness: number = 5): string {
const r = Math.floor(Math.random() * (256 - minBrightness)) + minBrightness;
const g = Math.floor(Math.random() * (256 - minBrightness)) + minBrightness;
const b = Math.floor(Math.random() * (256 - minBrightness)) + minBrightness;
return rgb(${r},${g},${b});
}

private getHotKey(){
axios.get<string, AxiosResponse<CategoriesResponse>, null>(BASE_URL+HOT_KEY)
.then((response: AxiosResponse<CategoriesResponse>)=> {
if (response.data.errorCode==0) {
this.hotList=response.data.data
}
})
.catch((error: AxiosError)=> {

console.info(JSON.stringify(error));
})
.then(()=> {

});
}

private saveSearchTxt(txt:string){
this.txtList.push(txt)
let singleString: string = this.txtList.join(’,’);
mmkv.encodeString(‘searchTxt’, singleString);
}
private initTxtList(){
let textList=mmkv.decodeString(‘searchTxt’) as string
if (textList!=undefined) {
let stringArray: string[] =textList.split(’,’);
this.txtList=stringArray
}
}
private removeList(){
this.txtList.length=0
mmkv.removeValueForKey(‘searchTxt’);
}
}



关于HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页面业务逻辑实现》的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。

1 回复

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

回到顶部