tauri2+typescript+vue+vite+leaflet等的简单联合使用(一)
项目目标
主要的目的是学习tauri。
流程
1、搭建项目
2、简单的在项目使用leaflet
3、打包
准备项目
环境准备
废话不多说,直接开始
需要有准备能运行Rust的环境和Node,对于Rust可以参考下面这位大佬的文章,Node不必细说。
Rust 和 Cargo 安装指南-CSDN博客
https://blog.csdn.net/qq_44154915/article/details/139365116
建立项目
进入tauri2
官网
https://tauri.app/start/

笔者将使用pnpm建立项目,项目名称为ttvvl
如下

使用VSCode或者WebStorm打开项目
安装依赖
pnpm install

运行
pnpm tauri dev
然后就在compiling

这笔者感到疑惑,可能是第一次运行,搞了许久

运行结果

没有问题。
看一下文件夹的属性

6个G,有点大。
如果以
pnpm run dev
点击按钮,会出现错误


观察上面的代码,我们可以发现,这个是invoke好像是个方法。第一个参数是个字符串greet
第二个参数是个对象,属性是name。
同时找到src-tauri/src/lib.rs中的代码,如下

fn 是Rust的关键字,相当与定义了一个函数,函数名叫greet,参数name
format!是个格式化字符串的函数
其他不是很懂,但我们可以把这段代码给deepseek,问一问
解答如下

从这里我们可以得到关键信息——被这个宏标记的函数能被前端调用。
因为Rust函数的函数名叫greet,而invoke的第一个参数是字符串greet,我们可以很容易猜测
二者必然有关系,我们可以检验一下
修改函数名为greets,运行
发现报错了

我们可以看到下面还有一个函数
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {tauri::Builder::default().plugin(tauri_plugin_opener::init()).invoke_handler(tauri::generate_handler![greet]).run(tauri::generate_context!()).expect("error while running tauri application");
}
可以问一问deepseek

原来下面那个函数是入口函数,invoke_handler是注册器,因此,把中括号里面的greet改成greets
应该可以运行了,(每次都要编译,有点慢)。
如果点击按钮,下面应该不会出现字

事实确实如此。
那么推断很有可能是正确的,那么我们把字符串greet改成greets,就可以出现字了

事实确实如此,笔者明白了。
再次观察,Rust函数greets返回值是String,

而返回格式化后的字符串,对于App.vue中的TypeScript代码,打印出greetMsg.value的值

在运行后的的tauri中,可以打开开发者工具,打印结果如下。

既然如此,感觉明白了,invoke作为Rust与TypeScript交互的关键函数。
安装leaflet有关依赖
pnpm install leaflet leaflet-geoman-free
因为使用typescipt,还需要安装类型定义包
pnpm install --save @types/leaflet.pm @types/leaflet
显示地图
这也是很麻烦的事情。
安装vue-router
pnpm install vue-router
新建一些目录和文件,如下

