HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页面业务逻辑实现》
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
这样我们就可以使用库了
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()
}
执行效果如下
可以看到接口请求的数据已经成功显示
接下来我们实现搜索记录
我们已经定义
@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)
}
})
实现如下效果
然后针对清空事件先实现清空数据源和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()
}
}
}
)
实现效果如下
添加和清空都实现之后当我们退出页面再进入,搜索记录还要保存,我们还需要一个初始化获取数据的方法
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;
returnrgb(${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 联系官网客服。
有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html