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,})}}@Builderprivate 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 Mapprivate groupNameList: string[] = ['A区', 'B区', 'C区', 'D区', 'F区', 'G区', 'H区', 'J区', 'K区', 'L区']@State private selectGroupIndex: number = -1private categoryScroller: ListScroller = new ListScroller()private categoryScroller1: ListScroller = new ListScroller()private isClickScroll:boolean = falseaboutToAppear() {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 CategoriesTypethis.currentCategory = data.current[0]this.hotCategories = data.hotthis.groupCategories = data.Categoriesconsole.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]}@BuilderitemHead(text: string) {Text(text).fontSize(16).width("100%").padding({ left: 10 }).height(45).backgroundColor(0xEEEEEE)}@BuildercategoryList() {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})}@BuildernavigationList() {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 = truethis.selectGroupIndex = index// 通过导航选中selectGroupIndex与Scroller控制分区列表滚动到对应位置this.categoryScroller.scrollToIndex(index + 2, true, ScrollAlign.START)})}}, (item: string) => item)}.listDirection(Axis.Horizontal).backgroundColor(Color.Transparent).width('100%')}
}