玩安卓-鸿蒙版 二 首页横幅、搜索、跳转链接功能

本篇涉及组件TextInput、Image、Menu、Swiper、Web、自定义组件、路由跳转传参、POST请求

1.首页横幅

Swiper组件内部需要放其他内容组件,且需要设置宽高100%。

Image显示网络图片,直接设置图片链接即可。

复制代码
      Swiper(){
        ForEach(this.bannerData,(data:Datum,index:number)=>{
          Image(data.imagePath)
            .width('100%')
            .height('100%')
            .onClick(()=>{
              console.log("Swiper onClick link "+data.url)
              router.pushUrl({
                url:"pages/WebPage",
                params:{data:data.url}
              })
            })
        })
      }
      .width('100%')
      .height(150)

2.搜索框

placeholder是提示词,text就是输入框已存在的内容,通过onChange监听输入内容。

然后同步bindMenu添加菜单,为了做搜索热词功能

复制代码
        TextInput({placeholder:"输入搜索关键词",text:this.searchContent})
          .width(270)
          .height(40)
          .margin({top:10,bottom:10})
          .backgroundColor(Color.White)
          .bindMenu(
            this.searchKey()
          )
          .onChange((value: string) => {
            this.searchContent = value;
          })

  @Builder
  searchKey(){
    Menu(){
      ForEach(this.searchKeyData,(data:SearchKeyDataBean,index:number)=>{
        MenuItem({"content":data.name})
          .onClick(()=>{
            this.searchContent = data.name
          })
      })
    }
  }

输入完后,点击按钮确认搜索,跳转到搜索页。

复制代码
        Button("搜索")
          .margin({left:10,right:10})
          .onClick(()=>{
            console.log("searchContent "+this.searchContent)
            router.pushUrl({
              url:"pages/SearchListPage",
              params:{data:this.searchContent}
            })
          })

3.搜索页

搜索页内容就是一个列表,和首页一样,区别是获取搜索列表是通过POST请求,需要在method指定post请求,且在extraData写入post传参

复制代码
    let httpRequest = http.createHttp();
    httpRequest.request("https://www.wanandroid.com/article/query/"+this.page+"/json", {method: http.RequestMethod.POST,extraData: "k="+this.searchKey,}, (err, data) => {
      if (!err) {
        console.log("SearchListPage data.result:"+data.result.toString())
        let welcome: Welcome = JSON.parse(data.result.toString());
        if(welcome && welcome.data && welcome.data.datas && welcome.data.datas.length > 0){
          this.dataList = this.dataList.concat(welcome.data.datas)
          this.page++;
        }
      } else {
      }
      this.state = RequestState.END;
    })

4.列表和横幅都能点击跳转到网页

使用Web组件,传网址给src,controller创建一个默认的即可

复制代码
      Web({
        src: this.url,
        controller: this.webviewController
      })

然后写一个标题栏能返回,能标题栏在搜索页也要使用,所以做了一个自定义组件,只用@Component描述

复制代码
@Component
export struct TitleBar {
  private title = '';

  build() {
    Column() {
      Row() {
        Image($r('app.media.ic_back'))
          .width(20)
          .height(20)
          .margin({ left: 26 })
          .objectFit(ImageFit.Contain)
          .onClick(() => {
            router.back()
          })
          .backgroundColor(Color.Blue)
          .id('backBtn')
        Text(this.title)
          .fontSize(20)
          .layoutWeight(1)
          .margin({ left: 16 })
          .align(Alignment.Start)
        Blank()
      }
      .height(56)
      .width('100%')
    }
  }
}

5.完整代码如下:

复制代码
import { http } from "@kit.NetworkKit";
import { DataElement, Welcome } from "../bean/HomePageBean";
import { RequestState } from "../data/RequestState";
import { router } from "@kit.ArkUI";
import { Datum, HomeBannerBean } from "../bean/HomeBannerBean";
import { SearchKeyBean, SearchKeyDataBean } from "../bean/SearchKeyBean";