在router目录的index.ts中
import {createRouter, createWebHashHistory, Router, RouteRecordRaw, RouterOptions} from "vue-router";
const routes:RouteRecordRaw[]=[{path:"/",redirect:"/map",children:[{path:"map",component:()=>import("../views/Map.vue")}]}
]
const options:RouterOptions={history:createWebHashHistory(),routes
}
const router:Router=createRouter(options)
export default router
暂时先这么写
main.ts的内容
import { createApp } from "vue";
import App from "@/App.vue";
import router from "@/router";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
const app=createApp(App);
app.use(router);
app.config.globalProperties.$L = L;app.mount("#app");
将L作为Vue的全局属性,并且引入插件leaflet-geoman-free及相关样式
关于@符号,不多解释。
在constant/data.ts中
export const MAP_URL= "https://tile-a.openstreetmap.fr/hot/{z}/{x}/{y}.png";
这个是地图瓦片的URL。通过它就能访问地图。
在utils/Map.ts中
import {MAP_URL} from "@/constant/data.ts";
import L from 'leaflet';
const GetMap = (control: any=null, //控件language:any = 'zh' //语言
): L.Map => {const options: L.MapOptions = {center: [30.6667, 104.0667], //中心点minZoom: 0,maxZoom: 30,zoom: 10,zoomControl: true,doubleClickZoom: true,attributionControl: true,dragging: true,boxZoom: true,scrollWheelZoom: true,zoomSnap: 0.5,};const map = L.map('map', options);L.tileLayer(MAP_URL, {attribution: '',}).addTo(map);map.pm.addControls(control); map.pm.setLang(language);return map;
};
export default GetMap;
如果不写
import L from 'leaflet'
Vue: 'L' refers to a UMD global, but the current file is a module. Consider adding an import instead.
在views/Map.vue中
<script setup lang="ts">
import GetMap from "@/utils/Map.ts";
import { onMounted } from 'vue';
let map: any = null
onMounted(() => {map = GetMap();map.on('click', (e: any) => {console.log(e);});
})
</script><template>
<div id="map"></div>
</template><style scoped>
#map {height: 100vh;width: 200vh;
}
</style>
运行,结果如下

地图定位到成都市。
显示控件
可以查看leaflet-geoman-free文档
Introduction | Documentation for Leaflet-Geoman
https://geoman.io/docs/leaflet在constant/data.ts中
export const MAP_CONTROL={
}
可以写一些设置,但有默认选项,就不改了。
在views/Map.vue中导入MAP_CONTROL,作为GetMap的参数
map = GetMap(MAP_CONTROL);
,使用控件,运行结果如下

搞点小操作1——计算两点之间的距离
操作过程
点两个点,通过invoke函数发送经纬度到rust函数,返回结果
计算距离函数
使用Haversine 公式
haversine公式计算两经纬度点距离-CSDN博客
https://blog.csdn.net/spatial_coder/article/details/116605509使用Rust实现,src-tauri/src/lib.rs的代码如下
const EARTH_RADIUS_KM: f64 = 6371.0; // 地球半径,单位:公里
#[tauri::command]
// 计算两个经纬度点之间的距离(单位:公里)
fn haversine_distance(start:[f64;2],end:[f64;2]) -> f64 {// 将经纬度从度数转换为弧度let lat1_rad = start[0].to_radians();let lon1_rad = start[1].to_radians();let lat2_rad = end[0].to_radians();let lon2_rad = end[1].to_radians();// 经纬度差值let dlat = lat2_rad - lat1_rad;let dlon = lon2_rad - lon1_rad;// Haversine 公式let a = (dlat / 2.0).sin().powi(2) + lat1_rad.cos() * lat2_rad.cos() * (dlon / 2.0).sin().powi(2);let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());// 计算距离EARTH_RADIUS_KM * c
}#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {tauri::Builder::default().plugin(tauri_plugin_opener::init()).invoke_handler(tauri::generate_handler![haversine_distance]).run(tauri::generate_context!()).expect("error while running tauri application");
}
以公里作为单位
对两个点marker的思考
点了两个点marker,我们通过leaflet和有关插件的某些事件可以获得这两个点的属性,
我们可以修改这些属性。
那应该然后修改?
可以尝试使用tauri的多窗口。
marker位于父窗口,发送信号到子窗口,在子窗口进行修改,返回父窗口。
父子窗口以及发送信号

