WPF和web泛型通信
This commit is contained in:
+35
-67
@@ -1,84 +1,52 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { useAppLogic } from './AppLogic'
|
||||
|
||||
const receivedMsg = ref('等待消息...')
|
||||
const inputMsg = ref('')
|
||||
|
||||
const handleMessage = (event) => {
|
||||
console.log("收到来自 WPF 的消息:", event.data);
|
||||
receivedMsg.value = event.data
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (window.chrome && window.chrome.webview) {
|
||||
window.chrome.webview.addEventListener('message', handleMessage)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (window.chrome && window.chrome.webview) {
|
||||
window.chrome.webview.removeEventListener('message', handleMessage)
|
||||
}
|
||||
})
|
||||
|
||||
const sendMessageToWPF = () => {
|
||||
if (window.chrome && window.chrome.webview) {
|
||||
window.chrome.webview.postMessage(inputMsg.value)
|
||||
} else {
|
||||
alert('未在 WebView2 环境中运行')
|
||||
}
|
||||
}
|
||||
// 所有的业务逻辑都在 AppLogic.js 中实现
|
||||
const {
|
||||
receivedMsg,
|
||||
systemInfo,
|
||||
calcResult,
|
||||
fetchSystemInfo,
|
||||
triggerNativeAlert,
|
||||
runCalculation
|
||||
} = useAppLogic()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<h1>Vue 3 + WebView2 交互演示</h1>
|
||||
<h1>WebView2 标准化交互网关</h1>
|
||||
|
||||
<div class="card">
|
||||
<h3>接收来自 WPF 的消息:</h3>
|
||||
<p class="msg-box">{{ receivedMsg }}</p>
|
||||
<h3>1. 属性同步 (WebMessage)</h3>
|
||||
<p>来自 WPF 的推送: {{ receivedMsg }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>发送消息给 WPF:</h3>
|
||||
<input v-model="inputMsg" placeholder="输入消息" />
|
||||
<button @click="sendMessageToWPF">发送到 WPF</button>
|
||||
<h3>2. 动态 API 调用 (Host Objects + 信封)</h3>
|
||||
<div class="btn-group">
|
||||
<button @click="fetchSystemInfo">获取 C# 系统信息</button>
|
||||
<button @click="triggerNativeAlert" class="btn-warning">触发原生弹窗</button>
|
||||
<button @click="runCalculation" class="btn-info">计算 10 + 20</button>
|
||||
</div>
|
||||
|
||||
<div v-if="systemInfo" class="result-box">
|
||||
<b>系统信息:</b> {{ systemInfo.OS }} ({{ systemInfo.Runtime }})
|
||||
</div>
|
||||
|
||||
<div v-if="calcResult !== null" class="result-box">
|
||||
<b>计算结果:</b> {{ calcResult }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
font-family: Arial, sans-serif;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.card {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
.msg-box {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
input {
|
||||
padding: 8px;
|
||||
width: 200px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
button {
|
||||
padding: 8px 15px;
|
||||
background-color: #42b883;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #3aa876;
|
||||
}
|
||||
.container { padding: 20px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
||||
.card { border: 1px solid #eee; padding: 15px; margin-bottom: 15px; border-radius: 8px; background: #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
|
||||
.btn-group { display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
|
||||
button { padding: 8px 16px; border: none; border-radius: 4px; background: #42b883; color: white; cursor: pointer; }
|
||||
button:hover { background: #3aa876; }
|
||||
.btn-warning { background: #f39c12; }
|
||||
.btn-info { background: #3498db; }
|
||||
.result-box { margin-top: 15px; padding: 10px; background: #f8f9fa; border-left: 4px solid #42b883; font-size: 0.9em; }
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { InteropHelper } from './utils/interop'
|
||||
|
||||
/**
|
||||
* App 页面的业务逻辑 Hook
|
||||
*/
|
||||
export function useAppLogic() {
|
||||
const receivedMsg = ref('等待消息...')
|
||||
const systemInfo = ref(null)
|
||||
const calcResult = ref(null)
|
||||
|
||||
// 1. 获取系统信息 (演示带返回值的标准化调用)
|
||||
const fetchSystemInfo = async () => {
|
||||
try {
|
||||
const data = await InteropHelper.callApi('GetSystemInfo')
|
||||
systemInfo.value = data
|
||||
} catch (err) {
|
||||
alert('获取失败: ' + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 发送弹窗指令 (演示带参数的标准化调用)
|
||||
const triggerNativeAlert = async () => {
|
||||
try {
|
||||
await InteropHelper.callApi('ShowDialog', '这是来自 Vue 的标准化信封消息!')
|
||||
} catch (err) {
|
||||
console.error('弹窗指令发送失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 泛型计算演示 (演示复杂对象参数)
|
||||
const runCalculation = async () => {
|
||||
try {
|
||||
const result = await InteropHelper.callApi('Calculate', { a: 10, b: 20 })
|
||||
calcResult.value = result
|
||||
} catch (err) {
|
||||
console.error('计算失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// 原有的 WebMessage 接收逻辑
|
||||
const handleMessage = (event) => {
|
||||
receivedMsg.value = event.data
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (window.chrome && window.chrome.webview) {
|
||||
window.chrome.webview.addEventListener('message', handleMessage)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
receivedMsg,
|
||||
systemInfo,
|
||||
calcResult,
|
||||
fetchSystemInfo,
|
||||
triggerNativeAlert,
|
||||
runCalculation
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 前后端互操作工具类
|
||||
*/
|
||||
export class InteropHelper {
|
||||
/**
|
||||
* 调用原生 API (通过 StandardApiRequest/Response 协议)
|
||||
* @param {string} action 行为名称
|
||||
* @param {any} data 业务数据
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
static async callApi(action, data = null) {
|
||||
if (!window.chrome?.webview?.hostObjects?.gateway) {
|
||||
const errorMsg = 'WebView2 环境未就绪 (hostObjects.gateway 缺失)';
|
||||
console.error(errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
const gateway = window.chrome.webview.hostObjects.gateway;
|
||||
|
||||
// 1. 封装标准信封
|
||||
const requestEnvelope = {
|
||||
action: action,
|
||||
data: data
|
||||
};
|
||||
|
||||
try {
|
||||
// 2. 调用 C# 网关方法 (使用新的方法名 InvokeAction)
|
||||
const responseJson = await gateway.InvokeAction(JSON.stringify(requestEnvelope));
|
||||
console.log(`API [${action}] 原始响应:`, responseJson);
|
||||
|
||||
// 3. 解析标准回包
|
||||
const response = JSON.parse(responseJson);
|
||||
|
||||
if (response.success) {
|
||||
return response.data;
|
||||
} else {
|
||||
const errorMsg = response.message || '未知错误';
|
||||
console.error(`API [${action}] 返回失败:`, errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`API 调用崩溃 [${action}]:`, err);
|
||||
// 如果是在控制台看到的报错,通常是因为 C# 端发生了未捕获异常
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user