回答:
直接的な解決策ではありませんが、(私がテストした限り)onfocusでのみ機能する(かなり限定的なイベントブロッキングが必要)ので、次のようにしてそれを実現できます。
document.body.onfocus = function(){ /*rock it*/ }
これの良い点は、ファイルイベントに合わせてアタッチまたはデタッチできることです。また、非表示の入力でも問題なく動作するようです(不快なデフォルトの入力type = 'に視覚的な回避策を使用している場合は確実な特典ですファイル')。その後、入力値が変更されたかどうかを確認する必要があります。
例:
var godzilla = document.getElementById('godzilla')
godzilla.onclick = charge
function charge()
{
document.body.onfocus = roar
console.log('chargin')
}
function roar()
{
if(godzilla.value.length) alert('ROAR! FILES!')
else alert('*empty wheeze*')
document.body.onfocus = null
console.log('depleted')
}
実際に見る:http : //jsfiddle.net/Shiboe/yuK3r/6/
悲しいことに、それはWebkitブラウザーでのみ機能するようです。多分誰かがfirefox / IEソリューションを理解することができます
addEventListener("focus",fn,{once: true})
。しかし、document.body.addEventListener
..を使用してもまったく起動できませんでした。理由はわかりません。代わりに、で同じ結果が得られましたwindow.addEventListener
。
mousemove
イベントをリッスンするwindow.document
だけでなく、イベントをリッスンすることfocus
はwindow
どこでも機能するようです(少なくとも最近のブラウザでは、過去10年の残骸は気にしません)。基本的に、開いているファイルを開くダイアログによってブロックされるこのタスクには、任意の対話イベントを使用できます。
できません。
ファイルダイアログの結果はブラウザに公開されません。
change
場合は、何も変更されていないため、イベントは送出されません。
change
イベントも送出されません。
私は新しい解決策を思いついたので、私はこの質問に私の帽子を投げます。ユーザーが写真やビデオをキャプチャしてアップロードできるプログレッシブWebアプリがあります。可能な場合はWebRTCを使用しますが、サポートが少ない* sough Safari cough *デバイスのHTML5ファイルピッカーにフォールバックします。特にネイティブカメラを使用して写真/ビデオを直接キャプチャするAndroid / iOSモバイルWebアプリケーションで作業している場合、これは私が遭遇した最良のソリューションです。
この問題の核心は、ページのロード時に、ということでfile
あるnull
が、ユーザが対話し、プレスを開いたときに「キャンセル」、file
まだnull
何の「変更」イベントがトリガされていないので、したがってそれは、「変更」しませんでした。デスクトップの場合、ほとんどのデスクトップUIはいつキャンセルが呼び出されたかを知る必要がないため、これはそれほど悪くありませんが、カメラを起動して写真/ビデオをキャプチャするモバイルUIは、いつキャンセルが押されたかを知ることに非常に依存しています。
私は当初document.body.onfocus
、ユーザーがファイルピッカーから戻ったときを検出するためにイベントを使用しましたが、これはほとんどのデバイスで機能しましたが、そのイベントがトリガーされないため、iOS 11.3はイベントを壊しました。
これに対する私の解決策は、ページが現在フォアグラウンドにあるかバックグラウンドにあるかを判断するためにCPUタイミングを測定する*シュダー*です。モバイルデバイスでは、現在フォアグラウンドにあるアプリに処理時間が与えられます。カメラが表示されている場合、CPU時間を盗み、ブラウザの優先順位を下げます。カメラを起動したときに使用可能な時間が大幅に減少する場合、ページに与えられた処理時間を測定するだけで済みます。カメラが却下された場合(キャンセルされた場合でもそうでない場合でも)、利用可能な時間は急増します。
setTimeout()
Xミリ秒でコールバックを呼び出すことでCPUタイミングを測定し、実際にそれを呼び出すのにかかった時間を測定できます。ブラウザはXミリ秒後に正確にそれを呼び出すことは決してありませんが、それが合理的に近い場合、フォアグラウンドにいる必要があります。ブラウザが非常に遠くにある場合(要求よりも10倍以上遅い)、バックグラウンドにいる必要があります。これの基本的な実装は次のようになります。
function waitForCameraDismiss() {
const REQUESTED_DELAY_MS = 25;
const ALLOWED_MARGIN_OF_ERROR_MS = 25;
const MAX_REASONABLE_DELAY_MS =
REQUESTED_DELAY_MS + ALLOWED_MARGIN_OF_ERROR_MS;
const MAX_TRIALS_TO_RECORD = 10;
const triggerDelays = [];
let lastTriggerTime = Date.now();
return new Promise((resolve) => {
const evtTimer = () => {
// Add the time since the last run
const now = Date.now();
triggerDelays.push(now - lastTriggerTime);
lastTriggerTime = now;
// Wait until we have enough trials before interpreting them.
if (triggerDelays.length < MAX_TRIALS_TO_RECORD) {
window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
return;
}
// Only maintain the last few event delays as trials so as not
// to penalize a long time in the camera and to avoid exploding
// memory.
if (triggerDelays.length > MAX_TRIALS_TO_RECORD) {
triggerDelays.shift();
}
// Compute the average of all trials. If it is outside the
// acceptable margin of error, then the user must have the
// camera open. If it is within the margin of error, then the
// user must have dismissed the camera and returned to the page.
const averageDelay =
triggerDelays.reduce((l, r) => l + r) / triggerDelays.length
if (averageDelay < MAX_REASONABLE_DELAY_MS) {
// Beyond any reasonable doubt, the user has returned from the
// camera
resolve();
} else {
// Probably not returned from camera, run another trial.
window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
}
};
window.setTimeout(evtTimer, REQUESTED_DELAY_MS);
});
}
私は最近のバージョンのiOSとAndroidでこれをテストし、<input />
要素に属性を設定してネイティブカメラを起動しました。
<input type="file" accept="image/*" capture="camera" />
<input type="file" accept="video/*" capture="camcorder" />
これは実際には私が予想したよりもはるかにうまく機能します。タイマーを25ミリ秒で呼び出すように要求することにより、10回の試行を実行します。次に、呼び出しに実際にかかった時間を測定し、10回の試行の平均が50ミリ秒未満の場合は、フォアグラウンドにいる必要があり、カメラがなくなっていると想定します。50ミリ秒を超える場合は、バックグラウンドで待機している必要があります。
後者は、お互いの直後に実行される複数の呼び出しをキューに入れることができるためではsetTimeout()
なく、使用しましたsetInterval()
。これにより、データのノイズが大幅に増加する可能性があるため、setTimeout()
少し複雑ですが、こだわりました。
これらの特定の数値は私にとってはうまくいきましたが、カメラの終了が時期尚早に検出された例を少なくとも一度は見ました。これは、カメラの開きが遅く、デバイスが実際にバックグラウンドになる前に10回の試行を実行する可能性があるためと考えられます。この機能を開始する前に、トライアルを追加するか、25〜50ミリ秒待機することで、この問題の回避策となる場合があります。
残念ながら、これはデスクトップブラウザでは実際には機能しません。理論的には、バックグラウンドページよりも現在のページを優先するので、同じトリックが可能です。ただし、多くのデスクトップには、バックグラウンドでもページをフルスピードで実行し続けるのに十分なリソースがあるため、この戦略は実際には機能しません。
私が探求したと多くの人が言及していない代替ソリューションの1つは、をあざけることでしたFileList
。私たちは、で始まるnull
に<input />
、ユーザーがカメラを開き、彼らが戻ってくるまでキャンセルした場合、その後とnull
変更なしイベントではありませんこれは、トリガされます。1つの解決策は<input />
、ページ開始時にダミーファイルを割り当てることです。null
と、適切なイベントをトリガーする変更になります。
残念ながら、を作成する公式な方法はありませんFileList
。また、<input />
要素にはFileList
特にが必要であり、以外の値は受け入れられませんnull
。当然のことながら、FileList
オブジェクトを直接構築することはできません。明らかに関連がなくなった古いセキュリティ問題に対処します。<input />
要素の外側で1つを取得する唯一の方法は、データをコピーして貼り付けるハックを利用して、FileList
オブジェクト偽造することです(基本的には、ファイルのドラッグアンドドロップを偽造しています) -your-website event)。これはFirefoxでは可能ですが、iOS Safariでは不可能であるため、私の特定のユースケースでは実行できませんでした。
言うまでもなく、これは明らかにばかげています。重要なUI要素が変更されたというWebページへの通知がゼロであるという事実は、ただ笑えるだけです。これは実際には仕様のバグです。フルスクリーンのメディアキャプチャUIを意図したものではなく、「変更」イベントをトリガーしないことは技術的にはに仕様に基づいています。
しかし、ブラウザのベンダーはこれの現実を認識できますか?これは、変更が発生しない場合でもトリガーされる新しい「done」イベントで解決するか、とにかく「change」をトリガーするだけで解決できます。ええ、それは仕様に反しますが、JavaScript側で変更イベントを重複排除するのは簡単ですが、自分の「完了」イベントを発明することは基本的に不可能です。ブラウザの状態が保証されていない場合でも、私の解決策は本当にヒューリスティックです。
現状では、このAPIは基本的にモバイルデバイスでは使用できません。ブラウザを比較的簡単に変更するだけで、Web開発者が* Soap Box *を使用するのが非常に簡単になると思います。
ファイルを選択して[開く/キャンセル]をクリックすると、input
要素はフォーカスを失います(別名)blur
。のイニシャルが空value
であると仮定すると、ハンドラーのinput
空でない値はすべてblur
OKを示し、空の値はキャンセルを意味します。
更新:が非表示のblur
場合、input
はトリガーされません。したがって、一時的にを表示したい場合を除き、IFRAMEベースのアップロードでこのトリックを使用することはできませんinput
。
blur
、ファイルを選択してもトリガーされません。他のブラウザでは試していません。
/* Tested on Google Chrome */
$("input[type=file]").bind("change", function() {
var selected_file_name = $(this).val();
if ( selected_file_name.length > 0 ) {
/* Some file selected */
}
else {
/* No file selected or cancel/close
dialog button clicked */
/* If user has select a file before,
when they submit, it will treated as
no file selected */
}
});
else
ステートメントが評価されるかどうかを確認しましたか?
これらの解決策のほとんどは私にはうまくいきません。
問題は、どのイベントが最初にトリガーされるかわからないclick
ことchange
です。おそらくブラウザの実装に依存するため、順序を想定することはできません。
少なくともOperaとChrome(2015年後半)click
では、入力がファイルで「満たされる」直前にトリガーされるため、の後にトリガーされるfiles.length != 0
まで遅延click
するまでの長さがわかりませんchange
。
ここにコードがあります:
var inputfile = $("#yourid");
inputfile.on("change click", function(ev){
if (ev.originalEvent != null){
console.log("OK clicked");
}
document.body.onfocus = function(){
document.body.onfocus = null;
setTimeout(function(){
if (inputfile.val().length === 0) console.log("Cancel clicked");
}, 1000);
};
});
クリックイベントも聞いてください。
Shiboeの例から、jQueryの例を次に示します。
var godzilla = $('#godzilla');
var godzillaBtn = $('#godzilla-btn');
godzillaBtn.on('click', function(){
godzilla.trigger('click');
});
godzilla.on('change click', function(){
if (godzilla.val() != '') {
$('#state').html('You have chosen a Mech!');
} else {
$('#state').html('Choose your Mech!');
}
});
あなたはここでそれを実際に見ることができます:http : //jsfiddle.net/T3Vwz
以前と同じファイルを選択して[キャンセル]をクリックすると、キャンセルをキャッチできます(この場合)。
あなたはこのようにそれを行うことができます:
<input type="file" id="myinputfile"/>
<script>
document.getElementById('myinputfile').addEventListener('change', myMethod, false);
function myMethod(evt) {
var files = evt.target.files;
f= files[0];
if (f==undefined) {
// the user has clicked on cancel
}
else if (f.name.match(".*\.jpg")|| f.name.match(".*\.png")) {
//.... the user has choosen an image file
var reader = new FileReader();
reader.onload = function(evt) {
try {
myimage.src=evt.target.result;
...
} catch (err) {
...
}
};
}
reader.readAsDataURL(f);
</script>
最も簡単な方法は、一時メモリにファイルがあるかどうかを確認することです。ユーザーがファイル入力をクリックするたびに変更イベントを取得したい場合は、それをトリガーできます。
var yourFileInput = $("#yourFileInput");
yourFileInput.on('mouseup', function() {
$(this).trigger("change");
}).on('change', function() {
if (this.files.length) {
//User chose a picture
} else {
//User clicked cancel
}
});
Shiboeのソリューションは、モバイルWebキットで機能すれば良いものですが、そうではありません。私が思いつくことができるのは、次のように、ファイル入力ウィンドウが開いているときに、いくつかのdomオブジェクトにmousemoveイベントリスナーを追加することです。
$('.upload-progress').mousemove(function() {
checkForFiles(this);
});
checkForFiles = function(me) {
var filefield = $('#myfileinput');
var files = filefield.get(0).files;
if (files == undefined || files[0] == undefined) $(me).remove(); // user cancelled the upload
};
ファイルダイアログが開いている間、mousemoveイベントはページからブロックされ、閉じたときに、ファイル入力にファイルがあるかどうかを確認します。私の場合、ファイルがアップロードされるまでアクティビティインジケーターがブロックするので、キャンセル時にインジケーターのみを削除します。
ただし、移動するマウスがないため、これはモバイルでは解決しません。私の解決策は完全ではありませんが、十分に良いと思います。
$('.upload-progress').bind('touchstart', function() {
checkForFiles(this);
});
これで、同じファイルのチェックを行うために画面をタッチするのを待機しています。このアクティビティインジケーターをキャンセルして閉じた後、ユーザーの指が画面にすばやく表示されると確信しています。
ファイル入力変更イベントにアクティビティインジケーターを追加することもできますが、モバイルでは、画像の選択と変更イベントの起動の間に数秒の遅れがあることが多いため、アクティビティインジケーターがアクティビティに表示されるのは、はるかに優れたUXです。プロセスの開始。
私はこの属性を見つけましたが、その最も単純なものです。
if ($('#selectedFile')[0].files.length > 1)
{
// Clicked on 'open' with file
} else {
// Clicked on 'cancel'
}
ここはselectedFile
ですinput type=file
。
私はこれが非常に古い質問であることを知っていますが、誰かを助けるために、onmousemoveイベントを使用してキャンセルを検出すると、短時間でそのようなイベントを2つ以上テストする必要があることがわかりました。これは、カーソルがファイル選択ダイアログウィンドウの外に移動するたび、およびメインウィンドウの外に移動するたびに、ブラウザー(Chrome 65)によって1つのonmousemoveイベントが生成されるためです。マウス移動イベントの単純なカウンターカウンターをゼロにリセットする短い期間のタイムアウトと相まって、ごちそうになりました。
私の場合、ユーザーが画像を選択している間、送信ボタンを非表示にする必要がありました。
これは私が思いついたものです:
$(document).on('click', '#image-field', function(e) {
$('.submit-button').prop('disabled', true)
})
$(document).on('focus', '#image-field'), function(e) {
$('.submit-button').prop('disabled', false)
})
#image-field
私のファイルセレクタです。誰かがクリックすると、フォーム送信ボタンが無効になります。重要なのは、ファイルダイアログが閉じたとき-ファイルを選択したかキャンセルしたかに関係なく- #image-field
フォーカスが戻ったので、そのイベントをリッスンします。
更新
私は、これはサファリとポルターガイスト/ファントムで動作しないことを発見しました。実装する場合は、この情報を考慮してください。
Shiboeのソリューションとalxのソリューションを組み合わせると、最も信頼できるコードが得られます。
var selector = $('<input/>')
.attr({ /* just for example, use your own attributes */
"id": "FilesSelector",
"name": "File",
"type": "file",
"contentEditable": "false" /* if you "click" on input via label, this prevents IE7-8 from just setting caret into file input's text filed*/
})
.on("click.filesSelector", function () {
/* do some magic here, e.g. invoke callback for selection begin */
var cancelled = false; /* need this because .one calls handler once for each event type */
setTimeout(function () {
$(document).one("mousemove.filesSelector focusin.filesSelector", function () {
/* namespace is optional */
if (selector.val().length === 0 && !cancelled) {
cancelled = true; /* prevent double cancel */
/* that's the point of cancel, */
}
});
}, 1); /* 1 is enough as we just need to delay until first available tick */
})
.on("change.filesSelector", function () {
/* do some magic here, e.g. invoke callback for successful selection */
})
.appendTo(yourHolder).end(); /* just for example */
一般に、mousemoveイベントはトリックを実行しますが、ユーザーがクリックした場合は、次のようになります。
... mousemoveイベントを取得しないため、キャンセルコールバックはありません。さらに、ユーザーが2番目のダイアログをキャンセルしてマウスを動かすと、2つのキャンセルコールバックが返されます。幸いなことに、特別なjQuery focusInイベントがどちらの場合もドキュメントにバブルアップし、そのような状況を回避するのに役立ちます。唯一の制限は、いずれかがfocusInイベントをブロックする場合です。
mousemove
しているdocument
ときにイベントをキャッチしました。マウスを動かさない場合、またはキーボードだけを使用してファイルを選択する場合は問題ありません。ダイアログを開いたまま、キャンセルをできる限り早く検出するために、「早すぎる」ではなく、に置き換える必要がありましmousemove
たkeydown
。
私の回答はかなり古くなっていると思いますが、それよりもずっと少ないことはありません。私も同じ問題に直面しました。これが私の解決策です。最も有用なコードはKGAのものです。しかし、それは完全には機能しておらず、少し複雑です。しかし、私はそれを簡略化しました。
また、トラブルの主な原因は、「変更」イベントがフォーカスの直後に発生しないことです。そのため、しばらく待つ必要があります。
"#appendfile"-ユーザーがクリックして新しいファイルを追加します。Hrefはフォーカスイベントを取得します。
$("#appendfile").one("focusin", function () {
// no matter - user uploaded file or canceled,
// appendfile gets focus
// change doesn't come instantly after focus, so we have to wait for some time
// wrapper represents an element where a new file input is placed into
setTimeout(function(){
if (wrapper.find("input.fileinput").val() != "") {
// user has uploaded some file
// add your logic for new file here
}
else {
// user canceled file upload
// you have to remove a fileinput element from DOM
}
}, 900);
});
これは限られた状況でのみ検出できます。具体的には、Chromeでは、以前にファイルを選択してからファイルダイアログをクリックしてキャンセルをクリックすると、ChromeはファイルをクリアしてonChangeイベントを発生させます。
https://code.google.com/p/chromium/issues/detail?id=2508
このシナリオでは、onChangeイベントを処理し、filesプロパティを確認することでこれを検出できます。
以下は私にとってはうまくいくようです(デスクトップ、Windows):
var openFile = function (mimeType, fileExtension) {
var defer = $q.defer();
var uploadInput = document.createElement("input");
uploadInput.type = 'file';
uploadInput.accept = '.' + fileExtension + ',' + mimeType;
var hasActivated = false;
var hasChangedBeenCalled = false;
var hasFocusBeenCalled = false;
var focusCallback = function () {
if (hasActivated) {
hasFocusBeenCalled = true;
document.removeEventListener('focus', focusCallback, true);
setTimeout(function () {
if (!hasChangedBeenCalled) {
uploadInput.removeEventListener('change', changedCallback, true);
defer.resolve(null);
}
}, 300);
}
};
var changedCallback = function () {
uploadInput.removeEventListener('change', changedCallback, true);
if (!hasFocusBeenCalled) {
document.removeEventListener('focus', focusCallback, true);
}
hasChangedBeenCalled = true;
if (uploadInput.files.length === 1) {
//File picked
var reader = new FileReader();
reader.onload = function (e) {
defer.resolve(e.target.result);
};
reader.readAsText(uploadInput.files[0]);
}
else {
defer.resolve(null);
}
};
document.addEventListener('focus', focusCallback, true); //Detect cancel
uploadInput.addEventListener('change', changedCallback, true); //Detect when a file is picked
uploadInput.click();
hasActivated = true;
return defer.promise;
}
これはangularjs $ qを使用しますが、必要に応じて他のpromiseフレームワークに置き換えることができるはずです。
IE11、Edge、Chrome、Firefoxでテストされていますが、Focusイベントを発生させないため、AndroidタブレットのChromeでは動作しないようです。
file
型フィールドは、イライラ、イベントの多く(ぼかしが美しいだろう)に応答しません。多くの人々が- change
指向の解決策を提案し、彼らが反対票を投じているのを見ます。
change
作業を行いますが、それは(私たちがどのような対主要な欠陥を持っていたい起こること)。
ファイルフィールドを含むページを新たにロードしたら、ボックスを開いてキャンセルを押します。イライラして何も変わりません。
私が選択したのは、ゲート状態でのロードです。
section#after-image
私の場合、フォームaの次の部分は表示されません。ときに私のfile field
変更、アップロードボタンが表示されます。アップロードが成功すると、section#after-image
が表示されます。change
このキャンセルによってイベントがトリガーされます。適切なファイルが選択されるまで、アップロードボタンを非表示にすることができます(実際に行うことができます)。幸運にも、このゲート状態はすでに私のフォームのデザインでした。同じスタイルを使用する必要はありません。最初にアップロードボタンを非表示にし、変更時に非表示フィールドまたはJavaScript変数を送信時に監視できるものに設定するだけです。
フィールドが操作される前に、files [0]の値を変更してみました。これはonchangeに関しては何もしませんでした。
ですからchange
、少なくとも私たちが手に入れようとしているように、うまくいきます。filefieldは、明らかな理由で保護されていますが、善意の開発者のフラストレーションに対して保護されています。
これは私の目的には合いませんがonclick
、警告プロンプト(alert()
ページ処理が停止するため、ではなく)をロードして、変更がトリガーされ、files [0]がnullの場合は非表示にすることができます。変更がトリガーされない場合、divはその状態のままです。
これを行うハッキーな方法があります(コールバックを追加するか、alert()
呼び出しではなく遅延/約束の実装を解決します)。
var result = null;
$('<input type="file" />')
.on('change', function () {
result = this.files[0];
alert('selected!');
})
.click();
setTimeout(function () {
$(document).one('mousemove', function () {
if (!result) {
alert('cancelled');
}
});
}, 1000);
仕組み:ファイル選択ダイアログが開いている間、ドキュメントはマウスポインターイベントを受け取りません。ダイアログが実際に表示され、ブラウザウィンドウがブロックされるまでに1000ミリ秒の遅延があります。ChromeとFirefoxでチェックインしました(Windowsのみ)。
しかし、これはもちろんキャンセルされたダイアログを検出する信頼できる方法ではありません。ただし、UIの動作が改善される場合があります。
これが私の解決策です、ファイル入力フォーカスを使用しています(タイマーは使用していません)
var fileInputSelectionInitiated = false;
function fileInputAnimationStart() {
fileInputSelectionInitiated = true;
if (!$("#image-selector-area-icon").hasClass("fa-spin"))
$("#image-selector-area-icon").addClass("fa-spin");
if (!$("#image-selector-button-icon").hasClass("fa-spin"))
$("#image-selector-button-icon").addClass("fa-spin");
}
function fileInputAnimationStop() {
fileInputSelectionInitiated = false;
if ($("#image-selector-area-icon").hasClass("fa-spin"))
$("#image-selector-area-icon").removeClass("fa-spin");
if ($("#image-selector-button-icon").hasClass("fa-spin"))
$("#image-selector-button-icon").removeClass("fa-spin");
}
$("#image-selector-area-wrapper").click(function (e) {
$("#fileinput").focus();
$("#fileinput").click();
});
$("#preview-image-wrapper").click(function (e) {
$("#fileinput").focus();
$("#fileinput").click();
});
$("#fileinput").click(function (e) {
fileInputAnimationStart();
});
$("#fileinput").focus(function (e) {
fileInputAnimationStop();
});
$("#fileinput").change(function(e) {
// ...
}
Error: { "message": "Uncaught SyntaxError: missing ) after argument list", "filename": "https://stacksnippets.net/js", "lineno": 51, "colno": 1 }
これはせいぜいハックですが、これは実際の例ですユーザーがファイルをアップロードしたかどうかを検出し、ファイルをアップロードした場合にのみ続行することを許可する私のソリューションのです。
基本的には非表示Continue
、Save
、Proceed
または任意のあなたのボタンがあります。次に、JavaScriptでファイル名を取得します。ファイル名に値がない場合は、Continue
ボタンを。値がある場合は、ボタンを表示します。これは、最初にファイルをアップロードしてから、別のファイルをアップロードして[キャンセル]をクリックした場合にも機能します。
これがコードです。
HTML:
<div class="container">
<div class="row">
<input class="file-input" type="file" accept="image/*" name="fileUpload" id="fileUpload" capture="camera">
<label for="fileUpload" id="file-upload-btn">Capture or Upload Photo</label>
</div>
<div class="row padding-top-two-em">
<input class="btn btn-success hidden" id="accept-btn" type="submit" value="Accept & Continue"/>
<button class="btn btn-danger">Back</button>
</div></div>
JavaScript:
$('#fileUpload').change(function () {
var fileName = $('#fileUpload').val();
if (fileName != "") {
$('#file-upload-btn').html(fileName);
$('#accept-btn').removeClass('hidden').addClass('show');
} else {
$('#file-upload-btn').html("Upload File");
$('#accept-btn').addClass('hidden');
}
});
CSS:
.file-input {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.file-input + label {
font-size: 1.25em;
font-weight: normal;
color: white;
background-color: blue;
display: inline-block;
padding: 5px;
}
.file-input:focus + label,
.file-input + label:hover {
background-color: red;
}
.file-input + label {
cursor: pointer;
}
.file-input + label * {
pointer-events: none;
}
CSSの多くは、Webサイトとボタンに誰もがアクセスできるようにすることです。ボタンのスタイルを自由に設定できます。
まあ、これはあなたの質問に正確に答えるものではありません。私の想定では、ファイル入力を追加してファイル選択を呼び出すシナリオがあり、ユーザーがキャンセルを押した場合は入力を削除するだけです。
これが事実である場合:空のファイル入力を追加する理由は?
オンザフライで作成しますが、それが入力されたときにのみDOMに追加します。
var fileInput = $("<input type='file' name='files' style='display: none' />");
fileInput.bind("change", function() {
if (fileInput.val() !== null) {
// if has value add it to DOM
$("#files").append(fileInput);
}
}).click();
そこで、ここで<input type = "file" />をその場で作成し、そのchangeイベントにバインドして、すぐにクリックを呼び出します。変更時は、ユーザーがファイルを選択して[OK]をクリックした場合にのみ起動します。それ以外の場合、入力はDOMに追加されないため、送信されません。
ここでの作業例:https : //jsfiddle.net/69g0Lxno/3/
すでにJQueryが必要な場合は、このソリューションが機能する可能性があります(これは私の場合に実際に必要なコードとまったく同じですが、Promiseを使用すると、ファイルの選択が解決されるまでコードを強制的に待機させることができます)。
await new Promise(resolve => {
const input = $("<input type='file'/>");
input.on('change', function() {
resolve($(this).val());
});
$('body').one('focus', '*', e => {
resolve(null);
e.stopPropagation();
});
input.click();
});
このスレッドにはいくつかの解決策が提案されており、ユーザーがファイル選択ボックスの[キャンセル]ボタンをクリックしたときに検出することの困難さは、多くの人に影響を与える問題です。
実際には、ユーザーがファイル選択ボックスの[キャンセル]ボタンをクリックしたかどうかを検出する100%信頼できる方法はありません。しかし、ユーザーがファイルを追加したかどうかを確実に検出する方法があります入力ファイルにをます。これがこの回答の基本戦略です!
他の回答がほとんどのブラウザで機能しないか、モバイルデバイスで保証されていないため、この回答を追加することにしました。
簡単に言うと、コードは3つのポイントに基づいています。
よりよく理解するために、以下のコードとメモも見てください。
[...]
<button type="button" onclick="addIptFl();">ADD INPUT FILE!</button>
<span id="ipt_fl_parent"></span>
[...]
function dynIptFl(jqElInst, funcsObj) {
if (typeof funcsObj === "undefined" || funcsObj === "") {
funcsObj = {};
}
if (funcsObj.hasOwnProperty("before")) {
if (!funcsObj["before"].hasOwnProperty("args")) {
funcsObj["before"]["args"] = [];
}
funcsObj["before"]["func"].apply(this, funcsObj["before"]["args"]);
}
var jqElInstFl = jqElInst.find("input[type=file]");
// NOTE: Open the file selection box via js. By Questor
jqElInstFl.trigger("click");
// NOTE: This event is triggered if the user selects a file. By Questor
jqElInstFl.on("change", {funcsObj: funcsObj}, function(e) {
// NOTE: With the strategy below we avoid problems with other unwanted events
// that may be associated with the DOM element. By Questor
e.preventDefault();
var funcsObj = e.data.funcsObj;
if (funcsObj.hasOwnProperty("after")) {
if (!funcsObj["after"].hasOwnProperty("args")) {
funcsObj["after"]["args"] = [];
}
funcsObj["after"]["func"].apply(this, funcsObj["after"]["args"]);
}
});
}
function remIptFl() {
// NOTE: Remove the input file. By Questor
$("#ipt_fl_parent").empty();
}
function addIptFl() {
function addBefore(someArgs0, someArgs1) {
// NOTE: All the logic here happens just before the file selection box opens.
// By Questor
// SOME CODE HERE!
}
function addAfter(someArgs0, someArgs1) {
// NOTE: All the logic here happens only if the user adds a file. By Questor
// SOME CODE HERE!
$("#ipt_fl_parent").prepend(jqElInst);
}
// NOTE: The input file is hidden as all manipulation must be done via js.
// By Questor
var jqElInst = $('\
<span>\
<button type="button" onclick="remIptFl();">REMOVE INPUT FILE!</button>\
<input type="file" name="input_fl_nm" style="display: block;">\
</span>\
');
var funcsObj = {
before: {
func: addBefore,
args: [someArgs0, someArgs1]
},
after: {
func: addAfter,
// NOTE: The instance with the input file ("jqElInst") could be passed
// here instead of using the context of the "addIptFl()" function. That
// way "addBefore()" and "addAfter()" will not need to be inside "addIptFl()",
// for example. By Questor
args: [someArgs0, someArgs1]
}
};
dynIptFl(jqElInst, funcsObj);
}
ありがとう!= D
以下のような角度で実現しました。
<input type="file" formControlName="FileUpload" click)="handleFileInput($event.target.files)" />
/>
this.uploadPanel = false;
handleFileInput(files: FileList) {
this.fileToUpload = files.item(0);
console.log("ggg" + files);
this.uploadPanel = true;
}
@HostListener("window:focus", ["$event"])
onFocus(event: FocusEvent): void {
if (this.uploadPanel == true) {
console.log("cancel clicked")
this.addSlot
.get("FileUpload")
.setValidators([
Validators.required,
FileValidator.validate,
requiredFileType("png")
]);
this.addSlot.get("FileUpload").updateValueAndValidity();
}
}
タイプがファイルである入力に「変更」リスナーを追加するだけです。すなわち
<input type="file" id="file_to_upload" name="file_to_upload" />
私はjQueryを使用しましたが、明らかに(要件に従って)誰でもvalina JSを使用できます。
$("#file_to_upload").change(function() {
if (this.files.length) {
alert('file choosen');
} else {
alert('file NOT choosen');
}
});
.change()
ユーザーがファイルピッカーで[キャンセル]をクリックすると、確実に呼び出されません。
enter code here
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<h1>Hello</h1>
<div id="cancel01">
<button>Cancel</button>
</div>
<div id="cancel02">
<button>Cancel</button>
</div>
<div id="cancel03">
<button>Cancel</button>
</div>
<form>
<input type="file" name="name" placeholder="Name" />
</form>
<script>
const nameInput = document.querySelector('input[type="file"]');
/******
*The below code if for How to detect when cancel is clicked on file input
******/
nameInput.addEventListener('keydown', e => {
/******
*If the cancel button is clicked,then you should change the input file value to empty
******/
if (e.key == 'Backspace' || e.code == 'Backspace' || e.keyCode == 8) {
console.log(e);
/******
*The below code will delete the file path
******/
nameInput.value = '';
}
});
</script>
</body>
</html>
注:このコードはキャンセルを検出せず、人々がそれを検出しようとする一般的なケースでそれを検出する必要性を回避する方法を提供します。
非表示の入力を使用してファイルをアップロードするためのソリューションを探しているときにここに来ました、これがファイル入力のキャンセルを検出する方法を探す最も一般的な理由だと思います(ファイルを開くダイアログ->ファイルが選択されている場合はいくつかを実行します)コード、そうでなければ何もしない)、これが私の解決策です:
var fileSelectorResolve;
var fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');
fileSelector.addEventListener('input', function(){
fileSelectorResolve(this.files[0]);
fileSelectorResolve = null;
fileSelector.value = '';
});
function selectFile(){
if(fileSelectorResolve){
fileSelectorResolve();
fileSelectorResolve = null;
}
return new Promise(function(resolve){
fileSelectorResolve = resolve;
fileSelector.dispatchEvent(new MouseEvent('click'));
});
}
ファイルが選択されていない場合、最初の行は1回だけselectFile()
呼び出さfileSelectorResolve()
れます(または、他の場所から呼び出された場合)。
async function logFileName(){
const file = await selectFile();
if(!file) return;
console.log(file.name);
}
もう一つの例:
async function uploadFile(){
const file = await selectFile();
if(!file) return;
// ... make an ajax call here to upload the file ...
}
入力フィールドでjquery変更リスナーを作成し、ユーザーがフィールドの値によってアップロードウィンドウをキャンセルまたは閉じたことを検出できます。
ここに例があります:
//when upload button change
$('#upload_btn').change(function(){
//get uploaded file
var file = this.files[0];
//if user choosed a file
if(file){
//upload file or perform your desired functiuonality
}else{
//user click cancel or close the upload window
}
});
e.target.files