关于窗口的配置
src-tauri/capabilities/default.json
{"$schema": "../gen/schemas/desktop-schema.json","identifier": "default","description": "Capability for the main window","windows": ["main","marker-name"],"permissions": ["core:default","opener:default","core:window:allow-hide","core:window:allow-show"]
}
在子窗口添加一个路由
src/router/index.ts
{path:"/name",component:()=>import("../views/name.vue")}
src-tauri/tauri.conf.json
"windows": [{"title": "ttvvl","label": "main","width": 800,"height": 600},{"title": "点位窗口","width": 400,"height": 300,"label": "marker-name","resizable": true,"parent": "main","visible": false,"url":"#/name","decorations": false,"center": true}],
参数的具体含义,可以参考官网或者deekssek
{"windows": [{"label": "main", // 窗口的唯一标识符"title": "My Tauri App", // 窗口标题"width": 800, // 窗口宽度"height": 600, // 窗口高度"x": null, // 窗口初始水平位置(null 表示由系统决定)"y": null, // 窗口初始垂直位置(null 表示由系统决定)"minWidth": null, // 窗口最小宽度"minHeight": null, // 窗口最小高度"maxWidth": null, // 窗口最大宽度"maxHeight": null, // 窗口最大高度"resizable": true, // 是否允许调整窗口大小"fullscreen": false, // 是否全屏"focus": true, // 窗口是否在创建时获得焦点"visible": true, // 窗口是否可见"decorations": true, // 是否显示窗口装饰(标题栏、边框等)"alwaysOnTop": false, // 窗口是否始终置顶"maximized": false, // 窗口是否最大化"transparent": false, // 窗口背景是否透明"center": true, // 窗口是否居中"theme": "system", // 窗口主题("system"、"light"、"dark")"url": "index.html", // 窗口加载的页面路径"fileDropEnabled": true, // 是否启用文件拖放功能"skipTaskbar": false, // 是否在任务栏中显示窗口"shadow": true, // 是否显示窗口阴影"acceptFirstMouse": false, // 是否接受首次鼠标点击事件"tabbingIdentifier": null, // macOS 标签页标识符"titleBarStyle": "visible", // macOS 标题栏样式("visible"、"transparent"、"overlay")"hiddenTitle": false // 是否隐藏标题栏标题}]
}
父窗口
src/views/Map.vue
<script setup lang="ts">
//@ts-nocheck
import GetMap from "@/utils/Map.ts";
import {MAP_CONTROL} from "@/constant/data.ts";
import {invoke} from "@tauri-apps/api/core";
import {emit,listen} from "@tauri-apps/api/event";
import {onMounted, ref} from 'vue';
import WindowManager from '@/utils/window';const windowManager = new WindowManager();
let startName=ref<String>('起点');
let endName=ref<String>('终点');
let markerWindow,mainWindow,markerIndex=null;
let map: any = null
let markerList: L.Marker[] = [];
let distance=ref<number>(0);listen('message-to-main-window', (event)=>{ //监听消息let payload:any=event.payloadif(payload.close){windowManager.closeWindow('marker-name')mainWindow.show()}if(markerIndex===null){return}if(markerIndex===0){startName.value='起点'+payload.tooltipContent}else{endName.value='终点'+payload.tooltipContent}markerList[markerIndex].bindTooltip(payload.tooltipContent)
});
async function sendMsg(tooltipContent:String,nowClickMarkerId:Number) { //发送消息markerWindow=await windowManager.getWindowByLabel('marker-name') //子窗口mainWindow=await windowManager.getWindowByLabel('main') //父窗口if(markerWindow) {mainWindow.hide()markerWindow.show();markerIndex=markerList.findIndex((marker:L.Marker)=>marker._leaflet_id===nowClickMarkerId)emit('message-to-second-window', { //发送消息 参数lat: markerList[0].getLatLng().lat,lng: markerList[0].getLatLng().lng,markerIndex:markerIndex,tooltipContent:tooltipContent})}
}async function get_distance(){let start=markerList[0].getLatLng(); //开始点let end=markerList[1].getLatLng(); //终点let startArray=[start.lat,start.lng];let endArray=[end.lat,end.lng];distance.value = await invoke('haversine_distance', { //发送给rust tauristart: startArray,end: endArray});
}
onMounted(() => {// openWindow()map = GetMap(MAP_CONTROL);map.on('pm:create', (e: any) => { // map create事件let marker:L.Marker = e.marker;marker.on('click',(e)=>{ // marker的点击事件let nowClickMarkerId=e.target._leaflet_id // 获取marker的idsendMsg(e.target.getTooltip(),nowClickMarkerId) // 发送消息})markerList.push(marker);let length = markerList.length;if(length==2){ // 起始点 和终点get_distance() //获取距离}else if(length>2){markerList[0].remove(); //移除第一个点markerList.shift();get_distance() // 获取距离}})})
</script><template>
<div id="map"><div id="distance-text" v-if="markerList.length>=2">从{{startName}}到{{endName}}的距离为</div><div><button type="button" id="show" >{{distance}}</button></div><div id="unit">公里</div></div>
</template><style scoped>
#map {margin: 0 auto;width: 100%;height: 900px;
}
#show {max-width: 200px;max-height: 50px;padding: 10px;background-color: blue;color: white;text-align: center;position: absolute;top: 100px;right: 10px;z-index: 999;border-radius: 20px;
}
#distance-text {max-width: 200px;max-height: 50px;padding: 10px;background-color: #af8433;color: white;text-align: center;position: absolute;top: 10px;right: 10px;z-index: 999;border-radius: 20px;
}
#unit {max-width: 200px;max-height: 50px;padding: 10px;background-color: #af8433;color: white;text-align: center;position: absolute;top: 150px;right: 10px;z-index: 999;border-radius: 20px;
}</style>
子窗口
src/views/Name.vue
<script setup>
import {listen,emit} from "@tauri-apps/api/event";
import {onMounted, ref} from "vue";
let lat = ref(0);
let lng = ref(0);
let markerIndex = ref(0); // 0 替换成起点 1 替换成终点
let inputValue = ref('');
let oldTooltip=nullconst handleClicked = () => {emit('message-to-main-window', {tooltipContent:inputValue.value,close: true,});
}
const handleCancel = () => {emit('message-to-main-window', {tooltipContent:oldTooltip,close: true,});
}
onMounted(() => {listen('message-to-second-window', (event) => {let payload = event.payload;lat.value = payload.lat;lng.value = payload.lng;markerIndex.value = payload.markerIndex;inputValue.value=payload.tooltipContent;oldTooltip=payload.tooltipContent});}
)</script>
<template><div data-tauri-drag-region class="titlebar" ><h1>{{markerIndex===0?'起点':'终点'}}</h1><div v-if="lat>0">纬度:{{lat }}</div><div v-if="lng>0">经度:{{lng }}</div><div>名称<br/><input v-model="inputValue"></input></div><br/><button type="button" @click="handleClicked" class="sure">确定</button><button type="button" @click="handleCancel" class="cancel">取消</button></div>
</template>
<style >
.sure{padding: 10px ;margin-right: 10vw;background-color: #5174ff;
}
.cancel{padding: 10px ;margin-right: 10vw;background-color: #ffb43e;}</style>
窗口管理
src/utils/window.ts
import { getAllWebviewWindows } from '@tauri-apps/api/webviewWindow';export class WindowManager {async getWindowByLabel(label: string) {const windows = await getAllWebviewWindows();return windows.find((win) => win.label === label);}async closeWindow(label: string) {const window = await this.getWindowByLabel(label);if (window) {window.hide();}}
}export default WindowManager;
运行结果



运行结果倒是没问题,代码写得不行,算了。不管那些。
打包
本地打包
打包成exe命令
pnpm tauri build
因为笔者不是第一次打包,如果是第一次打包,需要下载一些东西,笔者就不展示了,可参考下面这位大佬的过程。
从零开始的 Tauri 开发 & 打包成 exe 【Windows 平台】_tauri 打包-CSDN博客
https://blog.csdn.net/u010263423/article/details/136006546对于leaflet打包,会出现一个bug,解决过程可看这篇文章
解决Vue+Vite打包后Leaflet的marker图标不显示的问题_leaflet l.marker 没有-CSDN博客
https://blog.csdn.net/qq_63401240/article/details/139972362?spm=1001.2014.3001.5502总之。打包结果

打包运行结果
可以。

上传到github并打包
在github上通过工作流打包
工作流代码参考下面这位大佬
tauri使用github的action自动发布release,让别人也可以看到下载链接_tauri github action-CSDN博客
https://blog.csdn.net/weixin_44786530/article/details/140904091在大佬的基础上做出小的修改

修改了工件的版本,其他改动不大
运行结果如下

发现ubuntu出错了。笔者没有深究。
笔者再次打包,只选择了window系统,结果如下

项目地址
qe-present/ttvvl
https://github.com/qe-present/ttvvl
总结
简单地使用了tauri,使用了信号通信,多窗口,打包。
相关文章:
tauri2+typescript+vue+vite+leaflet等的简单联合使用(一)
项目目标 主要的目的是学习tauri。 流程 1、搭建项目 2、简单的在项目使用leaflet 3、打包 准备项目 环境准备 废话不多说,直接开始 需要有准备能运行Rust的环境和Node,对于Rust可以参考下面这位大佬的文章,Node不必细说。 Rust 和…...
【流程图】在 .NET (WPF 或 WinForms) 中实现流程图中的连线算法
在 .NET (WPF 或 WinForms) 中实现流程图中的连线算法,通常涉及 图形绘制 和 路径计算。常见的连线方式包括 直线、折线 和 贝塞尔曲线。以下是几种方法的介绍和示例代码。 1. 直线连接(最简单) 适用场景: 两个节点之间没有障碍…...
IDEA集成DeepSeek,通过离线安装解决无法安装Proxy AI插件问题
文章目录 引言一、安装Proxy AI1.1 在线安装Proxy AI1.2 离线安装Proxy AI 二、Proxy AI中配置DeepSeek2.1 配置本地部署的DeepSeek(Ollama方式)2.2 通过第三方服务商提供的API进行配置 三、效果测试 引言 许多开发者尝试通过安装Proxy AI等插件将AI能力…...
【流行病学】Melodi-Presto因果关联工具
title: “[流行病学] Melodi Presto因果关联工具” date: 2022-12-08 lastmod: 2022-12-08 draft: false tags: [“流行病学”,“因果关联工具”] toc: true autoCollapseToc: true 阅读介绍 Melodi-Presto: A fast and agile tool to explore semantic triples derived from …...
详细分析KeepAlive的基本知识 并缓存路由(附Demo)
目录 前言1. 基本知识2. Demo2.1 基本2.2 拓展2.3 终极 3. 实战 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 基本知识推荐阅读:KeepAlive知识点 从实战中学习,源自实战中vue路由的…...
【Go】Go viper 配置模块
1. 配置相关概念 在项目开发过程中,一旦涉及到与第三方中间件打交道就不可避免的需要填写一些配置信息,例如 MySQL 的连接信息、Redis 的连接信息。如果这些配置都采用硬编码的方式无疑是一种不优雅的做法,有以下缺陷: 不同环境…...
zabbix“专家坐诊”第277期问答
在线答疑:乐维社区 问题一 Q:这个怎么解决呢? A:缺少这个依赖。 Q:就一直装不上。 A:装 zabbix-agent2-7.0.0-releasel.el7.x86 64 需要前面提示的那个依赖才可以装。 问题二 Q:大佬,如果agen…...
大模型工程师学习日记(十一):FAISS 高效相似度搜索和密集向量聚类的库
Facebook AI Similarity Search (Faiss /Fez/) 是一个用于高效相似度搜索和密集向量聚类的库。它包含了在任意大小的向量集合中进行搜索的算法,甚至可以处理可能无法完全放入内存的向量集合。它还包含用于评估和参数调整的支持代码。 Faiss 官方文档:We…...
python学习第三天
条件判断 条件判断使用if、elif和else关键字。它们用于根据条件执行不同的代码块。 # 条件判断 age 18 if age < 18:print("你还是个孩子!") elif age 18:print("永远十八岁!") else:print("你还年轻!")…...
深入解析 Svelte:下一代前端框架的革命
深入解析 Svelte:下一代前端框架的革命 1. Svelte 简介 Svelte 是一款前端框架,与 React、Vue 等传统框架不同,它采用 编译时(Compile-time) 方式来优化前端应用。它不像 React 或 Vue 依赖虚拟 DOM,而是…...
C++20 中位移位运算符的统一行为:深入解析与实践指南
文章目录 1. 位移位运算符的基础1.1 左移运算符(<<)1.2 右移运算符(>>) 2. C20 对位移位运算符的统一2.1 移位数量超出操作数位宽2.2 负数移位 3. 实践中的注意事项4. 示例代码5. 总结 在 C 的发展历程中,…...
Linux——基本指令
我们今天学习Linux最基础的指令 ls 指令 语法: ls [选项] [⽬录或⽂件] 功能:对于⽬录,该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件,将列出⽂件名以及其他信 息。 命令中的选项,一次可以传递多个 ,…...
MySql面试总结(二)
WHERE 子句优化 截至2024年7月,MySQL最新稳定版本是8.2,并不存在MySQL 8.4 。下面从常见的几个方面为你介绍 MySQL 8.x 中 WHERE 子句的优化方法: 1. 确保使用索引 原理:索引可以加快数据的查找速度,当 WHERE 子句中的条件列有索引时,MySQL 可以直接定位到符合条件的数…...
Pytorch中的主要函数
目录 一、torch.manual_seed(seed)二、torch.cuda.manual_seed(seed)三、torch.rand(*size, outNone, dtypeNone, layouttorch.strided, deviceNone, requires_gradFalse)四、给大家写一个常用的自动选择电脑cuda 或者cpu 的小技巧五、torch.version.cuda;torch.bac…...
Java实现大数据量导出报表
一、实现方式 在Java中,导出数据到Excel有多种方式,每种方式都有其优缺点,适用于不同的场景。以下是常见的几种方式及其特点: 1.1 Apache POI Apache POI 是 Java 中最流行的库,支持读写 Excel 文件(包括…...
大语言模型 智能助手——既能生成自然语言回复,又能在必要时调用外部工具获取实时数据
示例代码: import json from langgraph.graph import Graph, END,StateGraph from langchain_core.utils.function_calling import convert_to_openai_function from langchain_community.tools.openweathermap import OpenWeatherMapQueryRun from langchain_core…...
PyTorch 系统教程:理解机器学习数据分割
数据分割是机器学习中的一个基本概念,它直接影响模型的性能和泛化。在本文中,我们将深入研究为什么数据分割在机器学习中很重要,并演示如何使用PyTorch有效地实现它。 理解数据分割 数据分割是将数据集划分为单独的组以进行训练、验证和测试…...
分水岭算法(Watershed Algorithm)教程:硬币分割实例
import cv2 import numpy as np# 1. 图像预处理 img cv2.imread("./water/water_coins.jpeg") gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU) kernel np.ones((3, 3), np.int8)…...
【STM32项目实战系列】基于STM32G474的FDCAN驱动配置
前言:本周工作中用到了CANFD的驱动,由于以前都是用到的CAN2.0,所以过程并不是特别的顺利,所以中间遇到几个比较小的问题导致自己卡住了一段时间,特此记录一下并完全奉上自己的配置的源码。 1,CANFD配置与简…...
shell文本处理
shell文本处理 一、grep 过滤来自一个文件或标准输入匹配模式内容。除了 grep 外,还有 egrep、fgrep。egrep 是 grep 的扩展,相当于 grep -E。fgrep 相当于 grep -f,用的比较少。 用法 grep [OPTION]... PATTERN [FILE]...支持的正则描述…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
