前端vue2中直接拉起vnc客户端

  1. 协议检测工具类 (src/utils/protocolCheck.js)
//1. 协议检测工具类 (src/utils/protocolCheck.js)
//javascript
// 浏览器检测函数
function checkBrowser() {
  const isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
  const ua = navigator.userAgent.toLowerCase();
  return {
    isOpera: isOpera,
    isFirefox: typeof InstallTrigger !== 'undefined',
    isSafari: (~ua.indexOf('safari') && !~ua.indexOf('chrome')) || 
              Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0,
    isIOS: /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream,
    isChrome: !!window.chrome && !isOpera,
    isIE: /*@cc_on!@*/false || !!document.documentMode
  }
}

// IE版本检测
function getInternetExplorerVersion() {
  let rv = -1;
  if (navigator.appName === 'Microsoft Internet Explorer') {
    const ua = navigator.userAgent;
    const re = new RegExp('MSIE ([0-9]{1,}[\.0-9]{0,})');
    if (re.exec(ua) != null) rv = parseFloat(RegExp.$1);
  } else if (navigator.appName === 'Netscape') {
    const ua = navigator.userAgent;
    const re = new RegExp('Trident/.*rv:([0-9]{1,}[\.0-9]{0,})');
    if (re.exec(ua) != null) rv = parseFloat(RegExp.$1);
  }
  return rv;
}

// 事件注册辅助函数
function _registerEvent(target, eventType, cb) {
  if (target.addEventListener) {
    target.addEventListener(eventType, cb);
    return {
      remove: function() {
        target.removeEventListener(eventType, cb);
      }
    };
  } else {
    target.attachEvent('on' + eventType, cb);
    return {
      remove: function() {
        target.detachEvent('on' + eventType, cb);
      }
    };
  }
}

// 创建隐藏iframe
function _createHiddenIframe(target, uri) {
  const iframe = document.createElement('iframe');
  iframe.src = uri;
  iframe.id = 'hiddenIframe';
  iframe.style.display = 'none';
  target.appendChild(iframe);
  return iframe;
}

// 各种浏览器处理函数
function openUriWithHiddenFrame(uri, failCb, successCb) {
  const timeout = setTimeout(function() {
    failCb();
    handler.remove();
  }, 1000);

  let iframe = document.querySelector('#hiddenIframe');
  if (!iframe) {
    iframe = _createHiddenIframe(document.body, 'about:blank');
  }

  const handler = _registerEvent(window, 'blur', onBlur);

  function onBlur() {
    clearTimeout(timeout);
    handler.remove();
    successCb();
  }

  iframe.contentWindow.location.href = uri;
}

function openUriWithTimeoutHack(uri, failCb, successCb) {
  const timeout = setTimeout(function() {
    failCb();
    handler.remove();
  }, 1000);

  let target = window;
  while (target != target.parent) {
    target = target.parent;
  }

  const handler = _registerEvent(target, 'blur', onBlur);

  function onBlur() {
    clearTimeout(timeout);
    handler.remove();
    successCb();
  }

  window.location = uri;
}

function openUriUsingFirefox(uri, failCb, successCb) {
  let iframe = document.querySelector('#hiddenIframe');
  if (!iframe) {
    iframe = _createHiddenIframe(document.body, 'about:blank');
  }

  try {
    iframe.contentWindow.location.href = uri;
    successCb();
  } catch (e) {
    if (e.name == 'NS_ERROR_UNKNOWN_PROTOCOL') {
      failCb();
    }
  }
}

function openUriUsingIEInOlderWindows(uri, failCb, successCb) {
  const version = getInternetExplorerVersion();
  if (version === 10) {
    openUriUsingIE10InWindows7(uri, failCb, successCb);
  } else if (version === 9 || version === 11) {
    openUriWithHiddenFrame(uri, failCb, successCb);
  } else {
    openUriInNewWindowHack(uri, failCb, successCb);
  }
}

function openUriUsingIE10InWindows7(uri, failCb, successCb) {
  const timeout = setTimeout(failCb, 1000);
  window.addEventListener('blur', function() {
    clearTimeout(timeout);
    successCb();
  });

  let iframe = document.querySelector('#hiddenIframe');
  if (!iframe) {
    iframe = _createHiddenIframe(document.body, 'about:blank');
  }
  try {
    iframe.contentWindow.location.href = uri;
  } catch (e) {
    failCb();
    clearTimeout(timeout);
  }
}

