asp.net simple no refreshing file upload system _ Practical skills

Source: Internet
Author: User
Tags extend blank page
The effect of Ps:flash is much better, but this is not the scope of my research, and there is nothing comparable.

Compatible: IE6/7/8, Firefox 3.5.5, opera 10.01, Safari 4.0.3, Chrome 3.0
Effect Preview
Renaming
File Upload
Select File Operation State
Reset Select File
Reset Select File
Reset Select File

PS: Because of the need backstage, to test the system please download the instance test.
PS2: In the full instance file, there is also a file attribute to view the instance.

Program Description

"Upload"

The most important method in the program is upload, which can be invoked without refreshing upload.
The upload process is this, first stop the last upload with the Stop method, and decide whether to select files.
Then call _setiframe,_setform and _setinput separately to generate the required iframe,form and input.

If you set the Timeout property, the timer is set automatically:
Copy Code code as follows:

if (This.timeout > 0) {
This._timer = settimeout ($ $F. Bind (This._timeout, this), this.timeout * 1000);
}

PS: After testing, less than 0 of the delay time, IE will cancel execution, and other browsers will be executed as 0.

The program has a _sending attribute used to determine the upload status.
It is set to false at Stop (stop), Dispose (Destroy), _finis (finish), _timeout (timeout).
and set it to true before the upload starts.

The final submission of the form began to be uploaded.

"IFRAME"

The program uses the _setiframe function to create an IFRAME that does not need to be refreshed.

Because the name of the IFRAME in IE cannot be modified, create an IFRAME like this:
Copy Code code as follows:

var iframename = "Quickupload_" + quickupload._counter++,
iframe = document.createelement ($ $B. ie? "<iframe name=\" "+ iframename +" \ ">": "iframe");
Iframe.name = Iframename;
Iframe.style.display = "None";

PS: Questions about the name of the IFRAME refer to the IFRAME section here.
IE8 has been able to modify name, but it cannot be modified in a non-standard (odd) mode.
It uses a quickupload function's own _counter property as a calculator, which guarantees that the name of the IFRAME for each instance will not be duplicated.

In order to execute the callback function after the file upload is completed, the _finish function is executed in the onload of the IFRAME:
Copy Code code as follows:

var finish = This._ffinish = $ $F. Bind (This._finish, this);
if ($ $B. IE) {
Iframe.attachevent ("onload", finish);
} else {
Iframe.onload = $ $B. Opera? function () {this.onload = finish;}: Finish;
}

In IE need to use attachevent to bind onload, because in IE directly set onload is invalid.
In addition to using attachevent can also be replaced with onreadystatechange.
As for the reasons I am not clear, detailed reference to "determine whether the IFrame loading complete the perfect method."

There is also a problem with the loading of IFRAME, test the following code:

Copy Code code as follows:

<body><div id= "msg" > Status:</div></body>
<script>
var msg = document.getElementById ("msg");
var iframe = document.createelement ("iframe");
Iframe.onload = function () {msg.innerhtml + = "onload,";}
Document.body.appendChild (IFRAME);
IFRAME.SRC = "http://cloudgamer.cnblogs.com/"
</script>

As a result safari, Chrome will trigger the onload two times, while opera, FF and IE (please be compatible) are 1 times.

It is estimated that safari and chrome are loaded for the first time after appendchild, and the load is completed before SRC is set, so two times is triggered.
If an IFRAME is randomly set to the body before inserting the body (except for the null value), the indirect length is first loaded, and then it is triggered only once.
PS: src without setting or null value is equivalent to linking to "About:blank" (Blank page).

Then opera, FF and IE may be the first time to load too slow, the second cover the first time, so only triggered a onload.
PS: There may also be other reasons, such as browser optimization and so on, I am not sure.

For the problem of too fast loading, can be in the onload time according to _sending to determine whether the upload status to solve.
Although not tested out, will there be _sending settings after submit just before the first onload situation?
To address this problem, the upload method will place the _sending after the submit setting.
What if the onload is triggered before _sending is set up after the submit? (... 囧
This situation basically will not appear, if really appear, put the _sending settings in front of the submit bar.

Opera also has a problem to test the following code:
Copy Code code as follows:

<body>
<div id= "msg" > Status:</div>
<form action= "http://cloudgamer.cnblogs.com/" target= "IFR" >
</form>
</body>
<script>
var msg = document.getElementById ("msg");
var iframe = document.createelement ("iframe");
Iframe.name = "IFR";
Iframe.onload = function () {msg.innerhtml + = "onload,";}
Document.body.appendChild (IFRAME);
Msg.innerhtml + + "Submit,";
Document.forms[0].submit ();
</script>

IE and FF display Submit,onload,safari and Chrome show the onload,submit,onload, consistent with the above analysis.
But opera shows Submit,onload,onload, two times the onload is triggered after the submit.
This situation can not be solved simply with _sending.
Is the submit not allowed to cancel the iframe load?
Before AppendChild set a src, the result is normal only trigger the onload once, it seems to be possible ah.

Although do not know the reason, the solution is still some, one is appendchild before setting up a SRC, can also in the first onload to reset the onload, like the program.
But these two methods are uncertain, can not completely solve the problem, but also can not find a better way.

FF's onload There is also a problem, in the presence of Error_internet_connection_reset (file size exceeds the server limit), such as server errors, even if the load completion will not trigger the onload, temporarily find no solution.

An IFRAME has a flaw that can only be used to judge the loading complete, but there is no way to determine whether the load succeeds.
There is no such thing as the status of the XMLHTTP, there is no way to judge the mistakes of 404.
In the use of this to do a good job, such as the description of the allowable upload file size, timeout time, how to deal with a long time no response.


"Form"

The program uses the _setform function to create a form to submit data.

To implement a no-refresh upload, special handling of the form is needed:
Copy Code code as follows:

$$.extend (Form, {
Target:this._iframe.name, Method: "Post", Encoding: "Multipart/form-data"
});

PS: Look at the details here without the refresh upload part.

Because the form is inserted manually, set the form style to make it "invisible" in order not to affect the original page layout:
Copy Code code as follows:

$ $D. SetStyle (Form, {
padding:0, margin:0, border:0,
BackgroundColor: "Transparent", display: "Inline"
});

Also note that the same form control can only correspond to a single form.
If the file control itself already has a form, it must be removed before committing:

File.form && $ $E. Addevent (File.form, "submit", $ $F. Bind (This.dispose, this));
The Dispose method is used to destroy the program, including removing the form.
PS: If submit is overwritten before submitting, manually execute the Dispose method once.

Finally insert the form into the DOM:

File.parentNode.insertBefore (form, file). appendchild (file);
First insert the form before the file control, and then insert file into the form so that the file is in its original position.


"Input"

If there are other parameters to pass, the program uses the _setinput function to create form controls that pass data.

Because there is only a file control in the generated form, passing other parameters can only be generated using the program.
The program uses a _inputs collection to hold the form controls that are currently generated in the form.

First, create a form control based on the custom parameter property:

Copy Code code as follows:

for (name in This.parameter) {
var input = Form[name];
if (!input) {
input = document.createelement ("input");
Input.name = name; Input.type = "hidden";
Form.appendchild (input);
}
Input.value = This.parameter[name];
Newinputs[name] = input;
Delete Oldinputs[name];
}

When there is no control in the form that corresponds to name, an hidden control is automatically generated and inserted into the form.
Where Newinputs is used to record the currently generated control, and Oldinputs is the _inputs collection.
When a control with the corresponding name is set, the association of the corresponding control is removed from the oldinputs.

Then remove the oldinputs associated controls:

for (name in oldinputs) {form.removechild (Oldinputs[name]);}
This allows you to remove the unused controls that were generated last time.

Finally, re-log the current control to the _inputs for easy next use.


"Stop"

If you want to stop the current upload operation, you can call the Stop method.

In general, when an IFRAME overload, will cancel the last load, so as long as the reset src can cancel the upload.
Test the following code:

Copy Code code as follows:

<body>
<iframe id= "IFR" Name= "IFR" ></iframe>
<form action= "http://cloudgamer.cnblogs.com/" target= "IFR" >
</form>
</body>
<script>
Document.forms[0].submit ();
document.getElementById ("IFR"). src = "";
</script>

Results can be canceled, except opera, unknown what reason.
There are two ways to solve, one is to use a form to submit one action at a time, there is a direct removal of the IFRAME.
The latter method is more convenient, the program uses _removeiframe method to remove the IFRAME directly.
PS: Remember to tell me if there is a better way.


"Dispose"

You can call the Dispose method when you want to destroy a program by using an end or some other reason.

The main thing in the Dispose is to remove the iframe and form.
To remove an IFRAME is the _removeiframe method, first remove the onload, and then remove the IFRAME from the body:

var iframe = This._iframe;
$ $B. ie? Iframe.detachevent ("onload", This._ffinish): (iframe.onload = null);
Document.body.removeChild (IFRAME); This._iframe = null;
Very simple, but there is a problem in FF, test the following code:
Copy Code code as follows:

<form target= "IFR" action= "X" >
<input id= "BTN" type= "Submit" value= "click" >
</form>
<iframe name= "IFR" id= "IFR" ></iframe>
<script>
document.getElementById ("btn"). onclick = function () {
document.getElementById ("IFR"). onload = function () {
This.parentNode.removeChild (this);
};
}
</script>

The IFRAME can be removed after submission, but FF also shows the status of "load".
However, the solution is also very simple, with settimeout set a delay, so that the implementation of the IFRAME can be complete.
So the _removeiframe is called in Dispose:
Copy Code code as follows:

if ($ $B. Firefox) {
SetTimeout ($ $F. Bind (This._removeiframe, this), 0);
} else {
This._removeiframe ();
}

The removal of the form is simpler and is handled in _removeform:
Copy Code code as follows:

var form = this._form, parent = Form.parentnode;
if (parent) {
Parent.insertbefore (this.file, form); Parent.removechild (form);
}
This._form = This._inputs = null;

To judge the parentnode, otherwise, if the parentnode does not exist, the following error will be executed.

"Reset of File"

In the example, there is a resetfile function to reset the file control.

The general way to reset a file control is to reset the form in which it is located, but the problem is to reset the other form controls as well.
Previously, the value of file was not allowed to be modified because of security concerns.
But now Ff,chrome and Safari can set it to a null value to reset:

File.value = "";
Of course, other values are not allowed.
PS: Memory is not the past, I do not know if I remember wrong.

For opera, there is an alternative way to take advantage of its type attribute:

File.type = "text"; File.type = "File";
By modifying the file control that the type obtains, value is automatically restored to a null value, which empties the file control indirectly.
PS: Using this method can indirectly get file path, but due to change back after the value is emptied, so no use.

And the IE form control of the type set is not allowed to modify, can not use opera method.
However, there are still the following ways to resolve:
1, create a new form, insert the file into the reset, and then remove:
Copy Code code as follows:

With (File.parentNode.insertBefore (document.createelement (' form '), file) {
AppendChild (file); Reset (); Removenode (FALSE);
}

The advantage is to use the original reset, stable and reliable, but inefficient.
Ps:removenode is only supported by IE and opera, and should be compatible with the removechild approach.

2, using outerhtml to reconstruct a file control:

file.outerhtml = file.outerhtml;
The benefit is efficient, but because it is the newly created file control, the previously associated items are lost.
PS:FF Support does not support outerhtml.

3, using CloneNode to copy a file control:

File.parentNode.replaceChild (File.clonenode (False), file);
Similar to the previous one, but less efficient.

4, select the Text field of the file control using the Select method, and then empty:

File.select (); Document.selection.clear ();
Or

File.select (); Document.selection.clear ();
There seems to be no problem, but file must be select (not hidden).
PS: Both of these methods can only be used in IE.

Methods 2 and 3 are not available because file in the program needs to be associated.
Method 4 looks good too, but there is a fatal problem in IE testing the following code:
Copy Code code as follows:

<form><input id= "Test" name= "file" type= "file" ></form>
<script>
document.getElementById ("Test"). onchange = function () {
This.select (); Document.selection.clear ();
This.form.submit ();
}
</script>

Execution to submit will show "Access Denied" error, the reason is not clear, do not know whether IE intentional or bug.

It seems that only method 1 is used:
Copy Code code as follows:

function Resetfile (file) {
File.value = "";//ff Chrome Safari
if (File.value) {
if ($ $B. IE) {//ie
With (File.parentNode.insertBefore (document.createelement (' form '), file) {
AppendChild (file); Reset (); Removenode (FALSE);
}
else {//opera
File.type = "text"; File.type = "File";
}
}
}

PS: If there is a better way to remember to tell me AH.

This function is not general enough, it is best to choose the method according to the actual situation.

Use Tips

"Number of files uploaded"

In the file upload instance, each file is uploaded at the same time.
After testing, the number of files the browser can upload at the same time is as follows:
IE 2
FF 8
Opera 8
Chrome 6
Safari 6
Because IE can only pass 2 at the same time, so set more files can only queue, and can not achieve the effect of uploading simultaneously.
PS: Just visual results, please raise the wrong.

"Pass Parameters"

Upload file instances, you can pass the corresponding modified file name, in the use of "general upload" multiple files upload together can also find the corresponding file name.
Because the form control values are passed to the background, the order in which the data is fetched is in the same order as the previous form control.
You can use this attribute to get the corresponding value as long as you ensure that the foreground file control is in the same order as the corresponding form control.
Detailed reference background code.

"Callback function"

There are two ways to respond to the upload completion callback function.
One is after the background upload completes, in the IFRAME output and executes the callback function or invokes the parent window's callback function through parent.
This is more convenient, but you must perform processing within the IFRAME, such as file properties to view instances.
The other is to execute the callback function in the onload of the IFRAME.
The advantage is that you can put all the processing in the parent window, the IFRAME can not do any processing or to feedback information.
The disadvantage is that there is a compatibility problem, and there will be loaded after the onload does not trigger the situation (above the IFRAME section has a description).
The upload file instance is the data that is processed in the onfinish in the IFRAME.
Because there may be some unexpected circumstances that result in a long response or even no response, be sure to set timeout in case.

"Process return Data"

As mentioned above, data that is output in an IFRAME can be processed in onfinish.
To get data from the body of an IFRAME, there are several ways to do this:
Iframe.contentWindow.document.body.innerHTML
Iframe.contentDocument.body.innerHTML
Window.frames[iframename].document.body.innerhtml
The first two are similar, the latter is relatively simple, but IE does not support contentdocument, unfortunately.
The third is to take advantage of the frames object, noting that the object being obtained directly is the Window object.
Because the program can directly obtain the IFrame object, so use the first way.
However, there is a problem in the IFRAME part also mentioned, is to return the error message page problem.
In the upload file instance, the output in the IFRAME is JSON-form file information data.
This is done in the onfinish:
Copy Code code as follows:

try{
var info = eval ("+ Iframe.contentWindow.document.body.innerHTML +"));
Show ("Upload complete");
}catch (e) {
Show ("Upload failed"); Stop (); Return
}

Only returns the correct JSON format data to function correctly, otherwise throws the error, indirectly excludes 404 error messages.
PS: There is a better way to welcome the proposal.

"Destruction Program"

There are many DOM operations in the program, and it is best to perform a Dispose method to destroy the program when you do not need to continue using it.
For example, after removing file, before closing the window, before submitting the form, before the form element, and so on.
It can save resources, prevent the memory leak of the DOM, and avoid the conflict problem when the form is nested.

"Availability"

After reading "PPK talk JavaScript", more attention to usability.
Upload the instance in the browser does not support JS situation can also normal upload, you can test yourself.

Coding

A no refresh upload system, many people reflect the file name after uploading garbled, and later found that the problem is coding.
When there is a Chinese information transmission, should pay attention to the front and back of the code must be unified, including CharSet, file encoding, web.config configuration and so on.

"ASP Version"

The ASP version is the same as the. NET version feature, using a component-free upload class.
However, the upload class itself has a flaw in the submission of the same name of the file control error, after modification can now be used normally.


Instructions for use

When instantiated, the first necessary parameter is the file control object:

New Quickupload (file);

The Second optional parameter is used to set the default properties of the system, including
Properties: Default value//description
Parameter: {},//Parameter object
Action: "",//Set action
timeout:0,//set timeout (in seconds)
Onready:function () {},//upload ready to execute
Onfinish:function () {},//execution when upload completes
Onstop:function () {},//execution when upload stops
Ontimeout:function () {}//upload timeout execution

The following methods are also available:
Upload: Perform upload operation;
Stop: The upload operation is stopped;
Dispose: Destroy the program.


Program source Code
Copy Code code as follows:


var quickupload = function (file, options) {

This.file = $$ (file);

This._sending = false;//is uploading
This._timer = null;//Timer
This._iframe = Null;//iframe Object
This._form = Null;//form Object
This._inputs = {};//input Object
This._ffinish = null;//Complete Execution function

$$.extend (This, this._setoptions (options));
};
Quickupload._counter = 1;
Quickupload.prototype = {
Set default Properties
_setoptions:function (options) {
This.options = {//default value
Action: "",//Set action
timeout:0,//set timeout (in seconds)
Parameter: {},//Parameter object
Onready:function () {},//upload ready to execute
Onfinish:function () {},//execution when upload completes
Onstop:function () {},//execution when upload stops
Ontimeout:function () {}//upload timeout execution
};
Return $$.extend (this.options, Options | | {});
},
Uploading files
Upload:function () {
Stop last Upload
This.stop ();
No file returned
if (!this.file | |!this.file.value) return;
May modify related properties in Onready so put it in front.
This.onready ();
Setting up Iframe,form and form controls
This._setiframe ();
This._setform ();
This._setinput ();
Set timeout
if (This.timeout > 0) {
This._timer = settimeout ($ $F. Bind (This._timeout, this), this.timeout * 1000);
}
Start uploading
This._form.submit ();
This._sending = true;
},
Set IFRAME
_setiframe:function () {
if (!this._iframe) {
Create an IFRAME
var iframename = "Quickupload_" + quickupload._counter++,
iframe = document.createelement ($ $B. ie? "<iframe name=\" "+ iframename +" \ ">": "iframe");
Iframe.name = Iframename;
Iframe.style.display = "None";
Record completion procedure for easy removal
var finish = This._ffinish = $ $F. Bind (This._finish, this);
Execute the completion program after the IFRAME finishes loading
if ($ $B. IE) {
Iframe.attachevent ("onload", finish);
} else {
Iframe.onload = $ $B. Opera? function () {this.onload = finish;}: Finish;
}
Insert Body
var body = document.body; Body.insertbefore (iframe, body.childnodes[0]);

This._iframe = iframe;
}
},
Set form
_setform:function () {
if (!this._form) {
var form = document.createelement (' form '), file = This.file;
Setting properties
$$.extend (Form, {
Target:this._iframe.name, Method: "Post", Encoding: "Multipart/form-data"
});
Set style
$ $D. SetStyle (Form, {
padding:0, margin:0, border:0,
BackgroundColor: "Transparent", display: "Inline"
});
Remove form before submitting
File.form && $ $E. Addevent (File.form, "submit", $ $F. Bind (This.dispose, this));
Insert Form
File.parentNode.insertBefore (form, file). appendchild (file);

This._form = form;
}
Action may Modify
This._form.action = this.action;
},
Set input
_setinput:function () {
var form = this._form, oldinputs = this._inputs, newinputs = {}, name;
Set input
for (name in This.parameter) {
var input = Form[name];
if (!input) {
If there is no corresponding input, create a new
input = document.createelement ("input");
Input.name = name; Input.type = "hidden";
Form.appendchild (input);
}
Input.value = This.parameter[name];
Log Current input
Newinputs[name] = input;
Delete an existing record
Delete Oldinputs[name];
}
Remove useless input
for (name in oldinputs) {form.removechild (Oldinputs[name]);}
Save current input
This._inputs = newinputs;
},
Stop uploading
Stop:function () {
if (this._sending) {
This._sending = false;
Cleartimeout (This._timer);
Reset iframe
if ($ $B. Opera) {//opera by setting SRC There will be a problem
This._removeiframe ();
} else {
THIS._IFRAME.SRC = "";
}
This.onstop ();
}
},
Destruction procedures
Dispose:function () {
This._sending = false;
Cleartimeout (This._timer);
Clear IFRAME
if ($ $B. Firefox) {
SetTimeout ($ $F. Bind (This._removeiframe, this), 0);
} else {
This._removeiframe ();
}
Clear Form
This._removeform ();
Clear Dom Association
this._inputs = This._ffinish = This.file = null;
},
Clear IFRAME
_removeiframe:function () {
if (this._iframe) {
var iframe = This._iframe;
$ $B. ie? Iframe.detachevent ("onload", This._ffinish): (iframe.onload = null);
Document.body.removeChild (IFRAME); This._iframe = null;
}
},
Clear Form
_removeform:function () {
if (this._form) {
var form = this._form, parent = Form.parentnode;
if (parent) {
Parent.insertbefore (this.file, form); Parent.removechild (form);
}
This._form = This._inputs = null;
}
},
Timeout function
_timeout:function () {
if (this._sending) {this._sending = false; This.stop (); This.ontimeout ();}
},
Completion function
_finish:function () {
if (this._sending) {this._sending = false; This.onfinish (this._iframe);}
}
}

Full instance Download
Full instance download (ASP version)
Related applications: JavaScript image upload Preview effect
Reprint please indicate the source: http://www.cnblogs.com/cloudgamer/
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.