Recently, I was involved in an emergency project. As the Chinese New Year is approaching, the construction period is tight, and the product design is rough, I encountered a small problem!

The requirements are as follows: click a download button to batch download multiple ZIP materials, such as 🌰, click the button, the back end returns an array of download Url, and then, the front end needs to trigger the download at once.

I thought, this is easy, iterate through the array, and then simulate a link, download each URL ah, so the following code appears:

// Download the function
const download = (link: string) = > {
    const el = getLinkNodeElement()
    el.setAttribute('href', link)
    triggerClick(el)
}

// Create a link
const getLinkNodeElement = () = > {
    const id = 'node-download'
    let el = document.getElementById(id)
    if(! el) { el =document.createElement('a')
      el.setAttribute('id', id)
      el.setAttribute('target'.'_blank')
      el.setAttribute('rel'.'noopener')
      document.body.appendChild(el)
    }
    return el
}

// Simulation click a link
const triggerClick = (node: HTMLElement) = > {
    try {
      if (document.createEvent) {
        const evt = document.createEvent('MouseEvents')
        evt.initEvent('click'.true.false)
        node.dispatchEvent(evt)
      } else if ((document as any).createEventObject) {
        (node as any).fireEvent('onclick')}}catch (e) {
      node.click()
    } 
}

// Get the address, iterate, batch download
const downloadZip = async() = > {await bookListVM.getZips()  // Get the zips download address
    bookListVM.zipUrlList.forEach((list) = > {   
      download(list.url)   // Iterate to download each URL})}Copy the code

I thought I’d call it a day, but once I tested it, I only downloaded one at a time, and the others got blocked by the browser.

Because the download address and the current system is not the same domain!! This is the browser’s security mechanism.

Isn’t it funny that you always have to allow this pop-up window to display if you want to continue downloading? The client won’t even notice this place!

Even if you did, you might not be willing to allow it. It’s not safe!

And the download, the page is still shaking, this scheme is broken.

It’s not that simple. Reverse the plan and start again!

Think briefly, how do you get around the browser’s security intercepts?

The answer is: open a new blank page, the browser will not block it, and then set the page as our download address

Well, I did it, and here’s the code:

const download = (url: string) = > {
  const win = window.open()
  win.src = url
}
// Get the address, iterate, batch download
const downloadZip = async() = > {await bookListVM.getZips()  // Get the zips download address
    bookListVM.zipUrlList.forEach((list) = > {   
      download(list.url)   // Iterate to download each URL})}Copy the code

Just finished writing, found the problem, this is not right, I want to open more than one page oh, I am batch triggered batch download! I jump out to a blank page, how to continue to open other blank pages??

A burst of meng Circle, it seems that or not, it seems that the problem is not so simple ah!

Nevertheless, already promised to test, half an hour is done, this see remaining 10 come minutes, cannot hit face!!

Think again, there must be a way, suddenly think of, why download must a link, this train of thought is a dead end, what can start to download?

Then I thought of iframe, it can also carry url ah, also can download? That label I don’t like, I didn’t think it was gonna save my life today.

Then you have the following code:

const download = (url) = > {
  var iframe = document.createElement('iframe') // Create an iframe tag
  iframe.style.display = 'none' // Can not be seen in the page, hide it, does not affect our use
  iframe.style.height = '0px'  // Give it a height of 0 so it doesn't affect the layout of the page
  iframe.src = url  // Link to our download address
  document.body.appendChild(iframe) // Bind it to the body to work, otherwise it will work
  setTimeout(() = > { 
    iframe.remove()    // If the iframe does not have an onload event, it must be cleared in setTimeout. If the zip package is too large, it must be cleared in setTimeout.
  }, 5000)}// Get the address, iterate, batch download
const downloadZip = async() = > {await bookListVM.getZips()  // Get the zips download address
    bookListVM.zipUrlList.forEach((list) = > {   
      download(list.url)   // Iterate to download each URL})}Copy the code

We’re done, we’re done, we have one minute left, let’s test it out and see what happens,

Click “Download”, the browser will pop up a prompt, whether you are allowed to download multiple files (will only prompt once), click “Allow”, the download is successful, Perfect!

Soon to go home for the Spring Festival, fortunately did not play hit, or wise sweep the floor ~

Move test, go home for the Spring Festival.