美食杰项目 -- 发布菜谱(七)

简介: 美食杰项目 -- 发布菜谱(七)

前言:

本文给大家讲解,美食杰项目中 实现发布菜谱页的效果,和具体代码。


具体实现思路:

按照效果图实现静态页面布局

可以使用element-ui框架

实现上传图片功能

默认为3个可以增加,删除,最少为1个

点击提交,成功发布菜谱

步骤:

1. 展示美食杰发布菜谱页效果

image.png

美食杰发布菜谱


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>

总结:

以上就是 美食杰项目 中 发布菜谱页的具体实现方法,不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。

相关文章
|
16天前
|
数据采集 NoSQL 搜索推荐
五一假期畅游指南:Python技术构建的热门景点分析系统解读
五一假期畅游指南:Python技术构建的热门景点分析系统解读
|
12月前
使用 bookdown 构建新年日记本
使用 bookdown 构建新年日记本
77 0
美食杰项目 -- 登录注册(三)
美食杰项目 -- 登录注册(三)
美食杰项目 -- 登录注册(三)
|
JavaScript
美食杰项目 -- 菜品信息(五)
美食杰项目 -- 菜品信息(五)
美食杰项目 -- 菜品信息(五)
|
前端开发 JavaScript UED
「CSS畅想」何以解忧,美食足矣,用技术给好友开发了一个零食盲盒小游戏
前端技术从业者与非技术好友互动,用技术给好友开发了一个零食盲盒小游戏
199 1
|
数据采集 机器学习/深度学习 自然语言处理
瑞士小哥开源文本英雄Texthero:一行代码完成数据预处理,网友:早用早下班!
自然语言处理任务的数据通常是杂乱无章的,而文本预处理要消耗大量的时间和精力。近日,GitHub上开源了一个NLP工具箱Texthero,不仅功能完善一个pipeline完成所有操作,速度还超快堪比SpaCy,一起来尝鲜吧!
152 0
瑞士小哥开源文本英雄Texthero:一行代码完成数据预处理,网友:早用早下班!