企业网站设计中应注意产品发布功能优化,作品集的个人网站怎么做,网站建设记账,温州专业网站开发网站设计前言 本文是基于rust和tauri#xff0c;由于tauri是前、后端结合的GUI框架#xff0c;既可以直接生成包含前端代码的文件#xff0c;也可以在已有的前端项目上集成tauri框架#xff0c;将前端页面化为桌面GUI。
环境配置 系统#xff1a;windows 10 平台#xff1a;visu…前言 本文是基于rust和tauri由于tauri是前、后端结合的GUI框架既可以直接生成包含前端代码的文件也可以在已有的前端项目上集成tauri框架将前端页面化为桌面GUI。
环境配置 系统windows 10 平台visual studio code 语言rust、javascript 库tauri2.0
概述 本文使用vite构建一个前端页面实现简单的计算器功能然后使用tauri集成前端实现桌面端的计算器窗口并使用rust后端进行计算器的功能计算然后返回前端。
1、创建前端页面
前端框架有很多本文是基于一个常用的vite框架来创建一个前端项目使用原始模板即不使用vue3或者react这样的前端模板而是vite框架下原生的javascript和html。 我们打开visual studio code如果你有现成的根文件夹直接打开或者创建一个新的根文件夹
mkdir tauri
cd tauri然后初始化一个vite项目
npm create vitelatest初始化时将需要填写一个基本信息 如上图项目名称自定义前端框架选原生语言选js。然后会在你的根文件夹下生成一个项目 我们可以先看一下这个前端页面运行起来的效果但这之前还需要安装以下npm包
cd vitepro
npm install
npm run dev这里是vite提供的模板示例是一个计数器点击网页下端的按钮计数值会改变。 但我们需要的是一个计算器界面所以需要对代码进行修改。先看一下vite提供的示例代码的结构 如上图所示main.js是主函数入口counter.js才是计数功能模块。
main.js源码
import ./style.css
import javascriptLogo from ./javascript.svg
import viteLogo from /vite.svg
import { setupCounter } from ./counter.jsdocument.querySelector(#app).innerHTML diva hrefhttps://vite.dev target_blankimg src${viteLogo} classlogo altVite logo //aa hrefhttps://developer.mozilla.org/en-US/docs/Web/JavaScript target_blankimg src${javascriptLogo} classlogo vanilla altJavaScript logo //ah1Hello Vite!/h1div classcardbutton idcounter typebutton/button/divp classread-the-docsClick on the Vite logo to learn more/p/div
setupCounter(document.querySelector(#counter))
其中setupCounter是由counter.js中导出的模块。官方提供的这个示例比较简单我们希望稍作修改首先是将app这个div的内容提取出来写在单独的html文件中可以将其命名为template.html
diva hrefhttps://vite.dev target_blankimg src${viteLogo} classlogo altVite logo //aa hrefhttps://developer.mozilla.org/en-US/docs/Web/JavaScript target_blankimg src${javascriptLogo} classlogo vanilla altJavaScript logo //ah1Hello Vite!/h1div classcardbutton idcounter2 typebutton/button/divp classread-the-docsClick on the Vite logo to learn more/p/div然后将template.html放在public文件夹中方便调用。 接着修改main.js以便于获取template.html中的内容
import ./style.css
import javascriptLogo from ./javascript.svg
import viteLogo from /vite.svg
import { setupCounter } from ./counter.jsasync function loadTemplate(path,divid) {const response await fetch(path);const template await response.text();document.querySelector(divid).innerHTML template.replace(${viteLogo}, viteLogo).replace(${javascriptLogo}, javascriptLogo);setupCounter(document.querySelector(#counter))
}loadTemplate(./template.html,#app)此处使用fetch来获取本地html文件的内容效果是一致的。接着我们修改template.html的页面设计一个简单的计算器布局此处是前端程序比较简单代码如下可以参考也可以直接去使用人工智能生成。 template.html
label forhistory历史:/labelinput typetext classhistory idhistory disabledlabel fordisplay实时:/labelinput typetext classdisplay iddisplay disableddiv classbuttonsbutton classbutton idclearbtn C/buttonbutton classbutton idsquarebtnX²/buttonbutton classbutton idbackbtn←/buttonbutton classbutton operator idmulbtn */buttonbutton classbutton idsevenbtn 7/buttonbutton classbutton ideightbtn 8/buttonbutton classbutton idninebtn 9/buttonbutton classbutton operator iddivbtn //buttonbutton classbutton idfourbtn 4/buttonbutton classbutton idfivebtn 5/buttonbutton classbutton idsixbtn 6/buttonbutton classbutton operator idaddbtn /buttonbutton classbutton idonebtn 1/buttonbutton classbutton idtwobtn 2/buttonbutton classbutton idthreebtn 3/buttonbutton classbutton operator idsubbtn -/buttonbutton classbutton idzerobtn 0/buttonbutton classbutton iddotbtn ./buttonbutton classbutton equal idequalbtn /button/div上面的代码在网页上看起来如下 注意页面布局还需要配合css样式 global.css
body {font-family: Arial, sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #ffffff;
}
.app {background-color: #73b4f1;padding: 20px;border-radius: 10px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);display: flex;flex-direction: column;
}
.display {height: 30px;text-align: right;margin-bottom: 10px;padding: 10px;font-size: 18px;border: 1px solid #e7adad;border-radius: 5px;
}
.history{height: 30px;text-align: right;margin-bottom: 10px;padding: 10px;font-size: 18px;border: 1px solid #e7adad;border-radius: 5px;
}
.buttons {display: grid;grid-template-columns: repeat(4, 1fr);gap: 10px;
}
.button {padding: 20px;font-size: 18px;border: none;border-radius: 5px;background-color: #f0f0f0;cursor: pointer;
}
.button:hover {background-color: #ddd;
}
.button.operator {background-color: #ff9500;color: white;
}
.button.operator:hover {background-color: #e08900;
}
.button.equal {background-color: #34c759;color: white;grid-column: span 2;
}
.button.equal:hover {background-color: #2da94f;
}页面布局写好了就需要为按钮实现功能了这部分需要写在js中我们将修改counter.js的代码为其中添加以下函数 1、清除函数 2、数字输入函数 3、计算函数加减乘除以及平方 4、退格函数 以上是本文将要实现的计算器功能当然只是简单的实现并非是一个完整的计算器功能本文的目的是通过这个小的计算器程序来说明tauri集成前端的示例。 counter.js
let currentInput;
let previousInput;
let operatornull;
let predisplay
let calflagfalse;// 导出一个函数用于在输入框中添加数字
export function appendnumber(element,number,display,history) {// 给元素添加点击事件element.addEventListener(click,() {///如果连续输入则直接拼接currentInput number;///输入值将实时显示在输入框内display.value currentInput;///判断是否进行了计算如果进行了计算则历史值清空显示新的实时输入if (calflag){history.value currentInput;calflagfalse;} else {history.value history.value number;}})}
// 导出一个函数用于在元素上添加功能符号的点击事件
export function appendOperator(element,op,display,history) {// 为元素添加点击事件element.addEventListener(click,() {///如果点击了功能符号但计算完成标记存在则不进行任何回应if (calflag){return;}///如果多次点击功能符号而不是输入下一个数值则切换功能符号if (currentInput ) {operator op;history.value previousInput operator;return;};///如果前次输入值不为空则直接计算结果if (previousInput ! ) {//calculate();insidecalculate();}operator op;previousInput currentInput;display.value previousInput;history.value currentInput operator;predisplaydisplay.value;currentInput ;})}function insidecalculate(){if (currentInput || previousInput ) return;let result;const prev parseFloat(previousInput);const current parseFloat(currentInput);switch (operator) {case :result prev current;break;case -:result prev - current;break;case *:result prev * current;break;case /:result prev / current;break;default:return;}currentInput result.toString();
}// 导出一个函数用于计算
export function calculate(element,display,history) {// 给element添加点击事件监听element.addEventListener(click,(){// 如果currentInput或previousInput为空则返回if (currentInput || previousInput ) return;let result;// 将previousInput和currentInput转换为浮点数const prev parseFloat(previousInput);const current parseFloat(currentInput);// 根据operator的值进行计算switch (operator) {case :result prev current;break;case -:result prev - current;break;case *:result prev * current;break;case /:result prev / current;break;default:return;}// 将计算结果转换为字符串赋值给currentInputcurrentInput result.toString();// 将计算结果添加到history中history.value history.value currentInput \n;// 将计算结果显示在display中display.value currentInput;// 将display的值赋值给predisplaypredisplaydisplay.value;// 将operator置为nulloperator null;// 将previousInput置为空previousInput ;// 将currentInput置为空currentInput;// 将calflag置为truecalflagtrue;})}// 导出一个函数用于清除显示
export function clearDisplay(element,operator,display,history) {// 为element添加点击事件监听器element.addEventListener(click,(){// 将currentInput设置为空字符串currentInput ;// 将operator设置为nulloperator null;// 将previousInput设置为空字符串previousInput ;// 将display的值设置为空字符串display.value ;// 将predisplay设置为空字符串predisplay;// 将history的值设置为空字符串history.value;})
}// 导出一个函数用于返回上一个输入的字符
export function backLast(element,display,history) {// 给element添加点击事件element.addEventListener(click,(){// 如果calflag为falseif (!calflag) {// 将currentInput的最后一个字符删除currentInput currentInput.slice(0, -1);// 将删除后的currentInput赋值给display的valuedisplay.value currentInput;// 将history的最后一个字符删除history.value history.value.slice(0, -1);} else {// 将currentInput的最后一个字符删除currentInput currentInput.slice(0, -1);// 将删除后的currentInput赋值给display的valuedisplay.value currentInput;}})
}// 导出一个函数用于计算平方
export function squarenumber(element,display,history) {// 给element元素添加点击事件element.addEventListener(click,(){// 将currentInput的值平方currentInput Math.pow(currentInput,2);// 将平方后的值显示在display元素中display.value currentInput;// 将计算过程添加到history元素中history.value history.value ^2 currentInput \n;// 将previousInput和currentInput的值重置为空previousInput ;currentInput;// 将calflag的值设置为truecalflagtrue;})
}然后在main.js中导入上述函数
import { appendnumber,appendOperator,calculate,clearDisplay,backLast,squarenumber } from ./counter.js2、tauri集成
完成了前端页面后我们现在来手动集成tauri。tauri的官网提供了详细的步骤在我们上面创建的项目文件夹vitepro下安装Tauri 的 CLI 工具
npm install -D tauri-apps/clilatest安装完成后node包文件夹下显示tauri库 还是在当前项目文件夹的根目录下我们使用tauri的cli工具初始化一个tauri使其包含在我们已经创建好的前端项目中
npx tauri init运行后会让你填写几个问题
✔ What is your app name? · vitepro
✔ What should the window title be? · vitepro
? Where are your web assets (HTML/CSS/JS) located, relative to the current dir/src-tauri/tauri.conf.json file that will be created? ›
✔ Where are your web assets (HTML/CSS/JS) located, relative to the current dir/src-tauri/tauri.conf.json file that will be created? · ..
✔ What is the url of your dev server? · http://localhost:5173
✔ What is your frontend dev command? · npm run dev
✔ What is your frontend build command? · npm run build由于我们是集成在vite构建的前端项目中所以url可以使用默认的 http://localhost:5173 初始化完成后可以看到项目文件夹下会多出一个src-tauri文件夹 此时我们可以使用
npx tauri dev来运行一下看看 看起来还可以不过默认的窗口尺寸并不匹配我们可以修改一下窗口参数。 在src-tauri文件夹下有一个配置文件tauri.conf.json其中有个app参数修改其中的windows项将窗口宽度设置为400。 app: {windows: [{title: vitepro,width: 400,height: 600,resizable: true,fullscreen: false}],security: {csp: null}},修改后如下 看起来要好多了事实上窗口还可以美化但是本文暂不再赘述。
3、后端函数替代
现在我们想把之前在javascript中的函数功能放到rust中实现再通过接口在前端调用实现前后端的数据通讯。此处tauri提供了两种方法一种是使用javascript API库另一个是使用withGlobalTauri这个配置实现预构建API。 1、如果使用javascript API那么需要先安装tauri-apps/api 使用
npm install tauri-apps/api指令安装api库安装完成后调用invoke函数
import { invoke } from tauri-apps/api/core2、如果使用withGlobalTauri配置那么需要修改tauri.conf.json文件中的build项
{build: {...withGlobalTauri: true},添加withGlobalTauri并设置为true。这里省略了其他参数的设置。 然后在js中调用
const invoke window.__TAURI__.invoke其中invoke函数的参数有三个第一个是要调用的函数名第二个是函数的参数如果有的话第三个是一个可选项一个headers参数用于操作http请求和响应的接口 如果要在前端调用rust首先你需要在rust中编写好函数然后才能在前端使用在tauri初始化的src-tauri文件夹中我们打开lib.rs文件添加一个函数
#[tauri::command]
fn greet(name:str) - String {format!(hello,this is from rust msg,your name is {}!,name)
}注意到这里函数被标记了使用#[tauri::command]来表明这是一个可以被前端使用的rust函数但是这还不够还需要将这个函数传递给构建列表
pub fn run() {tauri::Builder::default().invoke_handler(tauri::generate_handler![greet]).setup(|app| {if cfg!(debug_assertions) {app.handle().plugin(tauri_plugin_log::Builder::default().level(log::LevelFilter::Info).build(),)?;}Ok(())}).run(tauri::generate_context!()).expect(error while running tauri application);
}注意上面代码中的invoke_handler标记的函数通过它来传递。我们来测试一下为前端添加一个文本标签然后程序运行后显示一个从rust函数传递过来的字符串。 我们先修改template.html添加一个新标签 div idtitlediv classtitledivp idtitlep等待rust传递的字符/p/div设置一下背景色以做区分。先看下效果 现在我们还没有调用rust的函数所以只显示设定的内容。
然后在main.js中我们来修改这个标签将其内容替换为从rust函数获取的字符串
const titlepdocument.getElementById(titlep);const greetingawait invoke(greet);titlep.innerHTML greeting;console.log(greeting);同时修改一下rust端的函数
#[tauri::command]
fn greet() - String {format!(hello,这里是rust数据!)
}再次运行 说明是正确的从前端调用了rust的函数并获取了返回的内容。 现在我们尝试将之前的计算函数写到rust中然后前端这边点击相应按钮时调用rust函数并返回结果。 以等号的功能为例原先的等号功能的核心逻辑是 // 根据operator的值进行计算switch (operator) {case :result prev current;break;case -:result prev - current;break;case *:result prev * current;break;case /:result prev / current;break;default:return;}我们就将这段替换掉先在rust中新建一个calculate_rs函数
#[tauri::command]
fn calculate_rs(current_input:f32,previous_input:f32,operator:str
) - f32 {match operator { current_input previous_input,- current_input - previous_input,* current_input * previous_input,/ current_input / previous_input,_ 0.0,}
}这个函数就是根据输入数字和计算符返回相应结果当然这里比较简单没有进行错误处理。 在js中调用此函数来计算 const calawait invoke(calculate_rs,{currentInput:current,previousInput:prev,operator:operator})4、实例演示
上面介绍了代码下面来看一下动态演示 tauri简单计算器程序演示 5、源代码
https://download.csdn.net/download/normer123456/90354147