@Extend(Column)
function ColumnStyle(){
  .width("100%")
  .borderRadius(24)
  .backgroundColor(Color.White)
  .padding({left:12,right:12,bottom:4,top:4})
}


@Component
export struct HomePage{

  @State dataList:DataElement[] = [];
  @State bannerData:Datum[] = [];
  @State searchKeyData:SearchKeyDataBean[] = [];
  @State searchContent:string = ''

  aboutToAppear(): void {
    this.getHomeData();
    this.getHomeBanner();
    this.getSearchKey();
  }

  private page:number = 0;
  private state:RequestState = RequestState.INIT;
  private lastIndex = 0;
  getHomeData(){
    this.state = RequestState.REQUESTING;
    let httpRequest = http.createHttp();
    httpRequest.request("https://www.wanandroid.com/article/list/"+this.page+"/json", {}, (err, data) => {
      if (!err) {
        console.log("HomePage data.result:"+data.result.toString())
        let welcome: Welcome = JSON.parse(data.result.toString());
        if(welcome && welcome.data && welcome.data.datas && welcome.data.datas.length > 0){
          this.dataList = this.dataList.concat(welcome.data.datas)
          this.page++;
        }
      } else {
      }
      this.state = RequestState.END;
    })
  }

  getHomeBanner(){
    let httpRequest = http.createHttp();
    httpRequest.request("https://www.wanandroid.com/banner/json", {}, (err, data) => {
      if (!err) {
        console.log("HomePage data.result:"+data.result.toString())
        let welcome: HomeBannerBean = JSON.parse(data.result.toString());
        this.bannerData = welcome.data;
      } else {
      }
      this.state = RequestState.END;
    })
  }


  getSearchKey(){
    let httpRequest = http.createHttp();
    httpRequest.request("https://www.wanandroid.com/hotkey/json", {}, (err, data) => {
      if (!err) {
        console.log("HomePage data.result:"+data.result.toString())
        let welcome: SearchKeyBean = JSON.parse(data.result.toString());
        this.searchKeyData = welcome.data;
      } else {
      }
      this.state = RequestState.END;
    })
  }

  @Builder
  searchKey(){
    Menu(){
      ForEach(this.searchKeyData,(data:SearchKeyDataBean,index:number)=>{
        MenuItem({"content":data.name})
          .onClick(()=>{
            this.searchContent = data.name
          })
      })
    }
  }

  build() {
    Column(){
      Row(){
        TextInput({placeholder:"输入搜索关键词",text:this.searchContent})
          .width(270)
          .height(40)
          .margin({top:10,bottom:10})
          .backgroundColor(Color.White)
          .bindMenu(
            this.searchKey()
          )
          .onChange((value: string) => {
            this.searchContent = value;
          })
        Button("搜索")
          .margin({left:10,right:10})
          .onClick(()=>{
            console.log("searchContent "+this.searchContent)
            router.pushUrl({
              url:"pages/SearchListPage",
              params:{data:this.searchContent}
            })
          })
      }

      Swiper(){
        ForEach(this.bannerData,(data:Datum,index:number)=>{
          Image(data.imagePath)
            .width('100%')
            .height('100%')
            .onClick(()=>{
              console.log("Swiper onClick link "+data.url)
              router.pushUrl({
                url:"pages/WebPage",
                params:{data:data.url}
              })
            })
        })
      }
      .width('100%')
      .height(150)
      List(){
        if(this.dataList){
          ForEach(this.dataList,(data:DataElement,index:number)=>{
            ListItem(){
              Column(){
                Text(data.title)
                  .height(48)
                  .fontSize(14)
                  .width('100%')
                  .textAlign(TextAlign.Start)
                  .fontColor($r('app.color.font_color_shallow'))
                  .padding({bottom:4,top:4,left:24})
                  .maxLines(1)
                Row(){
                  Text("分享人:"+data.author+"  分类:"+data.chapterName+"/"+data.superChapterName+"  时间:"+data.publishTime)
                    .maxLines(1)
                    .fontSize(8)
                    .padding({bottom:4,left:24})
                }
                .width('100%')
                .justifyContent(FlexAlign.Start)
              }
              .ColumnStyle()
              .margin({top:6,bottom:6})
              .onTouch((event: TouchEvent | undefined) => {
                if (event) {
                  console.log("event.type "+event.type+" event.y "+event.touches[0].y)
                  //判断加载更多,需要当前item展示到最后,并且当前请求结束,且往上拉了一段距离
                  if(event.type == TouchType.Up && event.touches[0].y < -100 && this.state == RequestState.END && this.lastIndex == this.dataList.length-1){
                    this.getHomeData();
                  }
                }
              })
            }.onClick(()=>{
              console.log("onClick link "+data.link)
              router.pushUrl({
                url:"pages/WebPage",
                params:{data:data.link}
              })
            })
          })
        }
      }
      .onScrollIndex((start:number,end:number)=>{
        //可以获取到当前屏幕第一个可见item和最后一个可见item
        console.log("onScrollIndex start "+start+" end "+end)
        this.lastIndex = end;
      })

    }
  }
}

