You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tauri-Leptos应用中监听后端值变化?

高效监听Windows注册表主题变化(Tauri+Leptos)

你的当前方案用前端无限轮询注册表值,确实会占用大量CPU资源;而直接用std::thread::sleep会阻塞异步任务,tokio::sleep因为运行时上下文不匹配也无法正常工作。更优的方案是后端主动监听注册表变化,通过Tauri事件系统推送给前端,彻底避免轮询。

解决方案步骤

1. 后端实现注册表变化监听

利用Windows原生API RegNotifyChangeKeyValue 监听目标注册表键的修改,当值变化时主动向前端发送事件。

首先确保你的Cargo.toml添加必要依赖:

[dependencies]
tauri = { version = "1.5", features = ["api-all"] }
winapi = { version = "0.3", features = ["winreg", "handleapi"] }
tokio = { version = "1.0", features = ["spawn_blocking"] }

修改后端代码,添加监听逻辑:

use tauri::{AppHandle, Manager};
use winapi::{
    shared::minwindef::DWORD,
    um::{
        winreg::{RegCloseKey, RegNotifyChangeKeyValue, RegOpenKeyExW},
    },
};
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use tokio::task;

// 原有的is_light_theme命令保留
#[tauri::command]
fn is_light_theme() -> String {
    let theme = helpers::is_light_theme();
    format!("{}", theme)
}

// 启动注册表监听任务
fn start_theme_listener(app_handle: AppHandle) {
    task::spawn_blocking(move || {
        let hkey = winapi::um::winreg::HKEY_CURRENT_USER;
        // 转换为宽字符(Windows API要求)
        let subkey: Vec<u16> = OsStr::new(r#"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"#)
            .encode_wide()
            .chain(std::iter::once(0))
            .collect();
        let mut key = ptr::null_mut();

        // 打开注册表键,需要KEY_NOTIFY权限
        let result = unsafe {
            RegOpenKeyExW(
                hkey,
                subkey.as_ptr(),
                0,
                winapi::um::winreg::KEY_QUERY_VALUE | winapi::um::winreg::KEY_NOTIFY,
                &mut key,
            )
        };

        if result != 0 {
            eprintln!("打开注册表键失败: {}", result);
            return;
        }

        loop {
            // 阻塞等待注册表变化通知
            let result = unsafe {
                RegNotifyChangeKeyValue(
                    key,
                    0, // 不监听子键
                    winapi::um::winreg::REG_NOTIFY_CHANGE_LAST_SET, // 监听值修改
                    ptr::null_mut(), // 无事件对象,阻塞等待
                    1, // 通知后继续监听
                )
            };

            if result != 0 {
                eprintln!("注册注册表变化通知失败: {}", result);
                break;
            }

            // 获取最新主题值并发送给前端
            let is_light = helpers::is_light_theme();
            let _ = app_handle.emit_all("theme-changed", is_light.to_string());
        }

        // 关闭注册表键
        unsafe {
            RegCloseKey(key);
        }
    });
}

fn main() {
    tauri::Builder::default()
        .setup(|app| {
            // 启动监听任务
            start_theme_listener(app.handle());
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![is_light_theme])
        .run(tauri::generate_context!())
        .expect("运行Tauri应用失败");
}

2. 前端Leptos监听事件

前端不再需要轮询,只需要初始化时获取一次初始值,然后监听后端发送的theme-changed事件更新信号:

use leptos::*;
use tauri::{invoke, listen};

#[component]
pub fn App() -> impl IntoView {
    let (is_light_theme, set_is_light_theme) = create_signal(String::new());

    // 获取初始主题值
    spawn_local(async move {
        let initial_value = invoke("is_light_theme", to_value("").unwrap())
            .await
            .as_string()
            .unwrap_or_else(|| "false".to_string());
        set_is_light_theme.set(initial_value);
    });

    // 监听后端的主题变化事件
    spawn_local(async move {
        let _listener = listen("theme-changed", |event| {
            let new_value = event.payload().unwrap_or("false").to_string();
            set_is_light_theme.set(new_value);
        })
        .await
        .unwrap();

        // 保持listener存活,避免被销毁
        futures::future::pending().await;
    });

    view! {
        <div>
            <p>"当前主题:" {move || is_light_theme.get()}</p>
        </div>
    }
}

为什么之前的sleep会失效?

你用spawn_local创建的是Wasm异步任务,运行在浏览器的事件循环中:

  • std::thread::sleep是阻塞线程的操作,会直接卡死Wasm的事件循环,导致后续代码无法执行;
  • tokio::sleep依赖Tokio runtime,而spawn_local属于wasm_bindgen_futures的上下文,两者不兼容,所以无法正常休眠。

内容的提问来源于stack exchange,提问作者Grayza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:17:34