【问题标题】:Upload Image in Vue Component with Laravel使用 Laravel 在 Vue 组件中上传图片
【发布时间】:2019-04-18 19:34:44
【问题描述】:

我正在制作一个具有上传图片功能的简单网站。我尝试了 Laravel 方法,我在刀片模板中制作了它,它工作正常。现在我正试图在 Vue 组件中实现它

这是我的 Create.vue

<template>
  <div>

	 <div class="row">
		<input type="hidden" name="_token" :value="csrf">
		<div class="col-md-5">
			<div class="detail-container">
				<label for="title">Book Title:</label>
				<input type="text" name="title" id="title" v-model="book_title" class="form-control">
			</div>
			<div class="detail-container">
				<label for="title">Book Description:</label>
				<textarea type="text" name="description" id="description" v-model="book_description" class="form-control" rows="5"></textarea>
			</div>
			<div class="detail-container">
				<label for="title">Tags:</label>
				<multiselect v-model="tags" :show-labels="false" name="selected_tags" :hide-selected="true" tag-placeholder="Add this as new tag" placeholder="Search or add a tag" label="name" track-by="id" :options="tagsObject" :multiple="true" :taggable="true" @tag="addTag" @input="selectTags">
				<template slot="selection" slot-scope="tags"></template>
				</multiselect>
			</div>
		</div>

		<div class="col-md-7">
			<!-- BOOK COVER WILL GO HERE -->
			<div class="detail-container">
				<label>Book Cover:</label>
				<input type="file" class="form-control-file" id="book_cover" name="selected_cover" @change="onFileChange">
				<small id="fileHelp" class="form-text text-muted">After you select your desired cover, it will show the preview of the photo below.</small>
				<div id="preview">
					<img v-if="url" :src="url" height="281" width="180" />
				</div>
			</div>
		</div>
		<div class="detail-container" style="margin-top: 20px;">
			<button class="btn btn-primary" @click="saveBook()">Next</button>
		</div>
  </div>
  </div>
</template>

<script>
	import Multiselect from 'vue-multiselect'

	// register globally
	Vue.component('multiselect', Multiselect)

	export default {
		// OR register locally
		components: { Multiselect },
		data () {
			return {
				csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
				url: null,
				selected_cover: null,
				tags: [],
				tagsObject: [],
				selected_tags: [],
				book_title: '',
				book_description: ''
			}
		},
		methods: {
			getTags() {
				let vm = this;
				axios.get('/admin/getTags').then(function(result){
					let data = result.data;
					for(let i in data) {
						vm.tagsObject.push({id: data[i].id, name: data[i].name});
					}
				});
			},
			addTag (newTag) {
				const tag = {
					name: newTag,
					id: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
				}
				this.tagsObject.push(tag);
				this.tags.push(tag);
			},
			selectTags(value) {
				this.selected_tags = value.map(a=>a.id);
			},
			onFileChange(e) {
			  const file = e.target.files[0];
			  this.url = URL.createObjectURL(file);
			  this.selected_cover = file;
			},
			saveBook() {
				const fd = new FormData();
				fd.append('image', this.selected_cover, this.selected_cover.name)
				console.log(this.selected_cover);
				var book_details = {
					'title': this.book_title,
					'description': this.book_description,
					'book_cover': this.selected_cover,
					'tags': this.selected_tags
				};
				
				axios.post('/admin/saveBook', book_details).then(function(result){
					console.log('done')
				})
			}
		},
		created() {
			this.getTags();
		}
	}
</script>

<!-- New step!
	 Add Multiselect CSS. Can be added as a static asset or inside a component. -->
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

这是我的控制器

public function store(Request $request)
{

     $this->validate(request(), [
        'title' => 'required|min:5',
        'description' => 'required|min:10',
        'book_cover' => 'required|image|mimes:jpeg,jpg,png|max:10000'
     ]);
    // File Upload
    if($request->hasFile('book_cover')) {
        $fileNameWithExt = $request->file('book_cover')->getClientOriginalName();
        // GET FILE NAME
        $filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
        // GET EXTENSION
        $extension = $request->file('book_cover')->getClientOriginalExtension();
        // File Unique Name
        $fileNameToStore = $filename. '_'. time().'.'.$extension;
        $path = $request->file('book_cover')->storeAs('public/book_covers', $fileNameToStore);
    } else {
        $fileNameToStore = 'noimage.jpg';
    }

    $book = new Book;
    $book->title = request('title');
    $book->description = request('description');
    $book->book_cover = $fileNameToStore;
    $book->save();

    $book->tags()->sync($request->tags, false);

    return back()->with('success', 'Book Created Successfully!');

}

我从来没有碰过我的控制器,因为这是我在 Laravel Way 中执行此功能时使用的,但是当我保存它时,详细信息正在保存但图像没有上传,而是将 noimage.jpg 保存在数据库中。有谁知道我做错了什么?

我试图在book_details 中添加这部分const fd = new FormData();,但是当我console.log(fd) 时它没有返回任何数据。

【问题讨论】:

    标签: laravel-5 vue.js vuejs2 vue-component


    【解决方案1】:

    您应该在 POST 请求中传递 fd 对象而不是 book_details。

    你可以这样做。

    onFileChange(e) {
        const file = e.target.files[0];
        // this.url = URL.createObjectURL(file);
        this.selected_cover = file;
    },
    saveBook() {
        const fd = new FormData();
        fd.append('image', this.selected_cover)
        fd.append('title', this.book_title)
        fd.append('description', this.book_description)
        fd.append('book_cover', URL.createObjectURL(this.selected_cover))
        fd.append('tags', this.selected_tags)
    
        axios.post('/admin/saveBook', fd).then(function(result){
            console.log('done')
        })
    }
    

    而且,您不能只在控制台中console.log fd。你可以做的是这样的

    for (var pair of fd.entries()) {
        console.log(pair[0]+ ', ' + pair[1]); 
    }
    

    FormData 是一种特殊类型的对象,它不可字符串化,不能仅使用 console.log 打印出来。 (link)

    【讨论】:

    • 我需要更改控制器中的任何内容吗?
    • 这解决了我关于文件上传的问题,但发生了另一个错误。我的this.selected_tags 中出现错误,它显示“SQLSTATE[01000]:警告:1265 列 'tag_id' 的数据被截断
    猜你喜欢
    • 2021-07-19
    • 1970-01-01
    • 2020-09-27
    • 2017-12-16
    • 2018-08-15
    • 2020-01-11
    • 2018-08-01
    • 1970-01-01
    • 2018-09-26
    相关资源
    最近更新 更多