import { http } from "@kit.NetworkKit";
import { DataElement, Welcome } from "../bean/HomePageBean";
import { RequestState } from "../data/RequestState";
import { router } from "@kit.ArkUI";
import { TitleBar } from "../view/TitleBar";


@Extend(Column)
function ColumnStyle(){
  .width("100%")
  .borderRadius(24)
  .backgroundColor(Color.White)
  .padding({left:12,right:12,bottom:4,top:4})
}


@Entry
@Component
export struct SearchListPage{

  @State dataList:DataElement[] = [];
  searchKey:string = ''

  aboutToAppear(): void {
    let params: Record<string, Object> = router.getParams() as Record<string, Object>;
    this.searchKey = params['data'] as string;
    this.getHomeData();
  }

  private page:number = 0;
  private state:RequestState = RequestState.INIT;
  private lastIndex = 0;
  getHomeData(){
    this.state = RequestState.REQUESTING;
    let httpRequest = http.createHttp();
    httpRequest.request("https://www.wanandroid.com/article/query/"+this.page+"/json", {method: http.RequestMethod.POST,extraData: "k="+this.searchKey,}, (err, data) => {
      if (!err) {
        console.log("SearchListPage data.result:"+data.result.toString())
        let welcome: Welcome = JSON.parse(data.result.toString());
        if(welcome && welcome.data && welcome.data.datas && welcome.data.datas.length > 0){
          this.dataList = this.dataList.concat(welcome.data.datas)
          this.page++;
        }
      } else {
      }
      this.state = RequestState.END;
    })
  }


  build() {
    Column(){
      TitleBar({title:this.searchKey})
      List(){
        if(this.dataList){
          ForEach(this.dataList,(data:DataElement,index:number)=>{
            ListItem(){
              Column(){
                Text(data.title)
                  .height(48)
                  .fontSize(14)
                  .width('100%')
                  .textAlign(TextAlign.Start)
                  .fontColor($r('app.color.font_color_shallow'))
                  .padding({bottom:4,top:4,left:24})
                  .maxLines(1)
                Row(){
                  Text("分享人:"+data.author+"  分类:"+data.chapterName+"/"+data.superChapterName+"  时间:"+data.publishTime)
                    .maxLines(1)
                    .fontSize(8)
                    .padding({bottom:4,left:24})
                }
                .width('100%')
                .justifyContent(FlexAlign.Start)
              }
              .ColumnStyle()
              .margin({top:6,bottom:6})
              .onTouch((event: TouchEvent | undefined) => {
                if (event) {
                  console.log("event.type "+event.type+" event.y "+event.touches[0].y)
                  //判断加载更多,需要当前item展示到最后,并且当前请求结束,且往上拉了一段距离
                  if(event.type == TouchType.Up && event.touches[0].y < -100 && this.state == RequestState.END && this.lastIndex == this.dataList.length-1){
                    this.getHomeData();
                  }
                }
              })
            }.onClick(()=>{
              console.log("onClick link "+data.link)
              router.pushUrl({
                url:"pages/WebPage",
                params:{data:data.link}
              })
            })
          })
        }
      }
      .onScrollIndex((start:number,end:number)=>{
        //可以获取到当前屏幕第一个可见item和最后一个可见item
        console.log("onScrollIndex start "+start+" end "+end)
        this.lastIndex = end;
      })

    }
    .backgroundColor($r('app.color.background_shallow_grey'))


  }
}

