<tauri><rust><GUI>基于rust和tauri,实现多窗口与窗口间通信

前言

本文是基于rust和tauri,由于tauri是前、后端结合的GUI框架,既可以直接生成包含前端代码的文件,也可以在已有的前端项目上集成tauri框架,将前端页面化为桌面GUI。

环境配置

  1. 系统:windows 10
  2. 平台:visual studio code
  3. 语言:rust、javascript
  4. 库:tauri2.0

概述

本文主要说明,在tauri中如何实现多窗口以及窗口间如何实现数据传递。

1、创建前端项目

可以参考我之前的博文,本文不再赘述:

1、< tauri>< rust>< GUI>使用tauri实现一个简单的计算器程序

我们创建新的页面代码,因为我们要实现多窗口,本例以两个窗口来举例,那么我们将创建两个页面,首先是主页面:

html 复制代码
<div id="tauriappdiv" class="tauriappdiv">
    <div id="zone1div">
        <label for="windownameinput">窗口标签(唯一):</label>
        <input id="windownameinput" type="text" placeholder="请输入窗口名称">
        <button id="newwindowbtn">新建窗口</button>
    </div>
    <div id="zone2div">
        <div id="zone2div0">
            <div>
            <label for="windowlabelinput">窗口标签:</label>
            <input id="windowlabelinput" type="text" placeholder="请输入窗口标签">     
            </div>
            <div>
                <label for="sendmsginput">消息:</label>
                <input id="sendmsginput" type="text" placeholder="请输入消息">
            </div>
        </div>
        <button id="sendmsgbtn">发送消息给子窗口</button>
    </div>
     <div id="zone3div">
        <button id="eventbtn">触发事件</button>
        <button id="channelbtn">触发通道</button>
        <button id="eventtosubbtn">触发事件给子窗口</button>
    </div>
    <div>
        <p id="showeventmsg"></p>
        <p id="showchannelmsg"></p>
        <p>来自子窗口:</p>
        <p id="msgfromsub"></p>
    </div>
</div>

页面预览如下: 然后创建一个子页面:

html 复制代码
<div>
    <h1>子窗口</h1>
    <div>
        <p>来自主窗口:</p>
        <p id="mainwindowmsg"></p>
    </div>
    <div>
        <input id="sendmsginput" type="text" placeholder="输入消息">
        <button id="sendmsgtomainbtn" type="button">发送给主窗口</button>
    </div>
</div>

预览如下:

2、创建子窗口

我们要实现的功能是,在主窗口,通过按钮创建子窗口,注意,子窗口必须要有一个唯一的标签名,哪怕你不给窗口输入名字,它的标签就是空字符,也是不能重复的,如果想要创建两个标签名一样的子窗口,会报错:

如何在tauri中创建子窗口,tauri官网给出了两个方法,第一个是静态创建,可以通过tauri.conf.json这个配置文件来实现:

上图是官网的示例,这个方法很简单,但是我们不使用这种方法,我们使用官网提供的第二种方法,即通过代码来创建新窗口:

rust 复制代码
tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![greet])
    .setup(|app| {
        let webview_url = tauri::WebviewUrl::App("index.html".into());
        // First window
        tauri::WebviewWindowBuilder::new(app, "first", webview_url.clone())
            .title("First")
            .build()?;
        // Second window
        tauri::WebviewWindowBuilder::new(app, "second", webview_url)
            .title("Second")
            .build()?;
        Ok(())
    })
    .run(context)
    .expect("error while running tauri application");

这是官网的示例代码,在tauri程序初始化时,会加载两个窗口。这是简单的示例,我们在实际应用时,会希望当我点击一个按钮时,出现一个新的窗口。 所以,我们会希望从前端来创建新窗口,这可以通过invoke函数来实现。 具体来说,我们需要先在rust端创建一个新的指令函数:

rust 复制代码
#[tauri::command]
async fn newwindow(app: tauri::AppHandle, page: &str, title: &str) -> Result<(), String> {
    let webview_url = tauri::WebviewUrl::App(page.into());
    match tauri::WebviewWindowBuilder::new(&app, title, webview_url)
        .title(title)
        .build()
    {
        Ok(_) => Ok(()),
        Err(err) => Err(err.to_string()),
    }
}

