问题现象
页面一使用requestFocus通过组件id获焦成功,然后路由至页面二,再然后路由至页面一,此时为什么无法使用requestFocus通过组件id获焦?
主页代码示例参考如下:
// 主页
@Entry
@Component
struct NavigationIndex {
@Provide('pathInfos') pathInfos: NavPathStack = new NavPathStack();
private listArray: string[] = ['WLAN', 'Connect & Share'];
build() {
Column() {
Navigation(this.pathInfos) {
TextInput({ placeholder: '输入关键字搜索' })
.width('90%')
.height(40)
.margin({ bottom: 10 });
// 通过List定义导航的一级界面
List({ space: 12, initialIndex: 0 }) {
ForEach(this.listArray, (item: string) => {
ListItem() {
Row() {
Row() {
Text(${item.slice(0, 1)})
.fontColor(Color.White)
.fontSize(14)
.fontWeight(FontWeight.Bold);
}
.width(30)
.height(30)
.backgroundColor('#a8a8a8')
.margin({ right: 20 })
.borderRadius(20)
.justifyContent(FlexAlign.Center);
Column() {
Text(item)
.fontSize(16)
.margin({ bottom: 5 });
}
.alignItems(HorizontalAlign.Start);
Blank();
Row()
.width(12)
.height(12)
.margin({ right: 15 })
.border({
width: { top: 2, right: 2 },
color: 0xcccccc
})
.rotate({ angle: 45 });
}
.borderRadius(15)
.shadow({ radius: 100, color: '#ededed' })
.width('90%')
.alignItems(VerticalAlign.Center)
.padding({ left: 15, top: 15, bottom: 15 })
.backgroundColor(Color.White);
}
.width('100%')
.onClick(() => {
this.pathInfos.pushPathByName(`${item}`, '');
});
}, (item: string): string => item);
}
.listDirection(Axis.Vertical)
.edgeEffect(EdgeEffect.Spring)
.sticky(StickyStyle.Header)
.chainAnimation(false)
.width('100%');
}
.width('100%')
.mode(NavigationMode.Auto)
.title('设置'); // 设置标题文字
}
.size({ width: '100%', height: '100%' })
.backgroundColor(0xf4f4f5);
}
}
页面一代码示例参考如下:
// 页面一
@Builder
export function PageOneBuilder(name: string) {
PageOne({ name: name });
}
@Component
struct PageOne {
pathInfos: NavPathStack = new NavPathStack();
name: string = '';
@State isShow: boolean = false;
@Builder
textBuilder(id: string) {
TextInput()
.width('90%')
.id(id)
.onSubmit(() => {
this.isShow = true;
})
.onAppear(() => {
try {
this.getUIContext().getFocusController().requestFocus(id);
console.info(Succeeded in appearing component. name: ${this.name}, id ${id}.);
} catch (e) {
console.error(Failed to appear component. code: ${e.code}, message: ${e.message});
}
});
}
build() {
NavDestination() {
Column({ space: 24 }) {
this.textBuilder(${this.name}1);
if (this.isShow) {
this.textBuilder(${this.name}2);
}
Button('next')
.width('50%')
.height(40)
.margin({ top: 50 })
.onClick(() => {
// 弹出路由栈栈顶元素,跳转'Connect & Share'页面
this.pathInfos.pushPathByName(Connect & Share, '');
});
}
.size({ width: '100%', height: '100%' });
}
.title(${this.name})
.onReady((ctx: NavDestinationContext) => {
// NavDestinationContext获取当前所在的导航控制器
this.pathInfos = ctx.pathStack;
})
.onShown(() => {
this.isShow = false;
});
}
}
页面二跳转页面一代码示例参考如下:
// 页面二
@Builder
export function PageTwoBuilder(name: string) {
PageTwo({ name: name });
}
@Component
struct PageTwo {
pathInfos: NavPathStack = new NavPathStack();
name: string = '';
@State isShow: boolean = false;
build() {
NavDestination() {
Column({ space: 5 }) {
Button('next')
.width('50%')
.height(40)
.margin({ top: 5 })
.onClick(() => {
// 跳转到WLAN
this.pathInfos.pushPath({ name: 'WLAN', param: '' });
});
}
.size({ width: '100%', height: '100%' });
}
.title(${this.name})
.onReady((ctx: NavDestinationContext) => {
// NavDestinationContext获取当前所在的导航控制器
this.pathInfos = ctx.pathStack;
})
.onShown(() => {
this.isShow = false;
});
}
}
背景知识
Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏。其中NavPathStack导航控制器提供多种跳转方式,具体参考LaunchMode。
组件标识(id)为组件的唯一标识,在整个应用内唯一。
问题定位
当由页面一路由至页面二后,页面二重新路由至页面一,传参保持不变,组件最后id为“WLAN1”和“WLAN2”,与路由栈内存在的页面一组件id一致,因此id赋值失败,requestFocus找不到对应组件。报错信息如下:
Error code: 150003, Error message: The component doesn't exist, is currently invisible, or has been disabled.
分析结论
路由栈内存在已有同id组件,因此新页面组件id赋值失败,requestFocus找不到对应组件。
修改建议
路由逻辑:主页跳转页面一,页面一跳转页面二,页面二跳转页面一。
方案一:消除同id组件。
方式一:页面一跳转页面二时,跳转方法使用replacePathByName,用新页面替换旧组件所在页面。
// 弹出路由栈栈顶元素,跳转'Connect & Share'页面
this.pathInfos.replacePathByName(Connect & Share, '详情页面参数');
方式二:页面二跳转页面一时,跳转模式MOVE_TO_TOP_SINGLETON或者POP_TO_SINGLETON,使用原页面。
// 跳转到WLAN
this.pathInfos.pushPath({ name: 'WLAN', param: '' }, { launchMode: LaunchMode.MOVE_TO_TOP_SINGLETON });
方案二:使用新的组件id。
根据页面传入的不同数据,重新命名id。name参数或者param参数均可,如下例子为name参数。
主页跳转页面一:
this.pathInfos.pushPathByName('WLAN', '');
页面二跳转页面一:
this.pathInfos.pushPathByName('Bluetooth', '');
路由表router_map.json如下:
{
"routerMap": [
{
"name": "WLAN",
"pageSourceFile": "src/main/ets/pages/ProblemPage.ets",
"buildFunction": "PageOneBuilder"
},
{
"name": "Bluetooth",
"pageSourceFile": "src/main/ets/pages/ProblemPage.ets",
"buildFunction": "PageOneBuilder"
},
{
"name": "Connect & Share",
"pageSourceFile": "src/main/ets/pages/ProblemPage.ets",
"buildFunction": "PageTwoBuilder"
}
]
}
常见FAQ
Q:使用HMRouter三方库进行页面跳转是否也有上述问题?
A:有上述问题。HMRouter三方库是基于Navigation实现的。
Q:为什么使用replace没有出现上述问题?
A:本质原因是路由栈中只有一个页面一,因此无重复使用同一id问题。首先页面一跳转页面二使用replace,此情况下栈中只存在页面二,下次跳转页面一后,栈中只有一个页面一。其次页面二跳转页面一使用MOVE_TO_TOP_SINGLETON或者POP_TO_SINGLETON跳转模式,此模式为单例跳转,跳转后栈中只存在一个页面一。
总结
id为组件的唯一标识,在整个应用内唯一。其他组件不可使用已命名的id,同时id命名以最新的id为准。
https://coub.com/view/9tjqrj50va
https://coub.com/view/rb2xb8a4n5
https://coub.com/view/5b79yniyth
https://coub.com/view/wamid4rm21
https://coub.com/view/zaw8d5yz2e
https://coub.com/view/zniccr5gwr
https://coub.com/view/3399xuazi1
https://coub.com/view/lsrnrbztyl
https://coub.com/view/x1m7lryfzq
https://coub.com/view/37xic534xp
https://coub.com/view/e4ot7q9l4a
https://coub.com/view/7xfg675fke
https://coub.com/view/cd5uv7n8di
https://coub.com/view/2yftocq9eo
https://coub.com/view/iz8k9vdeoq
https://coub.com/view/ss942ngulq
https://coub.com/view/0otxz11rt6
https://coub.com/view/t380otx63g
https://coub.com/view/s5jv5wwpp8
https://coub.com/view/uqzz8yd5t0
https://coub.com/view/v5mqk9pi4b
https://coub.com/view/3x24yjjngs
https://coub.com/view/bgr3qxu81y
https://coub.com/view/aczggz0c7l
https://coub.com/view/19x48j87yh
https://coub.com/view/mhj9o7akb8
https://coub.com/view/t52hno1jvx
https://coub.com/view/xd692lkh1w
https://coub.com/view/45f8w8eqt6
https://coub.com/view/7ufkfov20r
https://coub.com/view/aracs9rxr1
https://coub.com/view/usxdnvf69s
https://coub.com/view/xn4zgcqewo
https://coub.com/view/feshuj117i
https://coub.com/view/bo1naj1hg3
https://coub.com/view/0ooh9cdel4
https://coub.com/view/3r5m3lecc0
https://coub.com/view/u0e1fs4r10
https://coub.com/view/im9tfsm0vb
https://coub.com/view/xn9sc0dl48
https://coub.com/view/okd6f44ahj
https://coub.com/view/2ul6cv24s5
https://coub.com/view/2wiiaa2m0v
https://coub.com/view/kdm5dqnfm9
https://coub.com/view/v0mkw3fy9q
https://coub.com/view/xf417qh06w
https://coub.com/view/p7o9bdx3hd
https://coub.com/view/a4c7cs4za4
https://coub.com/view/2m9q5l3tye
https://coub.com/view/l5wijck89c
https://coub.com/view/7uv550mvcv
https://coub.com/view/hinzf3owe6
https://coub.com/view/2xs4q3hodd
https://coub.com/view/z2sz46ny5w
https://coub.com/view/fnxtc5jxkn
https://coub.com/view/idp6ix7wa7
https://coub.com/view/143z08ound
https://coub.com/view/xh81ng97rv
https://coub.com/view/b6idbpkjwm
https://coub.com/view/japbulumr8
https://coub.com/view/lzxbq7ueb8
https://coub.com/view/rykuydlgya
https://coub.com/view/g0bcawp1uo
https://coub.com/view/2dha0vzzq9
https://coub.com/view/nnbmf46ubp
https://coub.com/view/k4bl2myg5o
https://coub.com/view/tw1cs9daax
https://coub.com/view/w6k3awnqf7
https://coub.com/view/ufi6kkw1pn
https://coub.com/view/smcemgyolt
https://coub.com/view/n7zx8jkeqx
https://coub.com/view/zejw3zqzj9
https://coub.com/view/3yb82a6rzb
https://coub.com/view/2yfowuwqug
https://coub.com/view/d71yoe6vki
https://coub.com/view/qtoldx6o14
https://coub.com/view/ww8hn3f0ng
https://coub.com/view/m01ucwuhs9
https://coub.com/view/hjur00uu7a
https://coub.com/view/hxqok76tx8
0 个评论
要回复文章请先登录或注册