当前位置: 首页 > article >正文

【每日学点鸿蒙知识】PersistentStorage持久化、插槽方法、相对布局、上拉加载下拉刷新、List联动滑动

1、HarmonyOS 使用PersistentStorage持久化用户信息无效?

在首页通过@StorageLink(‘userInfoTest’) userInfoTest: string = ''获取,获不到,返回undefind。是什么原因呢?

首先在首页时,在Entry外声明PersistentStorage.persistProp,其次在登录完成设置值时不使用PersistentStorage.persistProp而是使用AppStorage.set来修改值。下面以userInfo为例:

PersistentStorage.persistProp('userInfo',"111") //可以直接放在import代码下方,此处只以userInfo为例,每一个需要持久化保存的都需要声明
//声明时设置的值可以任意,后续通过set修改,j尽量和目标值保持属性一致
@Entry
@Component
struct Index {
  build() {
    Column(){
      Button("点击测试").onClick(()=>{
        console.log("测试set")
        AppStorage.set('userInfo', "ceshi") //直接使用AppStorage.set,而非PersistentStorage.persistProp,否则将无法修改
      })
      Button("查找userInfo").onClick(()=>{
        const ut = AppStorage.get<string>('userInfo')
        console.log(ut); //测试结果显示userInfo中存的值变成了"ceshi",杀进程,重新进入后直接点击button,log的结果依旧是"ceshi",实现持久化存储
      })
    }
  }
}
2、HarmonyOS 有像 Vue 一样的插槽使用方法吗?

可以使用@BuilderParam装饰器,该装饰器用于声明任意UI描述的一个元素,类似slot占位符。参考链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-builderparam-V5

3、HarmonyOS RelativeContainer 经过offset设置的锚点位置坐标不能作为锚点,只能用没有经过offset配置的旧坐标作为锚点来给下一个组件进行标定?

比如说A组件经过了锚点配置了位置,此时A组件有一个坐标pos1,经过offset设置了新的位置pos2,B组件想要基于A的新位置pos2做标定,必须要将A组件的offset一并加上才能达到在pos2基础上做标定。

比如说下面三个组件,想要达成的效果是年龄和个人信息之间相差13,性别和年龄之间间隔13,但是实际上却是这三个组件之间的间隔为0

