HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页实现搜索列表展示和查看》

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

HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页实现搜索列表展示和查看》
HarmonyOS的隐私保护政策非常严格,让我对个人信息的安全更加有信心。

关于HarmonyOS 鸿蒙Next 玩转HarmonyOS(二) 首页《搜索页实现搜索列表展示和查看》的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。

1 回复

上一节我们已经实现了搜索页面的展示、查询、删除等业务逻辑,那我们针对这些模块所做的操作一定是要提交数据库做数据查询的,根据我们的热词、记录、搜索输入内容来进行查询,然后展示列表给用户查看,最后点击详情查看详细内容,这一节我们来实现这个逻辑

开发准备

在这一节我们要实现的功能有关键字查询,列表展示,内容查看

由此可得我们要使用的主要技术有

1.axios 进行携带关键词的请求(上一节我们已经对输入的关键字进行了存储和获取操作直接使用即可)

2.list 列表展示

3.跳转展示详情,因为详情都是通过url查看,所以要使用webview,在首页列表我们已经实现这个功能所以可以直接使用

要请求的接口如下

https://www.wanandroid.com/article/query/0/json

方法:POST 参数: 页码:拼接在链接上,从0开始。 k : 搜索关键词 <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

注:该接口支持传入 page_size 控制分页数量,取值为[1-40],不传则使用默认值,一旦传入了 page_size,后续该接口分页都需要带上,否则会造成分页读取错误。

注意:支持多个关键词,用空格隔开

代码实现

首先在搜索页面把拿到的关键字通过router传到搜索列表展示页面

我们先创建一个公共的方法,因为我们要传递参数的位置有搜索按钮,热词列表点击,搜索记录点击

private PushKey(key:string){

router.pushUrl({url:“pages/SearchContentListPage”,params:new routerParams(key)})
}

我们只需要在点击的地方调用方法即可

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)
this.PushKey(this.text)
}
})

通过router我们把关键字传输到SearchContentListPage页面,这个页面也就是我们要通过拿到关键字进行请求操作展示列表的界面,我们在这个页面接收传递的参数

ps:router传递参数我们传递过来一个对象,所以创建了一个对象

export class routerParams {
data1:string

constructor(str:string) {
this.data1 = str

}
}

通过router.getparams拿到关键字然后赋给定义的变量

@State keys: string = ‘’;
this.keys= (router.getParams() as routerParams).data1

然后进行post请求拿到数据

private pushKeySearch(key: string){


axios({ url: BASE_URL+"/"+QUERY_KEY, method: ‘post’, params: { k:key} })
.then((response: AxiosResponse<HomeResponse>) => {
let responseObject:HomeResponse = JSON.parse(JSON.stringify(response.data));
if (responseObject.errorCode==0) {
this.newsList=response.data.data.datas
}else {
showToast(responseObject.errorMsg)
}
})
.catch((error:Error) => {
console.info(JSON.stringify(error));
});
}

接口请求时发现数据源跟首页的列表是一样的,所以直接用一个实体类去接收

@State newsList:Article[]=[]

通过定义变量拿到返回的数组数据,我们把数据放到list中展示出来,在进行数据展示的时候发现数据源是这种格式

 “title”: “【Android 13源码分析】应用启动<em class=‘highlight’>动画</em>-app_transition-1”,

可以看到字段中都有 <em class=‘highlight’>和</em> 我们用正则表达式去除掉先

stripHighlightEmphasis(text: string): string {
const regex =/<em class=‘highlight’>|</em>/g;
return text.replace(regex, ‘’);
}

lits代码如下

