基于vue3+ts的前端网页,实现网页点击按钮打开本地exe运行文件的完整实例

核心原理

使用 URL Protocol 协议注册 + 前端跳转协议 的方式实现,兼容主流浏览器(需用户提前注册协议)。

完整实现步骤

1. 注册自定义 URL 协议(Windows 系统)

创建 open-app.reg 文件,内容如下:

复制代码
Windows Registry Editor Version 5.00

; 删除旧的(如果存在)
[-HKEY_CLASSES_ROOT\myapp]

[HKEY_CLASSES_ROOT\myapp]
@="URL:MyApp Protocol v2"
"URL Protocol"=""
"EditFlags"=dword:00000002  ; 强制重新关联

[HKEY_CLASSES_ROOT\myapp\DefaultIcon]
@="C:\\Path\\To\\YourApp.exe,0"

[HKEY_CLASSES_ROOT\myapp\shell]
[HKEY_CLASSES_ROOT\myapp\shell\open]
[HKEY_CLASSES_ROOT\myapp\shell\open\command]
@="\"C:\\Path\\To\\YourApp.exe\" \"%1\""

说明:

  • 替换 C:\Path\To\YourApp.exe 为实际 exe 路径(如 C:\ProgramFiles\MyApp\app.exe)
  • 双击运行该文件完成注册

2.Vue3 + TypeScript 前端实现

复制代码
<template>
  <button @click="openLocalApp" :disabled="isOpening">
    {{ isOpening ? '正在启动...' : '启动本地应用' }}
  </button>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  data() {
    return {
      isOpening: false,
      fallbackShown: false
    };
  },
  methods: {
    async openLocalApp() {
      if (this.isOpening) return;
      
      this.isOpening = true;
      
      // 方法1:使用 iframe(最兼容)
      const hiddenFrame = document.createElement('iframe');
      hiddenFrame.style.display = 'none';
      hiddenFrame.src = 'myapp://launch?timestamp=' + Date.now(); // 添加时间戳避免缓存
      document.body.appendChild(hiddenFrame);
      
      // // 方法2:使用 window.open(备用)
      // const fallbackTimer = setTimeout(() => {
      //   if (!this.fallbackShown) {
      //     this.fallbackShown = true;
      //     window.open('myapp://launch', '_blank');
      //   }
      // }, 100);
      
      // 监听各种可能的事件来判断应用是否启动
      const cleanup = () => {
        this.isOpening = false;
        // clearTimeout(fallbackTimer);
        clearTimeout(failTimer);
        hiddenFrame.remove();
        window.removeEventListener('blur', blurHandler);
        document.removeEventListener('visibilitychange', visibilityHandler);
      };
      
      const blurHandler = () => {
        console.log('应用启动成功 - 窗口失去焦点');
        cleanup();
        
        // 可选:显示成功提示
        setTimeout(() => {
          alert('应用启动成功!');
        }, 100);
      };
      
      const visibilityHandler = () => {
        if (document.hidden) {
          console.log('应用启动成功 - 页面被隐藏');
          cleanup();
        }
      };
      
      window.addEventListener('blur', blurHandler, { once: true });
      document.addEventListener('visibilitychange', visibilityHandler, { once: true });
      
      // 超时处理
      const failTimer = setTimeout(() => {
        if (this.isOpening) {
          cleanup();
          
          // 提供详细的错误帮助
          const userChoice = confirm(
            '应用启动可能需要额外权限。\n\n' +
            '可能的原因:\n' +
            '1. 防火墙或安全软件阻止\n' +
            '2. 需要手动允许协议启动\n' +
            '3. 应用路径不正确\n\n' +
            '点击"确定"查看详细解决方案'
          );
          
          if (userChoice) {
            window.open('/help#protocol-guide', '_blank');
          }
        }
      }, 5000); // 5秒超时
    }
  }
});
</script>
相关推荐
谢尔登5 小时前
Monorepo 架构
前端·arcgis·架构
栀秋6665 小时前
你会先找行还是直接拍平?两种二分策略你Pick哪个?
前端·javascript·算法
漂流瓶jz5 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·css
xhxxx5 小时前
传统工具调用太痛苦?LangChain 一键打通 LLM 与真实世界
前端·langchain·llm
南山安6 小时前
LangChain学习:Memory实战——让你的大模型记住你
前端·javascript·langchain
BD_Marathon6 小时前
Promise基础语法
开发语言·前端·javascript
BOF_dcb7 小时前
网页设计DW
前端
千寻girling7 小时前
计算机组成原理-全通关源码-实验(通关版)---头歌平台
前端·面试·职场和发展·typescript·node.js
karshey7 小时前
【前端】解决:点击一个button,发现不触发点击事件
前端
用泥种荷花7 小时前
【前端学习AI】Function Calling
前端