今天遇见了需要根据后端接口返回得地址确定新跳页面得需求,简单记录下

196 阅读1分钟

背景

根据接口返回的url地址,打开新的标签页,部分用户出现浏览器拦截新窗口弹出甚至不提醒拦截弹窗的问题
原方案是在获取url之后直接使用window.open()window.location.href

原因

浏览器确认是用户操作的情况下,window.open()不会被拦截,但若是在ajax的回调里面进行window.open(),会拦截!因为浏览器的安全策略会认为这是一个骚扰用户的行为,不同浏览器的安全级别不同,也会根据用户的设置而表现不同。

经测试,方案一、二可以解决问题,其他方案测试无效,可自行试验

方案一: 先打开新标签页之后重定向页面

该方案的问题在于会优先打开一个 空白网页,如果网速太慢会出现白屏等待,可以在窗口写入用户提示标语

  async openNewTab(url: string) {
    const openNewWindow = window.open('', '_blank') // 在请求之前打开一个新页面
    openNewWindow.document.write('努力加载中,请稍后...')
    try {
      const resData = await this['$api'].get(this, url)
      if (resData && resData.code === 200) {
        openNewWindow.location.href = resData.url // 重定向页面URL
      }
    } catch (err) {
      log(err)
    }
  }

方案二: 将Ajax请求修改成同步请求

经测试axios框架使用asyncawait来模拟同步请求无效,需要原生Ajax请求设置为同步请求才有效
缺陷是当接口响应时间太长还是会出现拦截窗口的问题

  async openNewTab(url: string) {
    // 第四步,发送HTTP请求
    this.ajax({
      url: url, // 请求地址
      type: 'GET', // 请求方式
      success: function (response, xml) {
        // 此处放成功后执行的代码
        window.open(JSON.parse(response).url)
      },
      fail: function (status) {
        // 此处放失败后执行的代码
      }
    })
  }

  ajax(options) {
    // 第一步,创建一个XHR对象,也即一个异步调用的对象
    function createXHR() {
      let xhr
      // 非IE6
      if (typeof XMLHttpRequest !== 'undefined') {
        xhr = new XMLHttpRequest()
      } else if (typeof ActiveXObject !== 'undefined') {
        // IE6及以下版本浏览器
        xhr = new ActiveXObject('Microsoft.XMLHTTP')
      } else {
        xhr = null
      }
      return xhr
    }

    var xhr = createXHR()

    // 第二步,设置相应HTTP请求的状态变化函数
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if ((xhr.status >= 200 && xhr.status <= 300) || xhr.status === 304) {
          options.success(xhr.responseText)
        } else {
          options.fail(xhr.status)
        }
      }
    }

    // 第三步,创建一个新的HTTP请求,并设置请求的方式、URL,是否异步
    if (options.type === 'GET') {
      xhr.open('GET', options.url, options.params, false)  // 设置为同步请求
      xhr.send(null)
    }
  }

方案三: js生成a标签,修改a标签href或自定义点击事件

①修改a标签href,模拟用户点击

  async openNewTab(url: string) {
    try {
      const resData = await this['$api'].get(this, url)
      if (resData && resData.code === 200) {
        // 使用 a 标签 实现页面跳转
        const RecurrenceHtml = document.createElement('a')
        RecurrenceHtml.setAttribute('href', resData.url)
        RecurrenceHtml.setAttribute('target', '_blank')
        RecurrenceHtml.style.display = 'none'
        document.body.appendChild(RecurrenceHtml)
        RecurrenceHtml.click()
        document.body.removeChild(RecurrenceHtml)
      }
    } catch (err) {
      log(err)
    }
  }

②设置自定义点击事件,模拟用户点击

  async openNewTab(url: string) {
    try {
      const resData = await this['$api'].get(this, url)
      if (resData && resData.code === 200) {
        // 使用 a 标签 模拟实现用户点击自定义事件,实现页面跳转
        const RecurrenceHtml= document.createElement('a')
        RecurrenceHtml.onclick = function () {
          window.open(resData.url, '_blank')
        }
        document.body.appendChild(RecurrenceHtml)
        RecurrenceHtml.click()
        document.body.removeChild(RecurrenceHtml)
      }
    } catch (err) {
      log(err)
    }
  }

方案四: js生成form表单,使用form.submit来访问

  async openNewTab(url: string) {
    const openNewWindow = window.open('', '_blank') // 在请求之前打开一个新页面
    try {
      const resData = await this['$api'].get(this, url)
      if (resData && resData.code === 200) {
        // 使用 form.submit 实现页面跳转
        const form = document.createElement('form')
        form.action = resData.url
        form.target = '_blank'
        form.method = 'GET'
        document.body.appendChild(form)
        form.submit()
      }
    } catch (err) {
      log(err)
    }
  }