創(chuàng)建 images 目錄酣胀,并放置一張圖片當(dāng)做默認(rèn)圖片,最好把 images 目錄權(quán)限設(shè)置為 777(images的路徑: public)
20180105174650.png
修改 路由文件 index.js (路徑:resources/assets/js/router 下)
import Vue from 'vue';
import VueRouter from 'vue-router';
import Register from '../views/Auth/Register.vue';
import Login from '../views/Auth/Login.vue';
import RecipeIndex from '../views/Recipes/Index.vue';
import RecipeShow from '../views/Recipes/Show.vue';
import RecipeForm from '../views/Recipes/Form.vue';
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{path: '/register', component: Register},
{path: '/login', component: Login},
{path: '/', component: RecipeIndex},
{path: '/recipes/create', component: RecipeForm, meta: {mode: 'create'}},
{path: '/recipes/:id/edit', component: RecipeForm, meta: {mode: 'edit'}},
{path: '/recipes/:id', component: RecipeShow}
]
});
export default router;
添加 Recipes 文件夾 并在該文件夾下創(chuàng)建 Index.vue 全度、Form.vue 和 Show.vue (創(chuàng)建Recipes文件夾 的 路徑:/resources/assets/js/views)
Index.vue
<template>
<div class="recipe__list">
<div class="recipe__item" v-for="recipe in recipes">
<router-link class="recipe__inner" :to="`/recipes/${recipe.id}`">
<img :src="`/images/${recipe.image}`" v-if="recipe.image">
<p class="recipe__name">{{recipe.name}}</p>
</router-link>
</div>
</div>
</template>
<script type="text/javascript">
import { get } from '../../helpers/api';
export default{
data(){
return {
recipes : []
}
},
methods: {
},
created(){
get('/api/recipes')
.then((res) => {
this.recipes = res.data.recipes;
})
.catch((err) => {
});
}
}
</script>
Form.vue
<template>
<div class="recipe__show">
<div class="recipe__header">
<h3>{{action}} Recipe</h3>
<div>
<button class="btn btn__primary" @click="save" :disabled="isProcessing">Save</button>
<button class="btn" @click="$router.back()" :disabled="isProcessing">Cancel</button>
</div>
</div>
<div class="recipe__row">
<div class="recipe__image">
<div class="recipe__box">
<image-upload v-model="form.image"></image-upload>
<small class="error__control" v-if="error.image">{{error.image[0]}}</small>
</div>
</div>
<div class="recipe__details" >
<div class="recipe__details_inner">
<div class="form__group">
<label>Name</label>
<input type="text" class="form__control" v-model="form.name">
<small class="error__control" v-if="error.name">{{error.name[0]}}</small>
</div>
<div class="form__group">
<label>Description</label>
<textarea type="text" class="form__control" v-model="form.description"></textarea>
<small class="error__control" v-if="error.description">{{error.description[0]}}</small>
</div>
</div>
</div>
</div>
<div class="recipe__row">
<div class="recipe__ingredients">
<div class="recipe__box">
<h3 class="recipe__sub_title">Ingredients</h3>
<div v-for="(ingredient, index) in form.ingredients" class="recipe__form">
<input type="text" class="form__control" v-model="ingredient.name"
:class="[error[`ingredients.${index}.name`] ? 'error__bg' : '']">
<input type="text" class="form__control form__qty" v-model="ingredient.qty"
:class="[error[`ingredients.${index}.qty`] ? 'error__bg' : '']">
<button class="btn btn__danger" @click="remove('ingredients', index)">
×
</button>
</div>
<button class="btn" @click="addIngredient">Add Ingredient</button>
</div>
</div>
<div class="recipe__directions">
<div class="recipe__directions_inner">
<h3 class="recipe__sub_title">Directions</h3>
<div v-for="(direction, index) in form.directions" class="recipe__form">
<textarea type="text" class="form__control" v-model="direction.description"
:class="[error[`directions.${index}.description`] ? 'error__bg' : '']"></textarea>
<button class="btn btn__danger" @click="remove('directions', index)">
×
</button>
</div>
<button class="btn" @click="addDirection">Add Direction</button>
</div>
</div>
</div>
</div>
</template>
<script type="text/javascript">
import Vue from 'vue';
import Flash from '../../helpers/flash';
import { get, post } from '../../helpers/api';
import { toMulipartedForm } from '../../helpers/form';
import ImageUpload from '../../components/ImageUpload.vue';
export default{
data(){
return {
form: {
ingredients: [],
directions: []
},
error: {},
isProcessing: false,
initializeURL: `/api/recipes/create`,
storeURL: `/api/recipes`,
action: 'Create'
}
},
components:{
ImageUpload
},
methods: {
save(){
this.isProcessing = true;
const form = toMulipartedForm(this.form, this.$route.meta.mode);
post(this.storeURL, form)
.then((res) => {
if(res.data.saved){
Flash.setSuccess(res.data.message);
this.$router.push(`/recipes/${res.data.id}`);
}
}).catch((err) => {
if(err.response.status === 422){
this.error = err.response.data;
}
this.isProcessing = false;
})
},
addDirection(){
this.form.directions.push({description: ''});
},
addIngredient(){
this.form.ingredients.push({
name: '',
qty: ''
});
},
remove(type, index){
if(this.form[type].length > 1){
this.form[type].splice(index, 1);
}
}
},
created(){
if(this.$route.meta.mode === 'edit') {
this.initializeURL = `/api/recipes/${this.$route.params.id}/edit`;
this.storeURL = `/api/recipes/${this.$route.params.id}?_method=PUT`;
this.action = 'Update';
}
get(this.initializeURL).then((res) => {
Vue.set(this.$data, 'form', res.data.form);
}).catch((err) => {
console.log(err);
})
}
}
</script>
Show.vue
<template>
<div class="recipe__show">
<div class="recipe__row">
<div class="recipe__image">
<div class="recipe__box">
<img :src="`/images/${recipe.image}`" v-if="recipe.image" width="340px;">
</div>
</div>
<div class="recipe__details">
<div class="recipe__details_inner">
<small>Submitted by: {{recipe.user.name}}</small>
<h1 class="recipe__title">{{recipe.name}}</h1>
<p class="recipe__description">{{recipe.description}}</p>
<div v-if="auth.api_token && auth.user_id === recipe.user_id">
<router-link :to="`/recipes/${recipe.id}/edit`" class="btn btn-primary">
Edit
</router-link>
<button class="btn btn__danger" @click="remove" :disabled="isRemoving">Delete</button>
</div>
</div>
</div>
</div>
<div class="recipe__row">
<div class="recipe__ingredients">
<div class="recipe__box">
<h3 class="recipe__sub_title">Ingredients</h3>
<ul>
<li v-for="ingredient in recipe.ingredients">
<span>{{ingredient.name}}</span>
<span>{{ingredient.qty}}</span>
</li>
</ul>
</div>
</div>
<div class="recipe__directions">
<div class="recipe__directions_inner">
<h3 class="recipe__sub_title">Directions</h3>
<ul>
<li v-for="(direction, i) in recipe.directions">
<p>
<strong>{{i + 1}}</strong>
{{direction.description}}
</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script type="text/javascript">
import Auth from '../../store/auth';
import Flash from '../../helpers/flash';
import { get, del} from '../../helpers/api';
export default{
data(){
return {
auth: Auth.state,
isRemoving: false,
recipe: {
user: {},
ingredients: [],
directions: []
}
}
},
methods: {
remove(){
this.isRemoving = false;
del(`/api/recipes/${this.$route.params.id}`)
.then((res) =>{
if (res.data.deleted){
Flash.setSuccess('刪除操作成功煮剧!');
this.$router.push('/');
}
}).catch((err) => {
});
}
},
created(){
console.log(this.$route.params);
get(`/api/recipes/${this.$route.params.id}`)
.then((res) =>{
this.recipe = res.data.recipe;
}).catch((err) => {
})
}
}
</script>
在 components 文件夾下創(chuàng)建 ImagePreview.vue 和 ImageUpload.vue(路徑:/resources/assets/js/components/)
ImagePreview.vue
<template>
<div class="image__preview" v-if="image">
<img :src="image">
<button class="btn btn__danger image__close" @click="$emit('close')">×</button>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return {
image: null
}
},
props: {
preview: {
type: [String, File],
default: null
}
},
watch: {
'preview': 'setPreview'
},
methods: {
setPreview(){
if(this.preview instanceof File){
const fileReader = new FileReader;
fileReader.onload = (event) => {
this.image = event.target.result;
};
fileReader.readAsDataURL(this.preview);
}else if(typeof this.preview === 'string'){
this.image = `images/${this.preview}`;
}else {
this.image = null;
}
}
},
created(){
this.setPreview();
}
}
</script>
ImageUpload.vue
<template>
<div class="image">
<image-preview :preview="value" @close="$emit('input', null)" v-if="value"></image-preview>
<div class="image__upload" v-else>
<input type="file" accept="images/*" @change="upload">
</div>
</div>
</template>
<script type="text/javascript">
import ImagePreview from './ImagePreview.vue';
export default{
props: {
value: {
type: [String, File],
default: null
}
},
components: {
ImagePreview
},
methods: {
upload(e){
const files = e.target.files;
console.log(files);
if(files && files.length > 0){
this.$emit('input', files[0]);
}
}
}
}
</script>