// renderMode.ets
import { webview } from '@kit.ArkWeb';
import { router } from '@kit.ArkUI';
import { TitleBar } from '../view/TitleBar';

@Entry
@Component
struct WebPage {
  private webviewController: WebviewController = new webview.WebviewController()
  @State url:string = ''
  aboutToAppear() {
    let params: Record<string, Object> = router.getParams() as Record<string, Object>;
    this.url = params['data'] as string;
  }
  build() {
    Column() {
      TitleBar()
      Web({
        src: this.url,
        controller: this.webviewController,
        renderMode: RenderMode.ASYNC_RENDER // 设置渲染模式
      })
        .width('100%')
        .height('100%')
    }
  }
}

/*
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import router from '@ohos.router'

// Page title bar
@Component
export struct TitleBar {
  private title = '';

  build() {
    Column() {
      Row() {
        Image($r('app.media.ic_back'))
          .width(20)
          .height(20)
          .margin({ left: 26 })
          .objectFit(ImageFit.Contain)
          .onClick(() => {
            router.back()
          })
          .backgroundColor(Color.Blue)
          .id('backBtn')
        Text(this.title)
          .fontSize(20)
          .layoutWeight(1)
          .margin({ left: 16 })
          .align(Alignment.Start)
        Blank()
      }
      .height(56)
      .width('100%')
    }
  }
}

export interface HomeBannerBean {
  data:      Datum[];
  errorCode: number;
  errorMsg:  string;
}

export interface Datum {
  desc:      string;
  id:        number;
  imagePath: string;
  isVisible: number;
  order:     number;
  title:     string;
  type:      number;
  url:       string;
}

export interface SearchKeyBean {
  data:      SearchKeyDataBean[];
  errorCode: number;
  errorMsg:  string;
}

export interface SearchKeyDataBean {
  id:      number;
  link:    string;
  name:    string;
  order:   number;
  visible: number;
}
相关推荐
Zz_waiting.31 分钟前
Javaweb - 14.6 - Vue3 数据交互 Axios
开发语言·前端·javascript·vue·axios
森之鸟41 分钟前
开发中使用——鸿蒙子页面跳转到指定Tab页面
harmonyos·鸿蒙
切糕师学AI42 分钟前
前后端分离架构中,Node.js的底层实现原理与线程池饥饿问题解析
前端·vue.js·node.js
妄小闲1 小时前
网页设计模板 HTML源码网站模板下载
前端·html
icebreaker1 小时前
tailwindcss 究竟比 unocss 快多少?
前端·css·github
卢叁1 小时前
Flutter之自定义TabIndicator
前端·flutter
每天吃饭的羊2 小时前
state和ref
前端·javascript·react.js
GEO_YScsn2 小时前
Vite:Next-Gen Frontend Tooling 的高效之道——从原理到实践的性能革命
前端·javascript·css·tensorflow
GISer_Jing2 小时前
滴滴二面(准备二)
前端·javascript·vue·reactjs
ningmengjing_2 小时前
webpack打包方式
前端·爬虫·webpack·node.js·逆向