List({space:10}){
ForEach(this.newsList,(item:Article,index:number)=>{
ListItem(){
Column(){
Row(){
Text(this.setTagText(item))
.fontSize(14)
.padding(5)
.border({width:this.setTagText(item)!=’’?1:0,color:this.setTagText(item)!=’’?(this.setTagText(item)==‘新’?"#ffd0183d":"#ff43faab"):null,radius:4})

Text(item.shareUser)
.fontSize(14)
.fontColor("#999999")

Blank()
Text(this.formatTimestamp(item.publishTime))
.fontColor("#999999")
.fontSize(14)
}
.justifyContent(FlexAlign.SpaceBetween)
.width(‘100%’)

Text(this.stripHighlightEmphasis(item.title))
.fontSize(16)
.margin({top:10})

Text(){
Span(item.superChapterName)
.fontSize(14)
.fontColor("#999999")
Span(" / “)
.fontSize(14)
.fontColor(”#999999")
Span(item.chapterName)
.fontSize(14)
.fontColor("#999999")
}
.margin({top:10})
}
.alignItems(HorizontalAlign.Start)
.width(‘100%’)
.padding({left:10,right:10})
.onClick(()=>{
router.pushUrl({
url:“pages/WebDetailsPage”,
params:item})
})
}
})
}

因为这里的数据跟首页的列表相似所以我们的大部分代码还有跳转都可以复用(ps:因为数据源相同业务逻辑也类似所以可以把这个list改为一个自定义组件,这样两个页面去使用可以优化代码量)

执行代码后如下所示

cke_291296.png

这样我们搜索有关的内容就全部实现了

完整代码如下:

import router from ‘@ohos.router’;
import axios, { AxiosResponse } from ‘@ohos/axios’;
import { BASE_URL, QUERY_KEY, USER_LOGIN } from ‘./http/base_url’;
import { Article, HomeResponse } from ‘./modle/HomeList’;
import { ServerResponse } from ‘./modle/LoginResult’;
import { routerParams } from ‘./SearchHome’;
import showToast from ‘./utils/ToastUtils’;
import { BaseToolBar } from ‘./view/BaseToolBar’;

@Entry
@Component
struct SearchContentListPage {
@State keys: string = ‘’;
@State newsList:Article[]=[]

aboutToAppear(): void {
this.keys= (router.getParams() as routerParams).data1
this.pushKeySearch( (router.getParams() as routerParams).data1)

}
build() {
Column() {
BaseToolBar({title:this.keys,backIsShow:true,backCall:()=>{
router.back()
},backRightImgIsShow:false})
List({space:10}){
ForEach(this.newsList,(item:Article,index:number)=>{
ListItem(){
Column(){
Row(){
Text(this.setTagText(item))
.fontSize(14)
.padding(5)
.border({width:this.setTagText(item)!=’’?1:0,color:this.setTagText(item)!=’’?(this.setTagText(item)==‘新’?"#ffd0183d":"#ff43faab"):null,radius:4})

Text(item.shareUser)
.fontSize(14)
.fontColor("#999999")

Blank()
Text(this.formatTimestamp(item.publishTime))
.fontColor("#999999")
.fontSize(14)
}
.justifyContent(FlexAlign.SpaceBetween)
.width(‘100%’)

Text(this.stripHighlightEmphasis(item.title))
.fontSize(16)
.margin({top:10})

Text(){
Span(item.superChapterName)
.fontSize(14)
.fontColor("#999999")
Span(" / “)
.fontSize(14)
.fontColor(”#999999")
Span(item.chapterName)
.fontSize(14)
.fontColor("#999999")
}
.margin({top:10})
}
.alignItems(HorizontalAlign.Start)
.width(‘100%’)
.padding({left:10,right:10})
.onClick(()=>{
router.pushUrl({
url:“pages/WebDetailsPage”,
params:item})
})
}
})
}
}
.height(‘100%’)
.width(‘100%’)
}

private pushKeySearch(key: string){


axios({ url: BASE_URL+"/"+QUERY_KEY, method: ‘post’, params: { k:key} })
.then((response: AxiosResponse<HomeResponse>) => {
let responseObject:HomeResponse = JSON.parse(JSON.stringify(response.data));
if (responseObject.errorCode==0) {
this.newsList=response.data.data.datas
}else {
showToast(responseObject.errorMsg)
}
})
.catch((error:Error) => {
console.info(JSON.stringify(error));
});
}

private setTagText(item:Article):string{
let txt:string=’’
if (item.tags.length===1) {
txt=item.tags[0].name
}else {
if (this.isWithinLast24Hours(item.publishTime)) {
txt=‘新’
}else {
txt=’’
}
}

return txt
}

isWithinLast24Hours(timestampMillis: number): boolean {
const now = new Date();
const targetTime = new Date(timestampMillis);
const timeDiff = now.getTime() - targetTime.getTime();
const oneDayInMillis = 24 * 60 * 60 * 1000; // 24 hours in milliseconds

return timeDiff < oneDayInMillis && timeDiff >= 0;
}


formatTimestamp(timestampMillis: number): string {
const date = new Date(timestampMillis);

const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, ‘0’); // Months are zero-based
const day = String(date.getDate()).padStart(2, ‘0’);
const hour = String(date.getHours()).padStart(2, ‘0’);
const minute = String(date.getMinutes()).padStart(2, ‘0’);

return ${year}-${month}-${day} ${hour}:${minute};
}

stripHighlightEmphasis(text: string): string {
const regex =/<em class=‘highlight’>|</em>/g;
return text.replace(regex, ‘’);
}
}

回到顶部