euv 中的浏览器存储与导航
在构建 Web 应用程序时,两个常见的需求是持久化数据存储和基于 URL 的导航。euv 通过其 window() 函数提供了对浏览器 API 的直接访问,让你能够与 localStorage、sessionStorage 以及浏览器的 Location 对象进行交互。本文将介绍如何在 euv 框架中有效使用这些 API,包括读写存储、操作 URL 哈希值以及构建导航模式。
访问浏览器窗口
euv 中所有浏览器 API 的访问都从 window() 函数开始,它返回一个 Window 句柄。通过这个句柄,你可以访问文档、位置和各种存储机制:
let win: Window = window().expect("no global window exists");
let doc: Document = win.document().expect("should have a document");
window() 函数返回 Option<Window>,因此你应该始终处理它可能为 None 的情况(例如,在服务端渲染等非浏览器环境中运行)。实际上,对于在浏览器中运行的 WASM 应用,这总是会成功。
一旦你获得了 Window 句柄,就可以访问 Document 进行 DOM 操作,访问 Location 进行导航。
使用 localStorage
localStorage 提供了持久化的键值存储,数据在浏览器重启后仍然存在。euv 通过 Window 上的 local_storage() 方法暴露了它:
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
let _ = storage.set_item("key", "value");
let value: Option<String> = storage.get_item("key").unwrap_or_default();
}
让我们分解一下发生了什么:
win.local_storage()返回Option<Storage>。如果浏览器支持 localStorage(所有现代浏览器都支持),这将返回Some(storage)。set_item("key", "value")将值写入存储。它返回一个Result,你可以使用let _ =来忽略错误。get_item("key")从存储中读取值,返回Option<String>。.unwrap_or_default()将None(键未找到)转换为空字符串。
存储复杂数据
由于 localStorage 只存储字符串,你需要对复杂数据进行序列化和反序列化。euv 的 JavaScript 互操作能力使得使用 JSON 成为可能:
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
let _ = storage.set_item("user_name", "Alice");
let name: Option<String> = storage.get_item("user_name").unwrap_or_default();
}
对于更复杂的场景,你可以将 spawn_local 与 JsFuture 结合使用,通过 JavaScript 的 JSON.stringify 和 JSON.parse 进行序列化。
实际示例:持久化用户偏好
一个常见的用例是在不同会话之间持久化用户偏好设置:
let win: Window = window().expect("no global window exists");
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
let _ = storage.set_item("theme", "dark");
let theme: String = storage.get_item("theme").unwrap_or_default();
}
你可以将这与 watch! 结合使用,在响应式信号变化时自动保存偏好设置,确保存储的状态始终是最新的。
使用 Location 对象
Location 对象提供了对当前 URL 的访问以及导航方法:
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
let _ = location.set_hash("#/about");
读取当前哈希值
location.hash() 返回当前 URL 的哈希值(# 后面的部分),这通常用于单页应用中的客户端路由:
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
你可以使用这个哈希值来确定应该显示哪个视图或组件,在不重新加载页面的情况下实现客户端路由。
设置哈希值进行导航
location.set_hash() 更改 URL 哈希值,这会触发浏览器的哈希变更事件:
let _ = location.set_hash("#/about");
这会更新 URL 使其包含 #/about,而不会重新加载页面。结合条件渲染模式,你可以构建一个完整的客户端路由器:
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
// 使用哈希值来确定要渲染哪个页面
构建基于哈希的路由
通过将 location.hash() 与响应式信号和 watch! 结合,你可以构建一个简单但有效的路由系统:
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
watch!(hash, |h| {
// 响应哈希变更并更新显示的页面
});
结合存储与导航
存储和导航通常协同工作。例如,你可能想将当前页面状态保存到存储中,这样当用户返回应用时,他们会被带到同一个页面:
let win: Window = window().expect("no global window exists");
let location: Location = win.location();
let hash: String = location.hash().unwrap_or_default();
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
let _ = storage.set_item("last_page", &hash);
let last_page: String = storage.get_item("last_page").unwrap_or_default();
}
这种模式通过恢复用户之前的状态来提供更好的用户体验。
使用 Document 对象
除了存储和位置,Document 对象还让你可以访问完整的 DOM:
let win: Window = window().expect("no global window exists");
let doc: Document = win.document().expect("should have a document");
你可以使用 Document 来创建元素、查询选择器以及执行其他 DOM 操作。
错误处理注意事项
浏览器 API 可能因各种原因失败——存储可能已满、浏览器可能限制访问,或者环境可能不支持某些功能。始终正确处理 Option 和 Result 类型:
let storage: Option<Storage> = win.local_storage().unwrap_or_default();
if let Some(storage) = storage {
let _ = storage.set_item("key", "value");
let value: Option<String> = storage.get_item("key").unwrap_or_default();
}
对存储使用 if let Some(...),对单个值使用 .unwrap_or_default(),确保你的应用在浏览器 API 不可用时能够优雅降级。
总结
euv 通过 window() 函数及其相关对象提供了对浏览器存储和导航 API 的直接访问。通过利用 localStorage 进行持久化数据存储、Location 进行基于 URL 的导航,以及 Document 进行 DOM 访问,你可以构建功能完备的 Web 应用程序,支持数据持久化和客户端路由。这些 API 与 euv 的响应式系统自然集成——你可以使用 watch! 响应哈希变更,将响应式信号值存储到 localStorage,并创建丰富的、感知状态的导航体验。