基于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>
相关推荐
鲨莎分不晴12 小时前
【实战】老项目焕发新生:从 Webpack 平滑迁移到 Vite 避坑全记录
前端·webpack·node.js
web小白成长日记13 小时前
从零起步,用TypeScript写一个Todo App:踩坑与收获分享
前端·javascript·typescript
圣心13 小时前
Gemini 模型 介绍
前端
huangyiyi6666613 小时前
前端-远程多选搜索框不能反显的问题解决
前端·javascript·vue.js·笔记·学习
敲敲了个代码13 小时前
让 Vant 弹出层适配 Uniapp Webview 返回键
前端·javascript·vue.js·学习·面试·uni-app
AOwhisky13 小时前
Ansible管理变量和事实(管理变量部分) & 部署文件到受管主机
前端·chrome·ansible
小二·14 小时前
Python Web 开发进阶实战:绿色软件工程 —— 构建低能耗、低碳排的可持续应用
开发语言·前端·python
hhcccchh14 小时前
学习vue第十四天 小白学父组件传递子组件(Props)
前端·vue.js·学习
派大鑫wink14 小时前
【Day32】Tomcat 服务器:安装、配置与 Web 应用部署
服务器·前端·tomcat
蜕变菜鸟14 小时前
数组参数赋值
linux·前端·javascript