相关资源:
- 图片素材📎图片素材.zip
接口文档
1. HTTP 数据请求
什么是HTTP数据请求:
(鸿蒙)应用软件可以通过(鸿蒙)系统内置的 http 模块 和 Axios,通过 HTTP 协议和服务器进行通讯
学习核心Http请求技术:
- Http模块 - 属于鸿蒙内置模块,安全性较高,如果是银行项目都是Http模块
- Axios模块(第三方) - C端(B端)项目可以用开源的axios模块
- 鸿蒙、android,iOS 的原生App开发无需考虑跨域问题
2. http模块基本用法
咱们来看看 http 模块如何使用
传送门
// 1. 导入模块
import { http } from '@kit.NetworkKit'
// 2. 创建请求对象
const request = http.createHttp();
// 3. 调用request方法进行服务器请求
request.request('Url地址?key1=value1&key2=value2',{
//GET(默认请求方式)、POST、PUT、DELETE,
method:http.RequestMethod.GET, // 如果是Get之外的请求->必填
//OBJECT:服务器返回数据类型自动转换成对象(方便调用)
// STRING:服务器返回的数据是一个字符串
expectDataType:http.HttpDataType.OBJECT, // 必填
// 设置请求头为json格式
header:{ // 选填:Get请求有参数时+POST+PUT请求必填,其他选填
'Content-Type':'application/json'
},
// 用来给Get,POST,PUT携带参数用
// Get请求: url?key=value
// POST,PUT请求:在请求体中携带
// 选填:Get请求有参数时+POST+PUT请求必填,其他选填
extraData:{
// 'key':'value' //具体值来自接口文档
pname:'湖南省'
}
})
.then((res:http.HttpResponse)=>{
// 成功响应
console.log(JSON.stringify(res.result))
})
.catch((err:Error)=>{
// 失败处理
console.log(JSON.stringify(err))
})
注意:
- 预览器 和 模拟器 以及真机都可以发送请求
-
- 预览器无需配置网络权限即可成功发送请求
- 【模拟器】和【真机】需要配置网络权限才能成功发送请求
- 配置权限 -> 详细权限设置,可以参考 声明权限 权限列表
-
- 需要在项目的src/main/module.json5(模块配置)下添加如下代码
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}
2.1. Get请求演示
获取一条随机笑话:https://api-vue-base.itheima.net/api/joke
import { http } from '@kit.NetworkKit'
@Entry
@Component
struct Notebook_use {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(20)
Button('看笑话')
.onClick(() => {
const req = http.createHttp()
req.request('https://api-vue-base.itheima.net/api/joke',{
method: http.RequestMethod.GET,
expectDataType:http.HttpDataType.STRING
})
.then((res: http.HttpResponse) => {
// AlertDialog.show({ message: JSON.stringify(res,null,2) })
this.message = res.result.toString()
})
})
}
.width('100%')
}
.height('100%')
}
}
获取新闻列表数据:https://hmajax.itheima.net/api/news
import { http } from '@kit.NetworkKit'
interface NewsResponse {
message: string
data: News[]
}
interface News {
id: number
title: string
source: string
cmtcount: number
img: string
time: string
}
@Entry
@Component
struct Day01_02_URL {
@State data: NewsResponse | null = null
build() {
Column() {
Button('获取新闻列表数据')
.onClick(() => {
// 1. 创建请求对象
const req = http.createHttp()
// 2. 发送请求获取服务器数据
// http://hmajax.itheima.net/api/news
req.request('http://hmajax.itheima.net/api/news', {
expectDataType: http.HttpDataType.OBJECT
})
.then(res => {
console.log(JSON.stringify(res.result))
this.data = res.result as NewsResponse
})
})
// Text(JSON.stringify(this.data,null,2))
}
.height('100%')
.width('100%')
}
}
地址:http://hmajax.itheima.net/api/city
说明获取某个省所有的城市查询
参数名:pname
说明: 传递省份或直辖市名,比如 北京、广东省…
import { http } from '@kit.NetworkKit'
@Entry
@Component
struct Index {
build() {
Column() {
Button('获取城市信息')
.onClick(() => {
const req = http.createHttp()
req.request('http://hmajax.itheima.net/api/city', {
expectDataType:http.HttpDataType.OBJECT,
extraData:{
pname:'广东省'
}
})
.then(res=>{
console.log(JSON.stringify(res.result))
})
.catch((err:Error)=>{
console.log(JSON.stringify(err,null,2))
})
})
}
.height('100%')
.width('100%')
}
}
2.2. POST请求演示
注册用户:接口文档
@Entry
@Component
struct Day01_05_SubmitData {
@State username: string = ''
@State password: string = ''
build() {
Column({ space: 15 }) {
Text('请求方法和数据提交')
.fontSize(30)
.fontWeight(FontWeight.Bold)
// $$this.username 双向数据绑定
TextInput({ text: $$this.username, placeholder: '用户名' })
TextInput({ text: $$this.password, placeholder: '密码' })
.type(InputType.Password)
Button('注册')
.width('100%')
.onClick(() => {
Button('登录')
.width('100%')
.onClick(() => {
})
}
.width('100%')
.height('100%')
.padding(20)
}
}
import http from '@ohos.net.http'
const req = http.createHttp()
@Entry
@Component
struct Day01_05_SubmitData {
@State username: string = 'itheima522'
@State password: string = '123456'
build() {
Column({ space: 15 }) {
Text('请求方法和数据提交')
.fontSize(30)
.fontWeight(FontWeight.Bold)
TextInput({ text: $$this.username, placeholder: '用户名' })
TextInput({ text: $$this.password, placeholder: '密码' })
.type(InputType.Password)
Button('注册')
.width('100%')
.onClick(() => {
req.request('http://hmajax.itheima.net/api/register', {
method: http.RequestMethod.POST,
expectDataType:http.HttpDataType.OBJECT,
header: {
contentType: 'application/json'
},
extraData: {
username: this.username,
password: this.password
}
})
.then(res => {
AlertDialog.show({ message:JSON.stringify(res.result,null,2) })
})
})
}
.width('100%')
.height('100%')
.padding(20)
}
}
2.3. 模拟器和真机网络权限配置
预览器的网络请求无需配置网络请求权限。
模拟器和真机必须要配置网络权限才能进行网络请求
如果没有配置网络请求权限,则在请求后会出现如下错误:
如何配置网络权限?
在项目中找到entry/src/main/module.json5 文件,在里面配置网络请求
权限列表
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
]
}
]
}
}
3. 案例-开心一笑
接下来完成一个案例,需求:
- 默认获取若干条笑话,并渲染到页面上
- 下拉刷新
- 触底加载更多
- 点击返回顶部
3.1. 前置知识
3.1.1. Refresh下拉刷新容器组件
作用:可以实现下拉刷新功能
@Entry
@Component
struct Index {
// 1. 控制Refresh组件的下拉动画效果的,true:打开下拉刷新效果 false:关闭下拉刷新效果
@State isrefreshing: boolean = false
build() {
Column() {
Refresh({ refreshing: $$this.isrefreshing }) {
List({ space: 5 }) {
ForEach([1, 2, 3, 4, 5, 6, 7, 8], () => {
ListItem() {
Row() {
}.height(100).width('100%').backgroundColor(Color.Pink)
}
})
}
}
// 只要一下拉就会触发这个事件
.onRefreshing(() => {
// AlertDialog.show({ message: 'ok' })
setTimeout(() => {
this.isrefreshing = false // 关闭刷新
}, 3000)
})
}
.height('100%')
.width('100%')
}
}
3.1.2. LoadingProgress正在加载中的动画图标
LoadingProgress()
.height(50)
.color(Color.Red)
3.1.3. List的触底事件 .onReachEnd()
作用:可以实现List列表数据触底时加载
@Entry
@Component
struct Index {
@State isLoding: boolean = false
build() {
Column() {
List({ space: 5 }) {
ForEach([1, 2, 3, 4, 5, 6, 7, 8], () => {
ListItem() {
Row() {
}.height(100).width('100%').backgroundColor(Color.Pink)
}
})
// 加一个正在加载中的动画
ListItem() {
LoadingProgress()
.height(50)
}.width('100%')
}
// onReachEnd当List的滚动条滚动到底部的时候会触发
// ✨✨问题:鼠标一抖动触发了
/* 解决方案:设置一个状态变量初始值为false,
在onReachEnd中加一个if判断 -> 方法体里面将这个变量的值设置为true,
直到服务器返回了数据后,
重置这个变量的值为false
✨✨onReachEnd特点:页面加载的时候从服务器获取到数据之后会自动触发
*/
.onReachEnd(() => {
// 我们可以发请求拿新数据
if (this.isLoding == false) {
this.isLoding = true
setTimeout(() => {
AlertDialog.show({ message: '触底加载' })
this.isLoding = false
}, 3000)
}
})
}
.height('100%')
.width('100%')
}
}
3.2. 基本结构
/**
* 1. 默认加载
* 2. 下拉刷新
* 3. 触底加载更多
* 4. 点击返回顶部
* */
@Entry
@Component
struct Day01_07_Jokes {
@State jokes: string [] = ['笑话 1']
build() {
Column() {
// 顶部
this.HeaderBuilder()
// 笑话列表
List({ space: 10 }) {
ForEach(this.jokes, (joke: string) => {
ListItem() {
Column({ space: 10 }) {
Text('笑话标题')
.fontSize(20)
.fontWeight(600)
Row({ space: 15 }) {
titleIcon({ icon: $r('app.media.ic_public_time'), info: '2024-1-1' })
titleIcon({ icon: $r('app.media.ic_public_read'), info: '阅读(6666)' })
titleIcon({ icon: $r('app.media.ic_public_comments'), info: '评论(123)' })
}
Text(joke)
.fontSize(15)
.fontColor(Color.Gray)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding(20)
}
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: Color.Gray })
})
}
.padding(10)
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#f6f6f6')
}
@Builder
HeaderBuilder() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.width(25);
Image($r('app.media.ic_public_joke_logo'))
.width(30)
Image($r('app.media.ic_public_search'))
.width(30);
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height(60)
.padding(10)
.border({ width: { bottom: 2 }, color: '#f0f0f0' })
.backgroundColor(Color.White)
}
}
@Component
struct titleIcon {
icon: ResourceStr = ''
info: string = ''
build() {
Row() {
Image(this.icon)
.width(15)
.fillColor(Color.Gray)
Text(this.info)
.fontSize(14)
.fontColor(Color.Gray)
}
}
}
3.3. 默认获取若干条笑话
核心步骤:
- 生命周期函数中获取数据
-
- aboutToAppear
- http 模块获取笑话,若干条
请求地址:https://api-vue-base.itheima.net/api/joke/list
参数:num
完整url:https://api-vue-base.itheima.net/api/joke/list?num=获取条数
- 将获取到的数据转换格式并渲染
-
- as 类型
import { http } from '@kit.NetworkKit'
export interface iItem {
code: number;
data: string[];
msg: string;
}
/**
* 1. 默认加载 -> 加载五条数据 -> aboutToAppear() -> getList()
* 2. 下拉刷新
* 3. 触底加载更多
* 4. 点击返回顶部
* */
@Entry
@Component
struct Day01_07_Jokes {
@State jokes: string [] = ['笑话 1']
aboutToAppear(): void {
this.getList()
}
// 请求笑话数据
async getList() {
const req = http.createHttp()
try {
const res = await req.request('https://api-vue-base.itheima.net/api/joke/list', {
expectDataType: http.HttpDataType.OBJECT,
extraData: {
num: '5'
}
})
// 将res.reslut这个Object对象as成真正的接口类型,才能使用里面的属性
const obj = res.result as iItem
this.jokes = obj.data
// AlertDialog.show({ message: JSON.stringify(obj.data, null, 2) })
} catch (err) {
AlertDialog.show({ message: '网络错误' })
}
}
build() {
Column() {
// 顶部
this.HeaderBuilder()
// 笑话列表
List({ space: 10 }) {
ForEach(this.jokes, (joke: string) => {
ListItem() {
Column({ space: 10 }) {
Text('笑话标题')
.fontSize(20)
.fontWeight(600)
Row({ space: 15 }) {
titleIcon({ icon: $r('app.media.ic_public_time'), info: '2024-1-1' })
titleIcon({ icon: $r('app.media.ic_public_read'), info: '阅读(6666)' })
titleIcon({ icon: $r('app.media.ic_public_comments'), info: '评论(123)' })
}
Text(joke)
.fontSize(15)
.fontColor(Color.Gray)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding(20)
}
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: Color.Gray })
})
}
.padding(10)
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#f6f6f6')
}
@Builder
HeaderBuilder() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.width(25);
Image($r('app.media.ic_public_joke_logo'))
.width(30)
Image($r('app.media.ic_public_search'))
.width(30);
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height(60)
.padding(10)
.border({ width: { bottom: 2 }, color: '#f0f0f0' })
.backgroundColor(Color.White)
}
}
@Component
struct titleIcon {
icon: ResourceStr = ''
info: string = ''
build() {
Row() {
Image(this.icon)
.width(15)
.fillColor(Color.Gray)
Text(this.info)
.fontSize(14)
.fontColor(Color.Gray)
}
}
}
3.4. 下拉刷新
核心步骤:
- 通过 Refresh组件实现下拉效果
- 在 onRefreshing 中重新获取数据替换默认值即可
- 抽取获取笑话的方法,在 2 个地方调用即可
-
- aboutToAppear
- onRefreshing
-
-
- 延迟关闭下拉刷新的效果
-
/**
* 1. 默认加载
* 2. 下拉刷新
* 3. 触底加载更多
* 4. 点击返回顶部
* */
import { http } from '@kit.NetworkKit'
interface iData {
code: number
msg: string
data: string[]
}
@Entry
@Component
struct Day01_07_Jokes {
@State jokes: string [] = ['笑话 1']
@State isrefreshing:boolean = false
// 1. 页面渲染完成后调用声明周期方法
aboutToAppear(): void {
this.getList()
.then(res => {
let objData: iData = JSON.parse(res.result.toString())
this.jokes = objData.data
})
}
// 获取笑话数据
getList() {
// 请求服务器数据
const req = http.createHttp()
// 返回对象
return req.request('https://api-vue-base.itheima.net/api/joke/list?num=5')
}
build() {
Column() {
// 顶部
this.HeaderBuilder()
// 笑话列表
Refresh({refreshing:$$this.isrefreshing}) {
List({ space: 10 }) {
ForEach(this.jokes, (joke: string) => {
ListItem() {
Column({ space: 10 }) {
Text(joke.slice(0, 10))// 从字符串中截取前若干个文字
.fontSize(20)
.fontWeight(600)
Row({ space: 15 }) {
titleIcon({ icon: $r('app.media.ic_public_time'), info: '2024-1-1' })
titleIcon({ icon: $r('app.media.ic_public_read'), info: '阅读(6666)' })
titleIcon({ icon: $r('app.media.ic_public_comments'), info: '评论(123)' })
}
Text(joke)
.fontSize(15)
.fontColor(Color.Gray)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding(20)
}
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: Color.Gray })
})
}
.padding(10)
.layoutWeight(1)
}
.onRefreshing(()=>{
// 重新请求服务器获取新数据
this.getList()
.then(res=>{
// 刷新列表
let objData: iData = JSON.parse(res.result.toString())
this.jokes = objData.data
//服务器返回数据后,关闭下拉加载功能
this.isrefreshing = false
})
})
}
.width('100%')
.height('100%')
.backgroundColor('#f6f6f6')
}
@Builder
HeaderBuilder() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.width(25);
Image($r('app.media.ic_public_joke_logo'))
.width(30)
Image($r('app.media.ic_public_search'))
.width(30);
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height(60)
.padding(10)
.border({ width: { bottom: 2 }, color: '#f0f0f0' })
.backgroundColor(Color.White)
}
}
@Component
struct titleIcon {
icon: ResourceStr = ''
info: string = ''
build() {
Row() {
Image(this.icon)
.width(15)
.fillColor(Color.Gray)
Text(this.info)
.fontSize(14)
.fontColor(Color.Gray)
}
}
}
3.5. 触底加载更多
核心步骤:
- 在 onReachEnd 事件中加载更多数据,list 组件
-
- 重新获取数据
- 和本地的合并到一起
- this.jokes.push(...['笑话 1',’笑话 2‘])
- 获取到的数据和本地数据合并
/**
* 1. 默认加载
* 2. 下拉刷新
* 3. 触底加载更多
* 4. 点击返回顶部
* */
import { http } from '@kit.NetworkKit'
interface iData {
code: number
msg: string
data: string[]
}
@Entry
@Component
struct Day01_07_Jokes {
@State jokes: string [] = []
@State isrefreshing: boolean = false
@State isLoadMore: boolean = false //控制触底加载
// 1. 页面渲染完成后调用声明周期方法
aboutToAppear(): void {
// this.getList()
// .then(res => {
// let objData: iData = JSON.parse(res.result.toString())
// this.jokes = objData.data
// })
}
// 获取笑话数据
getList() {
// 请求服务器数据
const req = http.createHttp()
// 返回对象
return req.request('https://api-vue-base.itheima.net/api/joke/list?num=5')
}
build() {
Column() {
// 顶部
this.HeaderBuilder()
// 笑话列表
Refresh({ refreshing: $$this.isrefreshing }) {
List({ space: 10 }) {
ForEach(this.jokes, (joke: string) => {
ListItem() {
Column({ space: 10 }) {
Text(joke.slice(0, 10))// 从字符串中截取前若干个文字
.fontSize(20)
.fontWeight(600)
Row({ space: 15 }) {
titleIcon({ icon: $r('app.media.ic_public_time'), info: '2024-1-1' })
titleIcon({ icon: $r('app.media.ic_public_read'), info: '阅读(6666)' })
titleIcon({ icon: $r('app.media.ic_public_comments'), info: '评论(123)' })
}
Text(joke)
.fontSize(15)
.fontColor(Color.Gray)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding(20)
}
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: Color.Gray })
})
// TODO:触底加载更多的动画提示
ListItem() {
LoadingProgress()
.height(50)
}
.width('100%')
}
.onReachEnd(() => {
if (this.isLoadMore == false) {
this.isLoadMore = true
// 发送新的请求获取新数据新数据应该是追加到this.jokes的后面-> push
this.getList()
.then(res => {
let objData: iData = JSON.parse(res.result.toString())
// 将服务器新返回的数据展开之后追加原数组的后边
this.jokes.push(...objData.data)
this.isLoadMore = false
})
}
})
.padding(10)
.layoutWeight(1)
}
.onRefreshing(() => {
// 请求服务器获取新数据
this.getList()
.then(res => {
let objData: iData = JSON.parse(res.result.toString())
this.jokes = objData.data
//等服务器返回数据后关闭下拉加载功能
this.isrefreshing = false
})
})
}
.width('100%')
.height('100%')
.backgroundColor('#f6f6f6')
}
@Builder
HeaderBuilder() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.width(25);
Image($r('app.media.ic_public_joke_logo'))
.width(30)
Image($r('app.media.ic_public_search'))
.width(30);
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height(60)
.padding(10)
.border({ width: { bottom: 2 }, color: '#f0f0f0' })
.backgroundColor(Color.White)
}
}
@Component
struct titleIcon {
icon: ResourceStr = ''
info: string = ''
build() {
Row() {
Image(this.icon)
.width(15)
.fillColor(Color.Gray)
Text(this.info)
.fontSize(14)
.fontColor(Color.Gray)
}
}
}
3.6. 点击【顶部栏】返回顶部
核心步骤:
- 【顶部栏】点击事件中通过 Scroller控制器 scrollEdge 方法滚到顶部
-
- 通过控制器的方法,滚到顶部即可
/**
* 1. 默认加载
* 2. 下拉刷新
* 3. 触底加载更多
* 4. 点击返回顶部
* */
import { http } from '@kit.NetworkKit'
interface iData {
code: number
msg: string
data: string[]
}
@Entry
@Component
struct Day01_07_Jokes {
@State jokes: string [] = []
@State isrefreshing: boolean = false
@State isLoadMore: boolean = false //控制触底加载
listScroller = new ListScroller()
// 1. 页面渲染完成后调用声明周期方法
aboutToAppear(): void {
// this.getList()
// .then(res => {
// let objData: iData = JSON.parse(res.result.toString())
// this.jokes = objData.data
// })
}
// 获取笑话数据
getList() {
// 请求服务器数据
const req = http.createHttp()
// 返回对象
return req.request('https://api-vue-base.itheima.net/api/joke/list?num=5')
}
build() {
Column() {
// 顶部
this.HeaderBuilder()
// 笑话列表
Refresh({ refreshing: $$this.isrefreshing }) {
List({ space: 10, scroller: this.listScroller }) {
ForEach(this.jokes, (joke: string) => {
ListItem() {
Column({ space: 10 }) {
Text(joke.slice(0, 10))// 从字符串中截取前若干个文字
.fontSize(20)
.fontWeight(600)
Row({ space: 15 }) {
titleIcon({ icon: $r('app.media.ic_public_time'), info: '2024-1-1' })
titleIcon({ icon: $r('app.media.ic_public_read'), info: '阅读(6666)' })
titleIcon({ icon: $r('app.media.ic_public_comments'), info: '评论(123)' })
}
Text(joke)
.fontSize(15)
.fontColor(Color.Gray)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding(20)
}
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: Color.Gray })
})
// TODO:触底加载更多的动画提示
ListItem() {
LoadingProgress()
.height(50)
}
.width('100%')
}
.onReachEnd(() => {
if (this.isLoadMore == false) {
this.isLoadMore = true
// 发送新的请求获取新数据新数据应该是追加到this.jokes的后面-> push
this.getList()
.then(res => {
let objData: iData = JSON.parse(res.result.toString())
// 将服务器新返回的数据展开之后追加原数组的后边
this.jokes.push(...objData.data)
this.isLoadMore = false
})
}
})
.padding(10)
.layoutWeight(1)
}
.onRefreshing(() => {
// 请求服务器获取新数据
this.getList()
.then(res => {
let objData: iData = JSON.parse(res.result.toString())
this.jokes = objData.data
//等服务器返回数据后关闭下拉加载功能
this.isrefreshing = false
})
})
}
.width('100%')
.height('100%')
.backgroundColor('#f6f6f6')
}
@Builder
HeaderBuilder() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.width(25);
Image($r('app.media.ic_public_joke_logo'))
.width(30)
Image($r('app.media.ic_public_search'))
.width(30);
}
.onClick(() => {
// 点击滚动到顶部
this.listScroller.scrollEdge(Edge.Top)
})
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height(60)
.padding(10)
.border({ width: { bottom: 2 }, color: '#f0f0f0' })
.backgroundColor(Color.White)
}
}
@Component
struct titleIcon {
icon: ResourceStr = ''
info: string = ''
build() {
Row() {
Image(this.icon)
.width(15)
.fillColor(Color.Gray)
Text(this.info)
.fontSize(14)
.fontColor(Color.Gray)
}
}
}
4. 请求库-axios
除了原生的请求库http以外,还可以使用 第三方请求库axios来进行网络请求,为我们提供第二种http请求方式
axios文档传送门
4.1. 基本用法
4.1.1. 下载axios
作为一个第三方库,使用的时候需要先完成下包的操作
打开终端执行命令
# 安装
ohpm i @ohos/axios
# 卸载
ohpm uninstall @ohos/axios
ohpm 是一个包管理工具,用来管理鸿蒙提供的第三方模块
如果无法执行命令,或执行失败,可以使用如下方式来完成安装:
4.1.2. axios完成POST请求
基本语法格式:
// 1. 导入axios
// AxiosError:异常时的数据类型
// 正常时的数据类型AxiosResponse 是一个泛型类型
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
// 2. 创建axios的对象实例
const req = axios.create()
// 3. 发送POST请求,并提交数据给服务器
const res:AxiosResponse<响应数据类型> =
await req<响应数据类型(可以写null), AxiosResponse<响应数据类型>, 请求体数据类型>({
method: 'POST', // 请求方法
url: 'https://hmajax.itheima.net/api/login', //服务器url地址
data: { // 请求体数据
username: '黑马no1hello',
password: '123456'
}
})
登录接口传送门
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
// 1. 利用axios.create创建请求对象
const reqeust = axios.create({
baseURL: 'https://hmajax.itheima.net/'
})
export interface iRes {
/**
* 业务状态码, 10000成功, 10004-账号/密码未携带
*/
code: number;
/**
* 响应数据
*/
data: object;
/**
* 响应消息
*/
message: string;
}
export interface iBody {
/**
* 密码, 最少6位
*/
password: string;
/**
* 用户名, 最少8位,中英文和数字组成,
*/
username: string;
}
@Entry
@Component
struct Index {
build() {
Column() {
Button('post请求测试')
.onClick(async () => {
// 2. 发起请求
try {
const res: AxiosResponse<iRes> = await reqeust<null, AxiosResponse<iRes>, iBody>({
method: 'POST',
url: 'api/login',
data: {
username: '黑马no1hello',
password: '123456'
}
})
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
// 将err异常对象强制转换成 AxiosError
// response就是异常的响应对象
const error: AxiosError = err as AxiosError
AlertDialog.show({ message: JSON.stringify(error.response, null, 2) })
}
})
}
.height('100%')
.width('100%')
.backgroundColor(Color.Pink)
}
}
- 请求体有数据提交时,泛型参数 3,需要设置为【请求体】的格式,可以从 apifox 直接c+v
4.1.3. axios完成GET请求
一级商品(无参数) : 接口文档传送门
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
export interface ApifoxModel {
/**
* 响应数据
*/
data: Datum[];
/**
* 响应消息
*/
message: string;
}
export interface Datum {
/**
* 顶级分类id
*/
id: string;
/**
* 顶级分类名字
*/
name: string;
/**
* 顶级分类图片
*/
picture: string;
}
@Entry
@Component
struct Index {
build() {
Column() {
Button('axios.get')
.onClick(async () => {
// 1. 创建请求实例
const req = axios.create()
// 2. async 和 await方式发送get请求(不带参数)
try{
let res: AxiosResponse<ApifoxModel> = await req({
method: 'get',
url: 'https://hmajax.itheima.net/api/category/top'
})
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
let errObj: AxiosError = err
AlertDialog.show({ message: '出错了:' + JSON.stringify(errObj.message, null, 2) })
}
// 3. .then().catch()方式发送请求(不带参数)
// req.request({
// method: 'get',
// url: 'https://hmajax.itheima.net/api/category/top1'
// })
// .then((res: AxiosResponse<ApifoxModel>) => {
// AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
// })
// .catch((err: AxiosError) => {
// AlertDialog.show({ message: '出错了:' + JSON.stringify(err, null, 2) })
// })
})
}
.height('100%')
.width('100%')
}
}
get 请求传递的查询参数
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
export interface ApifoxModel {
/**
* 响应数据
*/
data: Data;
/**
* 响应消息
*/
message: string;
}
/**
* 响应数据
*/
export interface Data {
/**
* 顶级分类下属二级分类数组
*/
children: Child[];
/**
* 顶级分类id
*/
id: string;
/**
* 顶级分类名字
*/
name: string;
/**
* 顶级分类图片
*/
picture: string;
}
export interface Child {
/**
* 二级分类id
*/
id: string;
/**
* 二级分类名字
*/
name: string;
/**
* 二级分类图片
*/
picture: string;
}
@Entry
@Component
struct Index {
build() {
Column() {
Button('axios.get')
.onClick(async () => {
// 1. 创建请求实例
const req = axios.create()
// 2. async 和 await方式发送get请求(带参数)
try{
let res: AxiosResponse<ApifoxModel> = await req({
method: 'get',
url: 'https://hmajax.itheima.net/api/category/sub',
params:{
id:'1005000'
}
})
// 写法2:
let res: AxiosResponse<ApifoxModel> = await req.get(
'https://hmajax.itheima.net/api/category/sub', {
params: {
id: '1005000'
}
}
)
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
let errObj: AxiosError = err
AlertDialog.show({ message: '出错了:' + JSON.stringify(errObj.message, null, 2) })
}
// 3. .then().catch()方式发送请求(带参数)
// req.request({
// method: 'get',
// url: 'https://hmajax.itheima.net/api/category/sub',
// params:{
// id:'1005000'
// }
// })
// .then((res: AxiosResponse<ApifoxModel>) => {
// AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
// })
// .catch((err: AxiosError) => {
// AlertDialog.show({ message: '出错了:' + JSON.stringify(err, null, 2) })
// })
})
}
.height('100%')
.width('100%')
}
}
4.2. axios基地址配置
我们可以使用自定义配置新建一个实例
// 基于配置,返回一个 axios 的实例
const req = axios.create({
// 基地址,后续请求的时候这部分可以省略
baseURL:'https://hmajax.itheima.net'
})
// get 请求 直接写 url 即可
let res: AxiosResponse<ApifoxModel> = await req({
method: 'get',
url: '/api/category/top'
})
AlertDialog.show({ message: JSON.stringify(res) })
import axios, { AxiosResponse } from '@ohos/axios'
const req = axios.create({
// ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
// 设置请求url的基地址,它的值一般填写后台数据接口服务器的域名
// 注意点,最后要不要带 / 要看下边req.request()中的url中首字符是否有/
// 如果有,不带,否则带
//✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
baseURL:'https://hmajax.itheima.net'
})
export interface iRes {
/**
* 响应数据
*/
data: Datum[];
/**
* 响应消息
*/
message: string;
}
export interface Datum {
/**
* 顶级分类id
*/
id: string;
/**
* 顶级分类名字
*/
name: string;
/**
* 顶级分类图片
*/
picture: string;
}
@Entry
@Component
struct Index {
build() {
Column({ space: 100 }) {
Button('axios发送不带参数的请求')
.onClick(async () => {
// const req = axios.create()
try {
// 此处编写代码
let res: AxiosResponse<iRes> = await req({
url: '/api/category/top', //由于设置了基地址,所以此处只需要配置请求路径即可
method: 'get', //默认值,可以省略
})
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
AlertDialog.show({ message: JSON.stringify(err, null, 2) })
}
})
Button('axios发送带参数的请求').onClick(async () => {
// const req = axios.create()
try {
// 此处编写代码
let res: AxiosResponse<iRes> = await req({
url: '/api/city', //由于设置了基地址,所以此处只需要配置请求路径即可
method: 'get', //默认值,可以省略
// get请求的参数是通过固定的属性:params来进行携带
// post请求的参数是固定通过:data来携带的
params: {
pname: '广东省' // 使用axios中文参数值再内部回自动转成url编码,服务器能够正常响应数据
}
})
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
AlertDialog.show({ message: JSON.stringify(err, null, 2) })
}
})
}
.height('100%')
.width('100%')
}
}
注意:axios和内置的 http 模块在异常的处理上略有不同:
- 内置的 http 模块,http 状态码为异常时,不会响应为错误
- axios对于 http 状态码的错误(2xx 以外),会作为异常处理
5. 综合案例-我的书架-axios
图片素材
我的书架.zip
接口文档
接下来咱们使用 axios 来完成书架案例
5.1. 获取图书列表
5.1.1. 静态结构
@Entry
@Component
struct Index {
// 1. 我的书架
@Builder
MyBook() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.height(20)
Text('我的书架')
.fontSize(20)
.fontWeight(800)
Image($r('app.media.ic_public_add'))
.height(20)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(10)
.border({ width: { bottom: 1 }, color: { bottom: 'rgba(0,0,0,0.2)' } })
}
// 2. 书籍列表
@Builder
BookList() {
List() {
ListItem() {
// 布局
Row({ space: 10 }) {
Image($r('app.media.ic_public_cover'))
.width(100)
Column({ space: 25 }) {
Column() {
Text('书名:')
.width('100%')
.fontSize(20)
.fontWeight(800)
Text('作者:')
.width('100%')
.fontSize(14)
.fontWeight(600)
.fontColor('rgba(0,0,0,0.4)')
.padding({ top: 5 })
}
Text('出版社:')
.width('100%')
.fontWeight(600)
.fontColor('rgba(0,0,0,0.4)')
}
.layoutWeight(1)
}
.padding(10)
}
.swipeAction({
end: this.delBuilder()
})
}
}
// 3. 删除书籍的构建函数
@Builder
delBuilder() {
Column(){
Text('删除')
.backgroundColor(Color.Red)
.fontColor(Color.White)
.height('100%')
.width(60)
.textAlign(TextAlign.Center)
}
.padding(10)
}
build() {
Column() {
// 1. 我的书架
this.MyBook()
// 2. 书籍列表
this.BookList()
}
.height('100%')
.width('100%')
}
}
5.1.2. 准备类型模块并导出
由于图书的增,改,列表,详情接口返回的数据对象是一样的。所以我们可以在这些业务中可以共用同一个interface类型,因此,需要进行模块封装并导出
export interface iBookResponse {
/**
* 响应数组
*/
data: iBookInfo[];
/**
* 响应消息
*/
message: string;
}
// 按需导出
export interface iBookInfo {
/**
* 图书作者
*/
author: string;
/**
* 图书名字
*/
bookname: string;
/**
* 图书id
*/
id: number;
/**
* 图书出版社
*/
publisher: string;
}
5.1.3. 获取图书数据并渲染
import axios, { AxiosResponse } from '@ohos/axios'
import { iBookInfo, iBookResponse } from './models'
import { router } from '@kit.ArkUI'
const req = axios.create()
@Entry
@Component
struct Index {
@State bookList: iBookInfo[] = []
aboutToAppear(): void {
this.getBookList()
}
async getBookList() {
try {
let res: AxiosResponse<iBookResponse> =
await req.request({
url: 'https://hmajax.itheima.net/api/books',
params:{
creator:'ivan'
}
})
this.bookList = res.data.data
} catch (err) {
AlertDialog.show({message:JSON.stringify(err,null,2)})
}
}
build() {
Column() {
// 1. 我的书架
this.MyBook()
// 2. 书籍列表
this.BookList()
}
.height('100%')
.width('100%')
}
// 1. 我的书架
@Builder
MyBook() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.height(20)
Text('我的书架')
.fontSize(20)
.fontWeight(800)
Image($r('app.media.ic_public_add'))
.height(20)
.onClick(()=>{
router.pushUrl({url:'pages/axiosbooks/addBook'})
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(10)
.border({ width: { bottom: 1 }, color: { bottom: 'rgba(0,0,0,0.2)' } })
}
// 2. 书籍列表
@Builder
BookList() {
List() {
ForEach(this.bookList, (item: iBookInfo) => {
ListItem() {
// 布局
Row({ space: 10 }) {
Image($r('app.media.ic_public_cover'))
.width(100)
Column({ space: 25 }) {
Column() {
Text('书名:'+item.bookname)
.width('100%')
.fontSize(20)
.fontWeight(800)
Text('作者:'+item.author)
.width('100%')
.fontSize(14)
.fontWeight(600)
.fontColor('rgba(0,0,0,0.4)')
.padding({ top: 5 })
}
Text('出版社:')
.width('100%')
.fontWeight(600)
.fontColor('rgba(0,0,0,0.4)')
}
.layoutWeight(1)
}
.padding(10)
}
.swipeAction({
end: this.delBuilder()
})
})
}
}
// 3. 删除书籍的构建函数
@Builder
delBuilder() {
Column() {
Text('删除')
.backgroundColor(Color.Red)
.fontColor(Color.White)
.height('100%')
.width(60)
.textAlign(TextAlign.Center)
}
.padding(10)
}
}
5.2. 新增图书
5.2.1. 静态结构
// 导入创建者
import { creator } from './models'
@Entry
@Component
struct addPage {
@State bookname: string = ''
@State author: string = ''
@State publisher: string = ''
build() {
Navigation() {
Column({ space: 10 }) {
Row() {
Text('图书名称:')
TextInput({ placeholder: '请输入图书名字', text: $$this.bookname })
}
Row() {
Text('图书作者:')
TextInput({ placeholder: '请输入作者名字', text: $$this.author })
}
Row() {
Text('图书出版社:')
TextInput({ placeholder: '请输入出版社名字', text: $$this.publisher })
}
Button({ type: ButtonType.Normal }) {
Text('保存')
.fontColor(Color.White)
.fontWeight(800)
}
.width('100%')
.height(40)
.borderRadius(8)
}
.height('100%')
.width('100%')
.padding(10)
}
.title('新增图书')
.titleMode(NavigationTitleMode.Mini)
}
}
5.2.2. 新增逻辑实现
// 导入创建者
import axios, { AxiosResponse } from '@ohos/axios'
import { creator, iBookInfoDetial } from './models'
import { promptAction, router } from '@kit.ArkUI';
// POST请求体数据类型
export interface iReqeustBody {
/**
* 新增图书作者
*/
author: string;
/**
* 新增图书名字
*/
bookname: string;
/**
* 新增图书创建者,自己的外号,和获取图书时的外号相同
*/
creator: string;
/**
* 新增图书出版社
*/
publisher: string;
}
@Entry
@Component
struct addPage {
@State bookname: string = ''
@State author: string = ''
@State publisher: string = ''
async addBook() {
// 1. 非空验证 -> 轻提示用户
if (this.bookname == '' || this.author == '' || this.publisher == '') {
promptAction.showToast({ message: '图书名,作者,出版社均非空' })
return //阻止下面代码继续执行
}
const req = axios.create()
let res: AxiosResponse<iBookInfoDetial> = await req.request<null, AxiosResponse<iBookInfoDetial>, iReqeustBody>({
method: 'POST',
url: 'https://hmajax.itheima.net/api/books',
data: {
bookname: this.bookname,
author: this.author,
publisher: this.publisher,
creator: creator
}
})
promptAction.showToast({ message: res.data.message })
router.back()
}
build() {
Navigation() {
Column({ space: 10 }) {
Row() {
Text('图书名称:')
TextInput({ placeholder: '请输入图书名字', text: $$this.bookname })
}
Row() {
Text('图书作者:')
TextInput({ placeholder: '请输入作者名字', text: $$this.author })
}
Row() {
Text('图书出版社:')
TextInput({ placeholder: '请输入出版社名字', text: $$this.publisher })
}
Button({ type: ButtonType.Normal }) {
Text('保存')
.fontColor(Color.White)
.fontWeight(800)
}
.width('100%')
.height(40)
.borderRadius(8)
.onClick(() => {
this.addBook()
})
}
.height('100%')
.width('100%')
.padding(10)
}
.title('新增图书')
.titleMode(NavigationTitleMode.Mini)
}
}
5.3. 删除图书
import axios, { AxiosResponse } from '@ohos/axios'
import { iBookInfo, iBookResponse } from './models'
import { promptAction, router } from '@kit.ArkUI'
const req = axios.create()
@Entry
@Component
struct Index {
@State bookList: iBookInfo[] = []
onPageShow(): void {
this.getBookList()
}
async getBookList() {
try {
let res: AxiosResponse<iBookResponse> =
await req.request({
url: 'https://hmajax.itheima.net/api/books',
params: {
creator: 'ivan'
}
})
this.bookList = res.data.data
} catch (err) {
AlertDialog.show({ message: JSON.stringify(err, null, 2) })
}
}
build() {
Column() {
// 1. 我的书架
this.MyBook()
// 2. 书籍列表
this.BookList()
}
.height('100%')
.width('100%')
}
// 1. 我的书架
@Builder
MyBook() {
Row() {
Image($r('app.media.ic_public_drawer_filled'))
.height(20)
Text('我的书架')
.fontSize(20)
.fontWeight(800)
Image($r('app.media.ic_public_add'))
.height(20)
.onClick(() => {
router.pushUrl({ url: 'pages/axiosbooks/addBook' })
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(10)
.border({ width: { bottom: 1 }, color: { bottom: 'rgba(0,0,0,0.2)' } })
}
// 2. 书籍列表
@Builder
BookList() {
List() {
ForEach(this.bookList, (item: iBookInfo) => {
ListItem() {
// 布局
Row({ space: 10 }) {
Image($r('app.media.ic_public_cover'))
.width(100)
Column({ space: 25 }) {
Column() {
Text('书名:' + item.bookname)
.width('100%')
.fontSize(20)
.fontWeight(800)
Text('作者:' + item.author)
.width('100%')
.fontSize(14)
.fontWeight(600)
.fontColor('rgba(0,0,0,0.4)')
.padding({ top: 5 })
}
Text('出版社:' + item.publisher)
.width('100%')
.fontWeight(600)
.fontColor('rgba(0,0,0,0.4)')
}
.layoutWeight(1)
}
.padding(10)
.onClick(() => {
router.pushUrl({ url: 'pages/axiosbooks/editBook', params: { bookid: item.id } })
})
}
.swipeAction({
end: this.delBuilder(item.id)
})
})
}
}
// 3. 删除书籍的构建函数
@Builder
delBuilder(id: number) {
Column() {
Text('删除')
.backgroundColor(Color.Red)
.fontColor(Color.White)
.height('100%')
.width(60)
.textAlign(TextAlign.Center)
}
.padding(10)
.onClick(() => {
promptAction.showDialog({
title: '删除提示',
message: '确认删除图书吗?',
buttons: [
{
text: '取消',
color: '#000'
},
{
text: '确认',
color: '#ff27a1d7'
},
]
})
.then(async res => {
// res返回的内容:{index:0} 取消按钮被点击, {index:1} 确认按钮被点击
// AlertDialog.show({ message: JSON.stringify(res, null, 2) })
if (res.index == 1) {
try {
// 此处编写代码
let res: AxiosResponse<iBookResponse> = await req.request({
method: 'delete',
url: 'https://hmajax.itheima.net/api/books/' + id
})
promptAction.showToast({ message: res.data.message })
this.getBookList()
} catch (err) {
AlertDialog.show({ message: JSON.stringify(err, null, 2) })
}
}
})
})
}
}
5.4. 编辑图书
5.4.1. 回显图书信息
// 导入创建者
import { creator, iBookInfoDetial } from './models'
import { router } from '@kit.ArkUI'
import axios, { AxiosResponse } from '@ohos/axios'
interface iRouterParams {
bookid: number
}
const req = axios.create()
@Entry
@Component
struct addPage {
@State bookname: string = ''
@State author: string = ''
@State publisher: string = ''
bookid: number = 0
aboutToAppear(): void {
let routerObj = router.getParams() as iRouterParams
this.bookid = routerObj.bookid
this.loadBook()
}
// 1. 回显图书数据
async loadBook() {
try {
// 此处编写代码
let res: AxiosResponse<iBookInfoDetial> = await req.request({
url: 'https://hmajax.itheima.net/api/books/' + this.bookid
})
this.bookname = res.data.data.bookname
this.author = res.data.data.author
this.publisher = res.data.data.publisher
} catch (err) {
console.error('err--->', JSON.stringify(err).slice(0,800))
}
}
build() {
Navigation() {
Column({ space: 10 }) {
Row() {
Text('图书名称:')
TextInput({ placeholder: '请输入图书名字', text: $$this.bookname })
}
Row() {
Text('图书作者:')
TextInput({ placeholder: '请输入作者名字', text: $$this.author })
}
Row() {
Text('图书出版社:')
TextInput({ placeholder: '请输入出版社名字', text: $$this.publisher })
}
Button({ type: ButtonType.Normal }) {
Text('保存')
.fontColor(Color.White)
.fontWeight(800)
}
.width('100%')
.height(40)
.borderRadius(8)
}
.height('100%')
.width('100%')
.padding(10)
}
.title('编辑 图书')
.titleMode(NavigationTitleMode.Mini)
}
}
5.4.2. 修改图书信息
// 导入创建者
import { creator, iBookInfoDetial } from './models'
import { promptAction, router } from '@kit.ArkUI'
import axios, { AxiosResponse } from '@ohos/axios'
import { iReqeustBody } from './addBook'
interface iRouterParams {
bookid: number
}
const req = axios.create()
@Entry
@Component
struct addPage {
@State bookname: string = ''
@State author: string = ''
@State publisher: string = ''
bookid: number = 0
aboutToAppear(): void {
let routerObj = router.getParams() as iRouterParams
this.bookid = routerObj.bookid
this.loadBook()
}
// 1. 回显图书数据
async loadBook() {
try {
// 此处编写代码
let res: AxiosResponse<iBookInfoDetial> = await req.request({
url: 'https://hmajax.itheima.net/api/books/' + this.bookid
})
this.bookname = res.data.data.bookname
this.author = res.data.data.author
this.publisher = res.data.data.publisher
} catch (err) {
console.error('err--->', JSON.stringify(err).slice(0, 800))
}
}
// 2. 修改图书
async saveBook() {
try {
// 此处编写代码
let res: AxiosResponse<iBookInfoDetial> =
await req.request<null, AxiosResponse<iBookInfoDetial>, iReqeustBody>({
method: 'put',
url: 'https://hmajax.itheima.net/api/books/' + this.bookid,
data: {
bookname: this.bookname,
author: this.author,
publisher: this.publisher,
creator: creator
}
})
promptAction.showToast({ message: res.data.message })
router.back()
} catch (err) {
// console.log('编辑图书失败--->', JSON.stringify(err).slice(0, 800))
AlertDialog.show({message:JSON.stringify(err,null,2)})
}
}
build() {
Navigation() {
Column({ space: 10 }) {
Row() {
Text('图书名称:')
TextInput({ placeholder: '请输入图书名字', text: $$this.bookname })
}
Row() {
Text('图书作者:')
TextInput({ placeholder: '请输入作者名字', text: $$this.author })
}
Row() {
Text('图书出版社:')
TextInput({ placeholder: '请输入出版社名字', text: $$this.publisher })
}
Button({ type: ButtonType.Normal }) {
Text('保存')
.fontColor(Color.White)
.fontWeight(800)
}
.width('100%')
.height(40)
.borderRadius(8)
.onClick(()=>{
this.saveBook()
})
}
.height('100%')
.width('100%')
.padding(10)
}
.title('编辑 图书')
.titleMode(NavigationTitleMode.Mini)
}
}