这是我在堆栈溢出中的第一个问题。任何建议将不胜感激。
我正在创建一个网站,它的主要功能是允许用户上传所需数量的图像。它可以来自不同的文件夹,并且用户可以根据需要浏览图像多次。此外,用户可以预览他们选择的图像。如果用户不希望首先选择其中一张照片。用户可以通过单击预览图像附近的按钮将其删除。
在Laravel的View部分,您将看到一个按钮,用于浏览带有文本的多个文件,以告诉用户当前选择了多少张照片。当我使用View Part时,它似乎可以正常工作。但是,结果存储在表格之后。它显示它仅存储了所选照片仅来自上次浏览。
要查看更清晰的图片,这里是示例。
存储此图像的预期和正确的结果是,将A,B,C,E和F作为从用户选择的照片。但是,事实证明该数据库仅存储E和F,它们是第二次浏览的照片。
我想修复它,以便可以保存正确的照片;在这种情况下,A,B,C,E和F。
我使用JavaScript添加或删除预览图像,并添加复选框以存储所选图像的名称。稍后我将在Controller中使用它来检查它是否是用户要存储的文件。这是代码:
var totalFiles = [];
function handleFileSelect(evt) {
// FileList object
var files = evt.target.files;
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<input type="checkbox" name="selected[]" value="' , theFile.name, '" style="display: none;" checked /><img width=50% height="auto" class="thumb p-3" src="', e.target.result,
'" title="', theFile.name, '"/>', "<button onclick='deleteImage()'>" + "<i class='fas fa-trash-alt' aria-hidden='true'></i>" + " ลบรูปภาพ</button><br/>"].join('');
document.getElementById('preview_photo').insertBefore(span, null);
};
})(f);
totalFiles.push(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
if(Array.from(totalFiles).length > 0){
document.getElementById('count_selected_photo').innerHTML = "Image Selected: " + Array.from(totalFiles).length + " Photo(s)";
}
else{
document.getElementById('count_selected_photo').innerHTML = "No Image Selected";
}
}
function deleteImage() {
var index = Array.from(document.getElementById('preview_photo').children).indexOf(event.target.parentNode)
document.querySelector("#preview_photo").removeChild( document.querySelectorAll('#preview_photo span')[index]);
totalFiles.splice(index, 1);
if(Array.from(totalFiles).length > 0){
document.getElementById('count_selected_photo').innerHTML = "Image Selected: " + Array.from(totalFiles).length + " Photo(s)";
}
else{
document.getElementById('count_selected_photo').innerHTML = "No Image Selected";
}
}
document.getElementById('before_photo').addEventListener('change', handleFileSelect, false);
在Controller中,我使用request->file('before_photo')
删除之前选择的文件,并使用request->input('selected')
获取选择的照片的名称,并将这两个文件进行比较。如果request->file('before_photo')
中的文件名与request->input('selected')
中的文件名相同,它将存储该照片。如果不是,则意味着用户在单击“提交”之前将其删除,它将不会存储。
这是我在Controller中的代码的一部分:
// Store Photo If Existed
if (request()->hasFile('before_photo')) {
// File Chosen at First Time
$before_photos = $request->file('before_photo');
// File Chosen After Delete Image
$selected_photos = $request->input('selected');
// Collect Path of Each Photo
$paths = [];
// Collect File Name of Each Photo
$filenames = [];
foreach($selected_photos as $selected_photo){
foreach ($before_photos as $before_photo) {
// If File Name of Chosen Photo at First Time = File Name of Photo After Deleting
if($before_photo->getClientOriginalName() == $selected_photo){
// Transform The File Name to be 'before-photo-TIME-name-originalFileName'
$filename = "before-photo-" . time() . "-name-" . $before_photo->getClientOriginalName();
$paths[] = $before_photo->storeAs('', $filename, 'irepair_photo');
array_push($filenames, $filename);
}
}
}
// Transform List of Photo Name into Array
$repair_ticket->before_photo = $filenames;
}
如果对此有任何建议或意见,请在下面留言。谢谢您的关注。
这可能不是您要查找的内容,但应该引导您朝着正确的方向前进。我看到您使用的是原始JavaScript,这可能会使事情变得更棘手。但是由于您还使用了Laravel,并且Laravel附带了Vue支持(至少以前是这样),所以我将向您展示我使用Vue的实现。如果您知道JavaScript,那么它就会变得不难理解,因为Vue非常容易。
多文件上传的技巧是使用另一个数组存储文件,因为文件输入返回的本机FileList
对象是不可变的。查看下面的代码片段(我试图添加注释以解释我在做什么。)
您可以在此pen中看到一个有效的示例。
<!-- @change is the Vue equivalent of onchange -->
<input @change="handleFileSelect" type="file" multiple>
<ul>
<li v-for="(photo, index) in photos" :key="`thumb-${index}`">
<img :src="photo.preview" :alt="photo.file.name">
<button @click="removePhoto(index)" type="button">Remove Photo</button>
</li>
</ul>
在HTML部分,我们要做的就是聆听对文件输入的更改,并设置一个可以显示所选图像缩略图的位置。 Vue通过使用v-for
指令在数组上进行迭代使此操作非常容易。迭代中的当前元素可用于li
及其子元素,我们可以使用它来填充属性,例如img
的src
。
export default {
data() {
return {
photos: []
}
},
methods: {
handleFileSelect(e) {
Array.from(e.target.files).forEach(file => {
// perform check here such as making sure its an image
const reader = new FileReader()
reader.onload = () => {
// push the preview result and also the file to photos array
this.photos.push({
preview: reader.result,
file
})
}
reader.readAsDataURL(file)
})
},
removePhoto(index) {
this.photos.splice(index, 1)
},
upload() {
const fd = new FormData()
this.photos.forEach((photo, index) => {
// we only want to append the actual file, excluding the preview
// so we only append the `file` attribute
fd.append(`photo-${index}`, photo.file)
})
// send the data
// for example, using axios
const uploadEndpoint = ''
axios.post(uploadEndpoint, fd, {
headers: {
'Content-Type': 'multipart/form-data' // important
}
})
}
}
}
JavaScript部分非常简单。我们在这里所做的是设置photos
“本地状态”来存储我们的照片。我们使用此变量来迭代并在HTML中显示缩略图。当用户选择图像时,我们将使用FileReader
对象获取文件并为其生成缩略图,然后将其与实际文件一起推送至photos
变量。
{
preview: 'data:image/....', // the file preview generated by the FileReader
file: File object // the actual file the user selected
}
[当用户想要取消选择图像时,我们只是从splice
数组中选择photos
,因此photos
数组将始终包含用户要上传的照片。上载时,如果我们使用AJAX发送请求,则可以创建一个FormData
对象,并通过遍历photos
变量将每张照片附加到该对象上。在Laravel后端,可以使用request()->file()
访问这些照片。在发送请求之前,您必须设置适当的标题,主要是Content-Type: multipart/form-data
。
我希望这给了您一些有关如何解决此问题的一般思路。如果您有任何问题,请随时将其留在评论部分,我将尽力解释更多。