function openUriInNewWindowHack(uri, failCb, successCb) {
  const myWindow = window.open('', '', 'width=0,height=0');
  myWindow.document.write("<iframe src='" + uri + "'></iframe>");

  setTimeout(function() {
    try {
      myWindow.location.href;
      myWindow.setTimeout('window.close()', 1000);
      successCb();
    } catch (e) {
      myWindow.close();
      failCb();
    }
  }, 1000);
}

function openUriWithMsLaunchUri(uri, failCb, successCb) {
  navigator.msLaunchUri(uri, successCb, failCb);
}

// 主导出函数
export function protocolCheck(uri, failCb, successCb, unsupportedCb) {
  function failCallback() {
    failCb && failCb();
  }

  function successCallback() {
    successCb && successCb();
  }

  if (navigator.msLaunchUri) {
    openUriWithMsLaunchUri(uri, failCallback, successCallback);
  } else {
    const browser = checkBrowser();

    if (browser.isFirefox) {
      openUriUsingFirefox(uri, failCallback, successCallback);
    } else if (browser.isChrome || browser.isIOS) {
      openUriWithTimeoutHack(uri, failCallback, successCallback);
    } else if (browser.isIE) {
      openUriUsingIEInOlderWindows(uri, failCallback, successCallback);
    } else if (browser.isSafari) {
      openUriWithHiddenFrame(uri, failCallback, successCallback);
    } else {
      unsupportedCb && unsupportedCb();
    }
  }
}
  1. Vue 组件实现 (src/components/ProtocolChecker.vue)
<template>
  <div class="protocol-checker">
    <el-card shadow="hover">
      <template #header>
        <div class="card-header">
          <span>VNC 连接器</span>
        </div>
      </template>

      <el-form label-position="top">
        <el-form-item label="VNC 连接地址">
          <el-input 
            v-model="vncUrl" 
            placeholder="例如: com.realvnc.vncviewer.connect://10.0.66.98:20"
            clearable>
          </el-input>
        </el-form-item>

        <el-form-item>
          <el-button
            type="primary"
            :loading="loading"
            @click="handleProtocolCheck"
            icon="el-icon-connection">
            启动连接
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-dialog
      :title="dialogTitle"
      :visible.sync="dialogVisible"
      width="30%"
      :close-on-click-modal="false">
      <div class="dialog-content">
        <el-alert
          :title="dialogMessage"
          :type="alertType"
          :closable="false"
          show-icon>
        </el-alert>
      </div>
      <template #footer>
        <el-button @click="dialogVisible = false">关闭</el-button>
        <el-button
          v-if="showDownload"
          type="primary"
          @click="openDownloadPage">
          下载 VNC Viewer
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { protocolCheck } from '@/utils/protocolCheck'

export default {
  name: 'ProtocolChecker',
  data() {
    return {
      loading: false,
      dialogVisible: false,
      dialogTitle: '',
      dialogMessage: '',
      alertType: 'info',
      showDownload: false,
      vncUrl: 'com.realvnc.vncviewer.connect://10.0.66.98:20'
    }
  },
  methods: {
    handleProtocolCheck() {
      if (!this.vncUrl) {
        this.showDialog('错误', '请输入有效的VNC连接地址', 'error')
        return
      }

      this.loading = true
      
      protocolCheck(  //直接用这个方法就可以了
        this.vncUrl,
        () => {
          // 失败回调
          this.showDialog(
            '未检测到VNC Viewer', 
            '您的系统未安装VNC Viewer或协议不受支持', 
            'error',
            true
          )
          this.loading = false
        },
        () => {
          // 成功回调
          this.showDialog(
            '正在连接', 
            '正在启动VNC Viewer应用程序...', 
            'success'
          )
          this.loading = false
        },
        () => {
          // 浏览器不支持回调
          this.showDialog(
            '浏览器不支持', 
            '您的浏览器不支持此功能,请使用Chrome/Firefox/Edge浏览器', 
            'warning'
          )
          this.loading = false
        }
      )
    },

    showDialog(title, message, type = 'info', showDownload = false) {
      this.dialogTitle = title
      this.dialogMessage = message
      this.alertType = type
      this.showDownload = showDownload
      this.dialogVisible = true
    },

    openDownloadPage() {
      window.open('https://www.realvnc.com/en/connect/download/viewer/', '_blank')
      this.dialogVisible = false
    }
  }
}
</script>

<style scoped>
.protocol-checker {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.dialog-content {
  margin-bottom: 20px;
}
</style>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值