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

本篇涉及组件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;
}
相关推荐
Nejosi_念旧2 分钟前
包文件分析器 Webpack Bundle Analyzer
前端·webpack·node.js
noravinsc31 分钟前
vue request 发送formdata
前端·javascript·vue.js
Libby博仙40 分钟前
VUE3 vite下的axios跨域
前端·javascript·vue.js·前端框架·node.js
剪刀石头布啊1 小时前
Web Animation API
前端
资深前端之路1 小时前
react面试题一
前端·javascript·react.js
肖老师xy1 小时前
css动画水球图
前端·css
LBJ辉1 小时前
2. CSS 中的单位
前端·css
wang.wenchao2 小时前
十六进制文本码流转pcap(text2pcap)
前端·css
浪浪山小白兔2 小时前
HTML 基础入门:核心标签全解析
前端·javascript·html