当前位置:网站首页>FlutterWeb瀏覽器刷新後無法回退的解决方案
FlutterWeb瀏覽器刷新後無法回退的解决方案
2022-07-06 17:40:00 【代碼不難寫】
問題
在Flutter開發的網頁運行時,瀏覽器刷新網頁後,雖然會顯示刷新前的頁面(前提是用靜態路由跳轉),但這時調用Navigator.pop方法是回不到上一頁的,包括點擊瀏覽器的回退按鈕也是無效的(地址欄中的url會變,頁面不會變)。
原因
當瀏覽器刷新時,Flutter引擎會重新啟動,並加載當前頁面,也就是說,刷新後的Flutter內存中所有靜態變量都被初始化,頁面棧內之前的頁面記錄都未保留,只有當前的頁面。就像是瀏覽網頁時,把其中一頁的網址拷出來,在新的標簽頁再次打開。
解决方案
(一)思路
知道什麼原因引起的,就針對性解决。頁面棧記錄丟失,那麼就代碼中自己維護一套備用棧,監聽頁面路由,每次進入新頁面時,記錄當前頁面的URL,當退出時,删除記錄的URL,在瀏覽器刷新棧記錄失效時,幫助回退到上一頁。
(二)方案優缺點
優點: 可實現回退效果無异常,調用Navigator.pop方法或點擊瀏覽器回退按鈕都支持;
缺點: Navigator.pushName().then的回調無法生效,因為是重新生成的上一頁,所以並不會調用回調;回退後的頁面中的臨時數據都會消失,比如輸入框內的內容,成員變量等;跳轉必須用靜態路由的方式,並且傳參要用Uri包裹,不能用構造函數傳參。
實現
1. Web本地存儲工具—localStorage
localStorage是在html包下window中的一個存儲對象,以key、value的形式進行存儲
// 導包
import 'dart:html' as html;
// 使用方式
html.window.localStorage["key"] = "value"
對存儲工具的封裝這裏就不寫到文章裏了,根據實現業務情况去封裝,方便調用就行。
2. 棧記錄工具類RouterHistory
這是一個棧記錄工具,主要作用是注册監聽,添加删除記錄等。
/// DB()為封裝好的本地數據庫
class RouterHistory {
/// 監聽瀏覽器刷新前的回調
static Function(html.Event event)? _beforeUnload;
/// 監聽瀏覽器回退時的回調
static Function(html.Event event)? _popState;
/// 目前頁面是否被刷新過
static bool isRefresh = false;
/// 初始化與注册監聽
static void register() {
// 刷新時回調
_beforeUnload = (event) {
// 本地記錄,標記成"已刷新"
DB(DBKey.isRefresh).value = true;
// 移除刷新前的實例的監聽
html.window.removeEventListener('beforeunload', _beforeUnload);
html.window.removeEventListener('popstate', _popState);
};
// 瀏覽器回退按鈕回調
_popState = (event) {
// 頁面被刷新,觸發備用回調
if (isRefresh) {
_back(R.currentContext); //R.currentContext 為當前頁面的Context
}
};
// 添加監聽
html.window.addEventListener('beforeunload', _beforeUnload);
html.window.addEventListener('popstate', _popState);
// 從本地數據庫中取出"刷新"標記
isRefresh = DB(DBKey.isRefresh).get(false);
// 如果未被刷新,清除上次備用棧中的曆史記錄
if (!isRefresh) {
clean();
}
// 還原本地庫中的刷新標記
DB(DBKey.isRefresh).value = false;
}
static bool checkBack(currentContext) {
// 是否能正常 pop
if (Navigator.canPop(currentContext)) {
return true;
}
// 不能則啟用備用棧
_back(currentContext);
return false;
}
// 返回
static void _back(currentContext) {
List history = get();
if (history.length > 1) {
history.removeLast();
set(history);
//跳轉至上一頁並關閉當前頁
Navigator.of(currentContext).popAndPushNamed(history.last);
}
}
// 添加記錄
static add(String? path) {
if (path == null) return;
List history = get();
if (history.contains(path)) return;
history.add(path);
set(history);
}
// 删除記錄
static remove(String? path) {
if (path == null) return;
List history = get();
history.remove(path);
set(history);
}
// 設置備用棧數據
static String set(List<dynamic> history) => DB(DBKey.history).value = json.encode(history);
// 取出備用棧數據
static get() => json.decode(DB(DBKey.history).get('[]'));
// 清除備用棧
static clean() => DB(DBKey.history).value = '[]';
}
3. 監聽Flutter路由
自定義類並實現NavigatorObserver,並將實現類放在MaterialApp中的navigatorObservers參數中。
// 實現類
class HistoryObs extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
// 存路由信息
RouterHistory.add(route.settings.name);
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
// 删路由信息
RouterHistory.remove(route.settings.name);
}
}
// 設置監聽
MaterialApp(
......
navigatorObservers: [ HistoryObs() ],
......
)
4. 路由方法封裝
跳轉方法必須為靜態路由,以保證參數和路徑都能在url中,才可實現回退效果
/// 替換 Navigator.pop ,
static pop() {
// 檢測是否能正常返回,不能則返回FALSE
if (RouterHistory.checkBack(currentContext)) {
Navigator.pop(currentContext);
}
}
/// 靜態路由跳轉
static Future toName(String pageName, {Map<String, dynamic>? params}) {
// 封裝路徑以及參數
var uri = Uri(scheme: RoutePath.scheme, host: pageName, queryParameters: params ?? {});
return Navigator.of(currentContext).pushNamed(uri.toString());
}
5. 初始化比特置
放在MaterialApp外層的build中,或initState中即可。
@override
void initState() {
super.initState();
RouterHistory.register();
}
@override
Widget build(BuildContext context) {
// 或 RouterHistory.register();
return MaterialApp(
navigatorObservers: [MiddleWare()],
);
}
以上就是該方案的關鍵代碼
最後
該方案只是能解决問題,但不是最好的解决方案。有更好的解决方案歡迎留言~
Flutter官方的Navigator 2.0 雖然能實現回退,本質上也是跳轉了新頁面,並造成棧內記錄混亂,不能像真正的web一樣,感興趣的同學可以自行了解下Navigator 2.0。
Navigator2.0在瀏覽器回退按鈕的處理上又與Navigator1.0不同,點擊回退按鈕時Navigator2.0並不是執行pop操作,而是執行setNewRoutePath操作,本質上應該是從瀏覽器的history中獲取上一個頁面的url,然後重新加載。這樣確實解决了刷新後回退的問題,因為刷新後瀏覽器的history並未丟失,但是也導致了文章中我們提到的flutter中的頁面棧混亂的問題。
如果你進階的路上缺乏方向,可以掃描下方二維碼加入我們的圈子和安卓開發者們一起學習交流!
-以下全部內容都可以在微信中獲取!
Android進階學習全套手册
Android對標阿裏P7學習視頻
BATJ大廠Android高頻面試題
作者:蘇啵曼
鏈接:https://juejin.cn/post/7114848130004156446
边栏推荐
- 信息与网络安全期末复习(基于老师给的重点)
- CTF逆向入门题——掷骰子
- 微信防撤回是怎么实现的?
- Spark calculation operator and some small details in liunx
- Xin'an Second Edition: Chapter 26 big data security demand analysis and security protection engineering learning notes
- Total / statistics function of MySQL
- [translation] principle analysis of X Window Manager (I)
- 基于LNMP部署flask项目
- 网络分层概念及基本知识
- The NTFS format converter (convert.exe) is missing from the current system
猜你喜欢
02 personal developed products and promotion - SMS platform
C#版Selenium操作Chrome全屏模式显示(F11)
C # nanoframework lighting and key esp32
关于Selenium启动Chrome浏览器闪退问题
BearPi-HM_ Nano development board "flower protector" case
Pyspark operator processing spatial data full parsing (5): how to use spatial operation interface in pyspark
TCP连接不止用TCP协议沟通
Solr appears write Lock, solrexception: could not get leader props in the log
Deploy flask project based on LNMP
微信防撤回是怎么实现的?
随机推荐
TCP连接不止用TCP协议沟通
Flink parsing (III): memory management
Uipath browser performs actions in the new tab
Solrcloud related commands
远程代码执行渗透测试——B模块测试
06 products and promotion developed by individuals - code statistical tools
Openharmony developer documentation open source project
Flink parsing (V): state and state backend
MySQL stored procedure
Deploy flask project based on LNMP
04 products and promotion developed by individuals - data push tool
Vscode replaces commas, or specific characters with newlines
华为认证云计算HICA
mysql高級(索引,視圖,存儲過程,函數,修改密碼)
Flink analysis (II): analysis of backpressure mechanism
Start job: operation returned an invalid status code 'badrequst' or 'forbidden‘
Xin'an Second Edition: Chapter 24 industrial control safety demand analysis and safety protection engineering learning notes
Selenium test of automatic answer runs directly in the browser, just like real users.
[translation] principle analysis of X Window Manager (I)
BearPi-HM_ Nano development environment