Row() {
  Text('个人信息')
    .fontColor(Color.White)
    .fontSize(14)
    .alignRules({
      left: { anchor: 'row1', align: HorizontalAlign.Start },
      center: { anchor: 'row1', align: VerticalAlign.Center }
    })
    .offset({
      x: 13,
      y: 0,
    })
    .id("person_info_text")

  Button('年龄')
    .fontSize(12)
    .aspectRatio(1.857)
    .alignRules({
      left: { anchor: "person_info_text", align: HorizontalAlign.End },
      center: { anchor: 'row1', align: VerticalAlign.Center }
    })
    .offset({
      x: 13,
      y: 0,
    })
    .id("age_btn")

  Button('性别')
    .fontSize(12)
    .aspectRatio(1.857)
    .alignRules({
      left: { anchor: "age_btn", align: HorizontalAlign.End },
      center: { anchor: 'row1', align: VerticalAlign.Center }
    })
    .offset({
      x: 13,
      y: 0,
    })
    .id("gender_btn")

RelativeContainer经过offset设置的锚点位置还是之前没有偏移的位置,所以后面的组件参考的位置还是偏移前的位置,所以要实现上面的效果需要这样设置:

.offset({
  x: 13,
  y: 0,
})
  .offset({
    x: 26,
    y: 0,
  })
  .offset({
    x: 39,
    y: 0,
  })
4、HarmonyOS 上拉加载下拉刷新的控件有没有已经封装好了的?

数据请求写在listTouchEvent里,关联性太强,需要一个封装好,把上拉下拉布局暴露在外由用户设定,监听也有的。

PullToRefresh可用的下拉刷新、上拉加载组件。可参考链接:https://gitee.com/openharmony-sig/ohos_pull_to_refresh

demo如下:

import { PullToRefresh } from '@ohos/pulltorefresh'

@Entry
@Component
struct Index {
  @State refreshText: string = '';
  private dataNumbers: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
  private dataStrings: string[] =
    ['我的评论', '与我相关', '个人中心1', '个人中心2', '个人中心3', '我的发布', '设置', '退出登录'];
  @State data: string[] = this.dataStrings;
  // 需绑定列表或宫格组件
  private scroller: Scroller = new Scroller();

  build() {
    Column() {
      PullToRefresh({
        // 必传项,列表组件所绑定的数据
        data: $data,
        // 必传项,需绑定传入主体布局内的列表或宫格组件
        scroller: this.scroller,
        // 必传项,自定义主体布局,内部有列表或宫格组件
        customList: () => {
          // 一个用@Builder修饰过的UI方法
          this.getListView();
        },
        // 可选项,下拉刷新回调
        onRefresh: () => {
          return new Promise<string>((resolve, reject) => {
            // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
            setTimeout(() => {
              resolve('刷新成功');
              this.data = this.dataNumbers;
            }, 2000);
          });
        },
        // 可选项,上拉加载更多回调
        onLoadMore: () => {
          return new Promise<string>((resolve, reject) => {
            // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
            setTimeout(() => {
              resolve('');
              this.data.push("增加的条目" + this.data.length);
            }, 2000);
          });
        },
        customLoad: null,
        customRefresh: null,
      })
    }
  }

  @Builder
  private getListView() {
    List({ space: 20, scroller: this.scroller }) {
      ForEach(this.data, (item: string) => {
        ListItem() {
          Text(item)
            .width(160)
            .height(150)
            .fontSize(20)
            .textAlign(TextAlign.Center)
            .backgroundColor('#95efd2')
        }
      })
    }
    .backgroundColor('#eeeeee')
    .divider({ strokeWidth: 1, color: 0x222222 })
    .edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果
  }
}
5、HarmonyOS List联动滑动?

有个页面需要两个List联动,且第一个List需要吸顶,但使用ListItemGroup做吸顶功能后,由于Index变成Apis文档中说的:ListItemGroup作为一个整体计算一个索引值,ListItemGroup内部的ListItem不计算索引值。导致两个List不再能根据Index联动.

demo示例如下:

// 商品顶部分类
interface CategoriesType {
  current: string[],
  hot: string[],
  Categories: Map<string, Category[]>
}

interface Category {
  code: string;
  category: string;
}

@Entry
@Component
export default  struct CityList{
  private currentCategory: string = ''
  private hotCategories: string[] = []
  private groupCategories: Map<string, Category[]> = new Map
  private groupNameList: string[] = ['A区', 'B区', 'C区', 'D区', 'F区', 'G区', 'H区', 'J区', 'K区', 'L区']
  @State private selectGroupIndex: number = -1
  private categoryScroller: ListScroller = new ListScroller()
  private categoryScroller1: ListScroller = new ListScroller()
  private isClickScroll:boolean = false
  aboutToAppear() {
    let jsonString: string = '{"current":["保健品专区"],"hot":["险种转换","保单挂失","保单补发"],"Categories":{"A区":[{"code":"001","category":"新增附加险"},{"code":"002","category":"保险附效1"},{"code":"003","category":"保险附效2"},{"code":"004","category":"保险附效3"},{"code":"005","category":"保险附效4"},{"code":"006","category":"保险附效5"},{"code":"007","category":"保险附效6"}],"B区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"012","category":"保险附效3"}],"C区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"D区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"E区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"F区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"G区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"H区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"J区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"K区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}],"L区":[{"code":"008","category":"保险附效1"},{"code":"009","category":"保险附效2"},{"code":"010","category":"保险附效3"},{"code":"011","category":"保险附效4"},{"code":"012","category":"保险附效5"}]}}'
    let data: CategoriesType = JSON.parse(jsonString) as CategoriesType
    this.currentCategory = data.current[0]
    this.hotCategories = data.hot
    this.groupCategories = data.Categories
    console.log('fxm = ', JSON.stringify(this.groupCategories['A区']))
  }

  build() {
    Column() {
      Row() {
        this.navigationList()
      }
      .width('100%')
      .height(42)
      Column() {
        this.categoryList()
      }
      .height('100%')
    }
  }

  getCitiesWithGroupName(name: string): Category[] {
    console.log('fxm ', this.groupCategories[name])
    return this.groupCategories[name]
  }

  @Builder
  itemHead(text: string) {
    Text(text)
      .fontSize(16)
      .width("100%")
      .padding({ left: 10 })
      .height(45)
      .backgroundColor(0xEEEEEE)
  }

  @Builder
  categoryList() {
    List({ scroller: this.categoryScroller }) {
      ListItemGroup({ header: this.itemHead('当前专区') }) {
        ListItem() {
          Text(this.currentCategory)
            .width("100%")
            .height(45)
            .fontSize(16)
            .textAlign(TextAlign.Start)
            .backgroundColor(0xFFFFFF)
            .padding({ left: 10 })
        }
      }

      ListItemGroup({ header: this.itemHead('热门专区') }) {
        ForEach(this.hotCategories, (hotCategory: string) => {
          ListItem() {
            Text(hotCategory)
              .width("100%")
              .height(45)
              .fontSize(16)
              .textAlign(TextAlign.Start)
              .backgroundColor(0xFFFFFF)
              .padding({ left: 10 })
          }
        })
      }

      // A~L专区分组
      ForEach(this.groupNameList, (item: string) => {
        ListItemGroup({ header: this.itemHead(item) }) {
          ForEach(this.getCitiesWithGroupName(item), (item: Category) => {
            ListItem() {
              Text(item.category)
                .width("100%")
                .height(45)
                .fontSize(16)
                .textAlign(TextAlign.Start)
                .backgroundColor(0xFFFFFF)
                .padding({ left: 10 })
            }
          }, (item: Category) => item.category)
        }
      })
    }
    .width('100%')
    .height('100%')
    .scrollBar(BarState.Off)
    .sticky(StickyStyle.Header)
    .onTouch(()=>{
      // 分区列表触摸滚动,isClickScroll=false,防止滚动过程中与导航列表触发滚动冲突
      this.isClickScroll = false
    })
    .onScrollIndex((start: number, end: number, center: number)=>{
      // 通过selectGroupIndex状态变量与start联动控制导航列表选中状态
      if(!this.isClickScroll)
        this.selectGroupIndex = start - 2
    })
  }

  @Builder
  navigationList() {
    List({scroller:this.categoryScroller1}) {
      ForEach(this.groupNameList, (item: string, index: number) => {
        ListItem() {
          Text(item)
            .width(42)
            .height(30)
            .fontSize(16)
            .textAlign(TextAlign.Start)
            .backgroundColor(index == this.selectGroupIndex ? 0xCCCCCC : Color.Transparent)
            .padding({ left: 10 })
            .borderRadius(15)
            .onClick(() => {
              // 导航列表选中isClickScroll=true,防止与分区列表滚动过程中带动导航列表状态变化
              this.isClickScroll = true
              this.selectGroupIndex = index
              // 通过导航选中selectGroupIndex与Scroller控制分区列表滚动到对应位置
              this.categoryScroller.scrollToIndex(index + 2, true, ScrollAlign.START)
            })
        }
      }, (item: string) => item)
    }
    .listDirection(Axis.Horizontal)
    .backgroundColor(Color.Transparent)
    .width('100%')
  }
}

http://www.kler.cn/a/459178.html

相关文章:

  • java中static和const和final的区别
  • 大模型系列17-RAGFlow搭建本地知识库
  • DDoS攻击防御方案大全
  • VSCode设置ctrl或alt+mouse(left)跳转
  • 【图像处理】OpenCv + Python 实现 Photoshop 中的色彩平衡功能
  • C# 标准数字格式字符串
  • 【GO基础学习】Gin 框架中间件的详解
  • Error: The Calculated NPWS= 84330 != The Read NPWS= 84328
  • 优化租赁小程序提升服务效率与用户体验的策略与实践
  • 代码随想录算法训练营第六天 | 242. 有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和
  • 如何利用无线路由器实现水泵房远程监测管理
  • 关于科研工具的思考
  • 企业能源物联网数据采集设备
  • WOFOST作物模型(3):敏感性分析
  • 学习鸿蒙第一天
  • shell指令操作
  • 机器学习之逻辑回归算法、数据标准化处理及数据预测和数据的分类结果报告
  • 【VBA】EXCEL - VBA 创建 Sheet 表的 6 种方法,以及注意事项
  • pycharm如何运行js代码详细图文教程
  • Qt/C++案例 记录创建并加载动态链接库修改exe/dll类型文件的版本信息的示例
  • 云手机:Instagram 矩阵搭建方案
  • MySQL什么情况下会加间隙锁?
  • 使用 AI Cursor 编程实现一个小产品 Chrome 扩展插件 MVP 功能
  • 阿里云 ECS 服务器绑定多个公网IP
  • 程序员转行室内设计师(软装设计流程)
  • 打卡算法题:155. 最小栈 --- 从193ms 到 4 ms的优化