使用Laravel在Vue组件中上传图像

时间:2018-11-15 16:27:51

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

我正在制作一个具有上传图片功能的简单网站。我尝试了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保存在数据库中。有人知道我在做什么错吗?

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

1 个答案:

答案 0 :(得分:0)

您应该在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