然后将此函数注册为tauri的前端可以调用:

rust 复制代码
.invoke_handler(tauri::generate_handler![
            newwindow,
            ...此处省略其他代码
        ])

这样,我们就可以从前端来调用此函数:

javascript 复制代码
 //从前端创建新窗口
    newwindowbtn.addEventListener('click', async () => {
        const name = windownameinput.value
        invoke('newwindow',{page:'second.html',title:name})
        .then(res=>{
            
        }).catch(err=>{
            console.log(err)
            alert(`新建窗口错误提示:${err}`)
        })
    });

3、窗口间数据传递

因为tauri本身就是基于前端和后端集成的,tauri提供了前端与后端进行通信的方式,比如事件以及命令。即event和command。 如上文,我们提到的,在rust建立的函数,为其提供了添加了 #[tauri::command]这个宏,将函数变为前端可以调用。从而实现了从前端调用rust函数。 而事件系统是专门设计来用于rust和前端通信的系统,但事件系统的限制是数据传递不能太大,事件可以是全局的,也可以指定特定webview页面。 所以,我们可以利用事件系统,来向特定窗口的页面传递数据。 与新建窗口一样,我们需要先在rust端创建注册函数:

rust 复制代码
#[tauri::command]
fn eventtosomemsg(app:tauri::AppHandle,label:&str,msg:String){
    let newmsg = format!("hello,{}", msg);
    app.emit_to(EventTarget::labeled(label), "eventtosub", newmsg).unwrap();
}

如上,使用emit_to来传递消息,因为我们要向特定页面传递数据,所以可以使用EventTarget::labeled(label)来指定窗口标签。

我们可以在主窗口和子窗口的js代码中来调用此函数。 在主窗口中,我们调用时,指定子窗口标签:

javascript 复制代码
 //事件传递数据,指定窗口接收
    sendmsgbtn.addEventListener('click', async () => {
        let lbl = windowlabelinput.value;
        let msg = sendmsginput.value;
        invoke('eventtosomemsg',{label:lbl,msg:msg})
    })
    const window = getCurrentWebviewWindow();
    window.listen("eventtosub",(event)=>{
        msgfromsubp.innerText = event.payload
    })

这里子窗口的标签是通过input元素输入的。 而在子窗口页面的JavaScript代码中,我们也可以调用事件函数:

javascript 复制代码
const window = getCurrentWebviewWindow();

    sendmsgtomainbtn.addEventListener('click',()=>{
        let msg = sendmsginput.value
        invoke('eventtosomemsg',{ label:'main',msg:msg})
    })
    window.listen('eventtosub',(event)=>{
        mainwindowmsgp.innerHTML = event.payload
    })

在子窗口的函数中,我们可以直接指定目标窗口的标签为main,main是默认的主窗口标签。

这样一来,我们就通过rust端的事件触发函数,实现了向指定窗口发送消息,从而实现窗口间数据传递的功能。

4、动态演示

相关推荐
-代号952712 分钟前
【JavaScript】十二、定时器
开发语言·javascript·ecmascript
追逐时光者28 分钟前
面试官问:你知道 C# 单例模式有哪几种常用的实现方式?
后端·.net
Asthenia04121 小时前
Numpy:数组生成/modf/sum/输出格式规则
后端
Asthenia04121 小时前
NumPy:数组加法/数组比较/数组重塑/数组切片
后端
Asthenia04121 小时前
Numpy:limspace/arange/数组基本属性分析
后端
Asthenia04121 小时前
Java中线程暂停的分析与JVM和Linux的协作流程
后端
Asthenia04121 小时前
Seata TCC 模式:RootContext与TCC专属的BusinessActionContext与TCC注解详解
后端
自珍JAVA1 小时前
【代码】zip压缩文件密码暴力破解
后端
灵感__idea1 小时前
JavaScript高级程序设计(第5版):扎实的基本功是唯一捷径
前端·javascript·程序员
摇滚侠1 小时前
Vue3 其它API toRow和markRow
前端·javascript