This is the fourth day of my participation in Gwen Challenge

Encapsulate enterprise wechat SDK

Realize multiple picture upload

Iframe redirection + generator solution.

The reason why iframe is used is that to solve the cross-domain problem, the enterprise wechat interface requires the POST method to send messages, so iframe+ POST is directly used to achieve cross-domain (described later).

Why generators? Because generators don’t want to be scoped like a for loop, generators are ones that can be taken from wherever they want. Specific scene:

Since I use the form for cross-domain purposes, when I send a request, the iframe on which the form is located redirects to the request result page, so I need to redirect it back to the current field. So be sure to wait until he is finished, the page jumps, then to redirect back to the current page. Ifame. SRC =”\” SRC =” onload “; submit =” onload “; So if you want to redirect, you have to lock it, otherwise when you redirect back, you’re going to go through onload, and you’re going to keep redirecting, and you’re going to loop.

So that’s the background, so when I redirect the page back, I want to send the next POST request, so I need to check which data I sent, if there’s any more, and if there’s any more, I need to unlock it.

The specific process is as follows:

  1. Send a form first

  2. Page redirects to request results page

  3. After onload, I start to determine if there is a lock

    Find it unlocked and redirect to iframe.src=”/”

    Locking prevents redirection

  4. Determine if there is next data

    If so, continue sending as form

  5. When sending a form, check whether the form is sent to the last one

    Either send the previous data or send it to the last one, or open the lock and allow the page to be redirected back again

    You can’t close the lock until the last one is sent

  6. . (Repeat the above steps until the data is sent)

In other words, it is not only the onload inside the iframe that needs to determine whether the data has been sent, but also the form that needs to determine whether the data has been sent. If you use the for loop, you have to write the two together, or pass the parameters to determine whether the data has been sent.

Start with a generator:

private* getMsg(msg) {
    let i = 0
    while (i < msg.length) {
        yield msg[i];
        i++
    }
    // The page was redirected the last time it was sent
    return "redirect";
}
Copy the code

Cross domain problem solving

Use the form + the iframe

Encapsulate an iframe:

// Prevent iframe redirection recursion
let lock = true
// Control iframe and send data using form
public IframePost(msg, format = "") :Promise<any>{
    // Only one iframe is required
    let iframe = window.frames["postFrame"]? .frameElement// If it is an array, it is a multi-image upload
    this.genMsg = Array.isArray(msg)?this.getMsg(msg):null
    if(! iframe){ iframe =document.createElement('iframe')
        iframe.style.display = "none";
        iframe.name = "postFrame"
        iframe.id = "postFrame"
        // Listen for the onload event, which is triggered when the page reloads
        iframe.addEventListener('load'.() = >{
            // The page can be redirected if it is not locked
            if(! lock){// Whether to redirect the page
                // Redirection process The current page -> submit data after running to the back-end data page -> back-end page onload redirects to the current page
                // If not redirected: Stay on the backend data page, you can see the data returned, but cannot send the request again due to cross-domain
                iframe.src = "/"
                // The redirection must be locked once, otherwise it will cause a redirection loop
                lock = true
                // If the generator has a value, proceed to the next message
                if(this.genMsg){
                    let nextMsg = this.genMsg.next()
                    // Use form to send data
                    // The nextmsg is sent to the last one.! nextMsg.done&&this.FormPost(nextMsg, format)
                }
            }
        })
        document.body.appendChild(iframe)
    }
    if(this.genMsg){
        // If it is an array (pictures and files), use the generator to get the send message
        return this.FormPost(this.genMsg.next(), format)
    }else{
        return this.FormPost(msg, format)
    }
}      
Copy the code

Encapsulate the form:

// Create a form to send data
private FormPost(msg, format = ""){
    const form = document.createElement("form");
    form.style.display = "none";
    // Put the form page in the frame. The advantage of this is that you can retrieve the form directly from Windows without putting it in the iframe
    form.target = "postFrame"
    form.id = "postForm"
    return new Promise((resolve, reject) = > {
        form.setAttribute("method"."POST");
        // Define the format of the form (message body format)
        this.getFormatForm(form, msg, format)
        document.body.appendChild(form);
        // Submit the form
        form.submit();
        resolve(form)
    }).then((resolve) = >{
        // Delete it after submission
        form.remove()
        // If one more redirection is required, the lock is left unlocked
        if(msg.value === "redirect"){
            lock = false
        }else{
            // Do not lock until the end of the sending message
            lock = msg.done
        }
    })
}
Copy the code
  1. Send application/ X-www-form-urlencoded format data

    The default is this format, so you don’t need to set anything much.

    form.setAttribute("action"."http://localhost:3000/efoxPayWechatTips");
    let bodyKey = [
        {
            name: "rootKey".value: this.key
        },
        {
            name: "sendMsg".value: this.genMsg? msg.value:msg } ] bodyKey.forEach((el) = > {
        var input = document.createElement("input");
        input.name = el.name;
        input.value = JSON.stringify(el.value);
        form.appendChild(input);
    })
    Copy the code
  2. Send formData data

    // If you want to send the formData type, assign the input from the page directly to the input of the form
    form.setAttribute("action"."http://localhost:3000/postFile");
    form.setAttribute("enctype"."multipart/form-data")
    let input = document.createElement("input");
    // When formData is used, MSG is actually an input, which is put directly into the form
    input = msg;
    form.appendChild(input);
    let keyInput = document.createElement("input");
    keyInput.name = "rootKey"
    keyInput.value = this.key
    form.appendChild(keyInput);
    Copy the code