前言:
本文给大家讲解,美食杰项目中 实现发布菜谱页的效果,和具体代码。
具体实现思路:
按照效果图实现静态页面布局
可以使用element-ui框架
实现上传图片功能
默认为3个可以增加,删除,最少为1个
点击提交,成功发布菜谱
步骤:
1. 展示美食杰发布菜谱页效果
美食杰发布菜谱
2. 引入element-ui
点击跳转至 element-ui 中 Upload 上传使用方法:https://element.eleme.cn/#/zh-CN/component/upload
点击跳转至 element-ui 中 input 输入框使用方法:https://element.eleme.cn/#/zh-CN/component/input
点击跳转至 element-ui 中 Select 选择器使用方法:https://element.eleme.cn/#/zh-CN/component/select
3. 代码
element-ui 中 Upload 上传 功能要单独封装一个组件,因为它还需要在编辑个人资料页面中使用
其他的在代码中写有注释,按注释理解即可,不了解的也可以在评论区里问我,或者私聊我询问
上传功能实现代码在编辑个人资料页中 点击跳转至编辑个人资料页
- 主页面
<template> <div class="box"> <p class="title">欢迎发布新菜谱,先介绍一下你的大作</p> <div class="top"> <div class="headline"> <p>标题</p> <input type="text" placeholder="请输入内容" v-model="backData.title" /> </div> <div class="property"> <p>属性</p> <el-select v-for="item in property" :key="item.parent_type" :placeholder="item.parent_name" v-model="backData.property[item.title]" > <el-option v-for="option in item.list" :key="option.type" :label="option.name" :value="option.type" ></el-option> </el-select> </div> <div class="classify"> <p>菜谱分类</p> <el-select v-model="backData.classify" placeholder="请选择"> <el-option-group v-for="item in classify" :key="item.parent_type" :label="item.parent_name" > <el-option v-for="option in item.list" :key="option.type" :label="option.name" :value="option.type" > </el-option> </el-option-group> </el-select> </div> <div class="articles"> <p>成品图(328*440)</p> <div> <upload-img action="/api/upload/?type=product" class="image" v-model="backData.product_pic_url" @res-url="(data) => (backData.product_pic_url = data.resImgUrl)" :imageUrl="backData.product_pic_url" ></upload-img> <el-input type="textarea" :rows="5" :cols="500" placeholder="请输入内容" class="textarea" v-model="backData.product_story" > </el-input> </div> </div> </div> <p class="title">记录所有原材料</p> <div class="center"> <div class="one"> <p>主料</p> <Material v-model="backData.raw_material.main_material" @remove="(item) => (backData.raw_material.main_material = item)" ></Material> </div> <div class="two"> <p>辅料</p> <Material v-model="backData.raw_material.accessories_material" @remove=" (item) => (backData.raw_material.accessories_material = item) " ></Material> </div> </div> <p class="title">开始写步骤了!能否简单易学就看你怎么写了,加油!</p> <div class="bottom"> <div v-for="(item, index) in backData.steps" :key="index"> <b>{{ index }}.</b> <upload-img v-model="item.img_url" :imageUrl="avatar" :imgMaxWidth="184" class="image" action="/api/upload/?type=step" @res-url=" (data) => ( (item.img_url = data.resImgUrl), (avatar = data.resImgUrl) ) " ></upload-img> <el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="item.describe" > </el-input> <i class="delete-icon el-icon-close" v-show="backData.steps.length !== 1" @click="remove(index, id)" ></i> </div> <el-button class="eaeaea" type="primary" size="medium" icon="el-icon-plus" @click="add" >增加一项</el-button > <p>烹饪小技巧</p> <el-input type="textarea" :rows="2" placeholder="请输入内容" :style="{ height: '150px' }" v-model="backData.skill" > </el-input> </div> <div class="btn"> <button @click="submit">搞定,提交审核</button> </div> </div> </template> <script> import { getProperty, getClassify, publish } from "@/connector/api"; import UploadImg from "@/views/uploadImg/upload_img.vue"; import Material from "@/views/PublishRecipes/material.vue"; // const backData = { // //向后端发生的数据 // title: "", // property: { // craft: 0, // 工艺 enum: [1,2,3,4], // flavor: 0, // 口味 enum: [1,2,3,4], // hard: 0, // 难度 enum: [1,2,3,4], // pepole: 0, // pepole 人数: [1,2,3,4], // }, // //分类 // classify: "", // //成品图 // product_pic_url: // "https://s1.c.meishij.net/n/images/upload_big_img.png?_=1561906961", // 成品图URL // product_story: "", // 成品图故事 // raw_material: { // // 料 // main_material: [{ name: "", specs: "" }], // 主料 // accessories_material: [{ name: "", specs: "" }], // 辅料 // }, // // steps: [{img_url: '',describe: '',}], // 步骤 // steps: Array(3) // .fill(1) // .map(() => ({ ...steps_struct, customeId: this.uuid() })), // skill: "", //心得 // }; const material = { name: "", specs: "", }; const steps_struct = { img_url: "", describe: "", }; export default { components: { UploadImg, Material, }, data() { return { // 向后端发送的数据 backData: { // 标题 title: "", property: { // craft: 0, // 工艺 enum: [1,2,3,4], // flavor: 0, // 口味 enum: [1,2,3,4], // hard: 0, // 难度 enum: [1,2,3,4], // pepole: 0, // pepole 人数: [1,2,3,4], }, classify: "", // 成品图 product_pic_url: "https://s1.c.meishij.net/n/images/upload_big_img.png?_=1561906961", product_story: "", raw_material: { // Array(3):数组长度为3,fill(1):数组的值为1,map:循环添加值 main_material: Array(3) .fill(1) .map(() => ({ ...material })), // 主料 accessories_material: Array(3) .fill(1) .map(() => ({ ...material })), // 辅料 }, steps: Array(3) .fill(1) .map(() => ({ ...steps_struct })), skill: "", }, property: [], classify: [], avatar: "https://s1.c.meishij.net/n/images/upload_step_img.png", }; }, mounted() { // 获取所有属性分类 getProperty().then(({ data }) => { // console.log(data); this.property = data; }); // 获取所有菜谱分类 getClassify().then(({ data }) => { // console.log(data); this.classify = data; }); }, methods: { // 点击删除 remove(index) { this.backData.steps.splice(index, 1); }, // 点击添加 add() { this.backData.steps.push({ img_url: "", describe: "", }); }, // 点击发布新的菜品 submit() { // console.log(this.backData); // 发布新菜品的请求头 publish(this.backData).then((data) => { // console.log(data); // 发布成功后跳转至首页 window.location.href = "/"; }); }, }, }; </script> <style lang="scss" scoped> .box { width: 990px; margin: 0 auto; .title { text-align: center; font-size: 22px; } .top { background-color: #fff; padding: 20px; div { p { font-size: 14px; } input { width: 400px; height: 50px; } } .articles { div { display: flex; } .textarea { width: 50%; } } } .center { background-color: #fff; padding: 20px; } .bottom { background-color: #fff; padding: 20px; div { display: flex; b { font-size: 50px; color: gainsboro; } .image { margin: 10px 20px; } } } .btn { text-align: center; margin: 20px 0; button { background-color: red; padding: 30px 40px; color: #fff; border: none; } } } </style>
input框页
<template> <div> <div class="raw-item" v-for="(item, index) in value" :key="index"> <el-input placeholder="请输入内容" style="width: 200px" v-model="item.name" ></el-input> <el-input placeholder="请输入内容" style="width: 100px" v-model="item.specs" ></el-input> <!-- 只要input不等于1,删除功能就一直显示 --> <i class="delete-icon el-icon-close" v-show="value.length !== 1" @click="remove(index, id)" ></i> </div> <el-button class="eaeaea" type="primary" size="medium" icon="el-icon-plus" @click="add" >增加一项</el-button > </div> </template> <script> export default { props: { // 接收数据v-model传递数据 value: { type: Array, default: () => [], }, }, methods: { // 点击删除 remove(index) { const newValue = this.value.filter((item, i) => { // console.log(index, item, i); return i !== index; }); // console.log(newValue); this.$emit("remove", newValue); }, add() { // 子传父触发数据 this.$emit("input", [...this.value, { name: "", specs: "" }]); }, }, }; </script> <style></style>
总结:
以上就是 美食杰项目 中 发布菜谱页的具体实现方法,不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。