ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

web-sys 实战:用 wasm-bindgen 构建调用 OpenWeather API 的天气报告应用

web-sys 实战:用 wasm-bindgen 构建调用 OpenWeather API 的天气报告应用 开发工具【免费下载链接】wasm-bindgenFacilitating high-level interactions between Wasm modules and JavaScript项目地址https://gitcode.com/gh_mirrors/wa/wasm-bindgen点击查看免费下载本指南基于 wasm-bindgen 仓库中的 weather_report 示例完整讲解如何用 Rust web-sys 构建一个真实可运行的天气报告应用通过 HTTP 请求调用 OpenWeather API解析 JSON 响应用 web-sys 的 DOM API 动态渲染 UI并通过spawn_local在 Wasm 环境中驱动异步任务。读完本文你将掌握#[wasm_bindgen(start)]入口、web_sys元素创建、EventListener事件绑定、wasm_bindgen_futures::spawn_local异步调度以及如何用 webpack wasm-pack 把整个应用打包跑在浏览器里。示例概览与运行方式天气报告示例examples/weather_report展示了 wasm-bindgen 全栈开发的基本链路向 OpenWeather API 发起 HTTP 请求获取城市天气在 Rust 侧解析 JSON 响应使用web_sys的 DOM API 从零搭建页面结构并渲染数据使用spawn_local处理异步任务网络请求、渲染回调通过#[wasm_bindgen(module /util.js)]导入 JS 模块调用 Google Maps 在地图上标记城市位置。本地构建与运行示例的 README.md 给出了三步启动方式$ npm install $ npm run build $ npm start然后浏览器访问 http://localhost:8080 即可运行示例。其中npm run build走的是 package.json 中定义的 webpack 构建流程其核心插件配置见 webpack.config.jsWasmPackPlugin负责把crateDirectory即示例目录中的 Rust crate 编译为pkg/HtmlWebpackPlugin以 index.html 为模板生成页面CopyWebpackPlugin把assets目录复制到输出最终产物输出到../dist/weather_report。注意运行前必须在 src/lib.rs 的get_response()函数中填入你自己的 OpenWeather API Key详见下文接入 OpenWeather API小节否则请求会被拒绝。工程配置Cargo.toml 依赖详解示例的 Cargo.toml 定义了完整依赖是理解本应用如何打通网络 → 异步 → DOM的关键[package] authors [Ayush ayushmishra2005gmail.com] edition 2021 name rust-webassembly-weather-reports publish false version 0.0.0 [lib] crate-type [cdylib] [dependencies] chrono 0.4.11 gloo 0.11 json 0.12 reqwest 0.13 wasm-bindgen { path ../../ } wasm-bindgen-futures { path ../../crates/futures } [dependencies.web-sys] features [Document, Element, HtmlElement, Window] path ../../crates/web-sys [lints] workspace true各依赖在应用中的职责依赖版本在本示例中的用途chrono0.4.11把 Unix 时间戳秒转换为 UTC 时间并格式化输出日出/日落时刻gloo0.11提供gloo::events::EventListener为按钮绑定跨生命周期的 click 事件json0.12解析 OpenWeather API 返回的 JSON 字符串通过下标访问字段reqwest0.13在 Wasm 中发起 HTTP GET 请求并读取响应文本wasm-bindgen仓库本地 path提供#[wasm_bindgen]宏、prelude以及JsValue错误类型wasm-bindgen-futures仓库本地 pathcrates/futures提供spawn_local在 Wasm 的微任务队列上调度异步 Futureweb-sys仓库本地 pathcrates/web-sys提供Document、Element、HtmlInputElement、Window等 DOM 类型注意[lib] crate-type [cdylib]wasm-bindgen 的库 crate 必须编译为cdylib最终产物才是可供import(./pkg)加载的 Wasm 模块。web-sys采用了按 feature 裁剪的引入方式只启用了Document、Element、HtmlElement、Window四个 feature其余上千个 DOM 绑定默认不编译从而显著减小 Wasm 体积。接入 OpenWeather API应用的数据源是 OpenWeather 的当前天气接口请求构建逻辑位于 get_response 函数// Get response from weather api async fn get_response(location: str) - JsonValue { let url1 http://api.openweathermap.org/data/2.5/weather?q; let url2 appidapiKey; let url [url1, location, url2].concat(); let resp reqwest::get(url).await.unwrap().text().await.unwrap(); json::parse(resp).unwrap() }要点说明请求 URL 由三段拼接而成接口地址http://api.openweathermap.org/data/2.5/weather?q 城市名 appidapiKey使用前必须把url2中的apiKey替换为你自己的 OpenWeather API Key在 OpenWeather 官网注册后获得这也是文档强调的Please add your api key inget_response()这一前置条件reqwest::get(...).await拿到响应后再次.text().await取出字符串最后用json::parse解析为JsonValue城市名来自用户输入框因此该函数支持任意城市查询。入口函数与页面骨架构建应用入口是带#[wasm_bindgen(start)]的run()函数src/lib.rs#[wasm_bindgen(start)] fn run() - Result(), JsValue { let window web_sys::window().expect(no global window exists); let document window.document().expect(should have a document on window); let body document.body().expect(document should have a body); ... Ok(()) }#[wasm_bindgen(start)]是 wasm-bindgen 提供的特殊属性Wasm 模块实例化完成后JS 侧会自动调用被标记的函数无需手动导出调用。这相当于 Rust 版的main()。入口先获取window→document→body三级引用任何一级失败都会expect直接 panic这在初始化场景中是合理的防御方式。随后run()通过web_sys的 DOM API 创建页面骨架整个构建过程大量使用示例自定义的两个辅助函数fn create_div(document: Document, id: str, class: str) - Element { let div document.create_element(div).unwrap(); div.set_id(id); div.set_class_name(class); div }create_div封装了创建元素 设置 id 设置 class三步create_input_box与create_submit_boxsrc/lib.rs则通过set_attribute依次设置搜索输入框和 Search 按钮的name、value、type、placeholder、id、class等属性。页面结构要点搜索区search_div输入框 提交按钮挂载到body详情区temp_div内部是一个两列布局——左列third_div依次挂载城市名fourth_div和结果表格table_div右列是map_div下的地图画布map_canvas_div结果表格通过create_element(table)/(tbody)/(tr)/(td)逐层append_child组装包含温度/天气、气压、湿度、日出、日落、地理坐标六行每个数据单元格如pressure、humidity、sunrise、sunset、geocoords都设置了唯一的id供异步渲染时定位写入所有append_child与set_attribute都返回Result代码里用?或expect(...)统一处理错误。静态页面样式来自 index.html 内嵌的 CSSReportStyles-*系列类名与assets/stylesheets/bootstrap.cssRust 侧创建的 DOM 元素通过set_class_name与这些样式对齐。事件绑定与内存管理EventListener forget搜索按钮的点击事件通过 gloo 的EventListener绑定src/lib.rslet on_click EventListener::new(submit_box, click, move |_event| { let input_value document .get_element_by_id(name) .unwrap() .dyn_into::HtmlInputElement() .unwrap() .value(); ... let response get_response(input_value); spawn_local(async move { ... }); }); on_click.forget();这里包含两个关键工程点类型转换get_element_by_id返回Element通过dyn_into::HtmlInputElement()向下转型为输入框类型再调用.value()读取用户输入的城市名Closure 生命周期EventListener内部封装了一个 JS 闭包。Rust 侧闭包一旦被 drop关联的 JS 回调就会失效。此处希望回调在整个程序生命周期内持续有效因此调用on_click.forget()主动泄漏它——这是 wasm-bindgen 中让 JS 回调长期存活的惯用手段正如源码注释所提醒的应谨慎使用避免不必要的内存泄漏影响程序。异步渲染spawn_local 的使用spawn_local是本文档明确点名的核心 API来自 crates/futures 提供的wasm_bindgen_futurescrate。从其源码crates/futures/src/lib.rs可以看到该 crate 现已是一个薄薄的转发层spawn_local、JsFuture、future_to_promise等均从js_sys::futures重新导出以保持向后兼容。点击事件内的完整异步流程src/lib.rsspawn_local(async move { let parsed response.await; let lon parsed[coord][lon].to_owned().as_f64().unwrap(); let lat parsed[coord][lat].to_owned().as_f64().unwrap(); initialize(lat, lon); let city_name: str parsed[name].to_owned().to_string(); let country_name: str parsed[sys][country].to_owned().to_string(); let place [city_name, ,, country_name].concat(); let icon parsed[weather][0][icon].to_owned().to_string(); let src [img srchttp://openweathermap.org/img/w/, icon, .png, ].concat(); let temp (parsed[main][temp].to_owned().as_f64().unwrap() - 273.15) as i64; let content [src, temp.to_string()].concat(); let p: str parsed[main][pressure].to_owned().to_string(); let h: str parsed[main][humidity].to_owned().to_string(); let sun_r (parsed[sys][sunrise].to_owned().as_f64().unwrap()) as u64; let sun_s (parsed[sys][sunset].to_owned().as_f64().unwrap()) as u64; temp_d.set_attribute(style, display: block).expect(failed to set attr style); city.set_inner_html(place); image.set_inner_html(content); weather.set_inner_html(parsed[weather][0][main].to_owned().to_string()); pressure.set_inner_html(([p, hpa].concat())); humidity.set_inner_html(([h, %].concat())); sunrise.set_inner_html(get_time(sun_r)); sunset.set_inner_html(get_time(sun_s)); geo.set_inner_html(([[, lon.to_string(), ,, lat.to_string(), ]].concat())); });这段代码演示了 wasm-bindgen 异步编程的几个核心模式response.await直取 JSONget_response返回的FutureOutput JsonValue在spawn_local的 async 块中被.await这是 Rust Future 与 JS Promise 桥接后的自然写法按 JSON 路径取值parsed[coord][lon]、parsed[main][temp]等链式下标访问配合as_f64()/to_string()做类型转换摄氏度换算OpenWeather 默认返回开尔文温度示例用temp - 273.15转换为摄氏度并取整DOM 写入把所有元素克隆进闭包temp_div.clone()等通过set_inner_html一次性写入渲染结果。注意temp_div的样式默认是display: none见 index.html 中.ReportStyles-mainContainer数据就绪后通过set_attribute(style, display: block)才显示详情区——这是典型的加载后再展示交互模式跨 JS 调用initialize(lat, lon)是在 util.js 中定义的 JS 函数通过#[wasm_bindgen(module /util.js)] extern C声明导入src/lib.rs用于在 Google Maps 上根据经纬度放置标记。时间格式化chrono 转换 UTC 时间OpenWeather 返回的日出/日落是 Unix 时间戳秒示例用chrono将其格式化为可读时间src/lib.rs// Convert millisecond into UTC date fn get_time(millis: u64) - String { let d UNIX_EPOCH Duration::from_secs(millis); // Create DateTime from SystemTime let datetime DateTime::Utc::from(d); // Formats the combined date and time with the specified format string. datetime.format(%H:%M:%S).to_string() }流程为std::time::UNIX_EPOCH Duration::from_secs(秒数)构造SystemTime再经DateTime::Utc::from转换为 UTC 时间最后按%H:%M:%S时:分:秒格式化输出。这也是表格中Sunrise[UTC]、Sunset[UTC]两行数据的来源。运行效果与预期界面构建并运行后页面上方是标题栏与搜索输入框输入城市名示例默认填入Delhi并点击 Search 按钮后详情区显示该城市的天气图标与温度、天气类型如 Haze、气压单位 hPa、湿度单位 %、日出/日落时间UTC与地理坐标右侧 util.js 借助 Google Maps 在地图画布map_canvas中标记城市位置。示例仓库的 assets/images/weather.png 记录了搜索Delhi,IN时的真实运行结果气温 32℃、天气 Haze、气压 1004hPa、湿度 55%、日出 5:59:47、日落 18:41:40并在地图上以红色标记标注了德里位置可用于对照验证自己的运行输出。从示例到生产关键注意事项API Key 必填get_response()中appidapiKey是硬编码占位符不替换任何真实 Key 都无法拿到数据HTTP 明文接口示例使用http://协议访问 OpenWeather 与 Google Maps部署到 HTTPS 环境时浏览器会拦截混合内容生产环境应改用https://内存泄漏是有意为之on_click.forget()让事件回调常驻适用于程序生命周期内始终有效的场景若回调只在有限时间内需要应改为在适当时机 drop 以释放内存体积控制web-sys的 feature 裁剪仅启用 4 个 DOM feature是 wasm-bindgen 生态控制 Wasm 体积的标准做法按需开启Document、Element等 feature避免编译进用不到的绑定代码异步错误处理示例中reqwest与 JSON 解析大量使用unwrap()教学场景直观但不够健壮生产代码建议改用Result传播与?运算符并向前端返回可读错误信息。从完整源码中可以看到这个示例将 wasm-bindgen 的核心能力——#[wasm_bindgen(start)]入口、#[wasm_bindgen(module)]JS 导入、spawn_local异步调度、web-sys DOM 操作、闭包生命周期管理——串联成了一个真实可用的 Web 应用是学习 Rust 全栈 Wasm 开发的最佳起点之一。类似的实战组合还可以参考仓库中其他示例如 fetch、canvas、closures 等它们共同构成了 wasm-bindgen 的完整示例矩阵见 guide/src/examples。赞分享开发工具【免费下载链接】wasm-bindgenFacilitating high-level interactions between Wasm modules and JavaScript项目地址https://gitcode.com/gh_mirrors/wa/wasm-bindgen点击查看免费下载相关推荐从景区语音导览到凌晨语音客服语音AI智能体落地的五道验收关卡实战从景区语音导览到凌晨语音客服语音AI智能体落地的五道验收关卡实战 语音AI智能体项目翻车很少翻在模型上第一句语音回答迟迟出不来答错了拿不出依据上线两周开发工具go-app天气应用构建实时天气预报Web应用go app天气应用构建实时天气预报Web应用 你是否曾想过用Go语言开发一个既美观又实用的Web应用本文将带你从零开始使用go app框架构建一个实时天前端Web框架WebAssembly大麦自动抢票工具实操手册部署、配置与成功率优化全解析大麦自动抢票工具实操手册部署、配置与成功率优化全解析 ticket purchase 是一个针对大麦网的自动抢票开源工具基于 Python 实现网页端与移动开发工具上一篇如何快速解决TranslucentTB启动失败Microsoft.UI.Xaml依赖问题的完整指南下一篇WeMod 免费版时长限制为什么 Wand-Enhancer 10 分钟就能离线拆掉创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表