美食杰项目 -- 首页(一)

前言:

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


具体实现思路:

  1. 向后端请求数据,获取数据,渲染数据
  2. 引入 element-ui
  3. 刷新后加载新图片

步骤:

头部代码中包含了一部分登录功能,这个功能在本文没有实现,想要知道的,可以看我发布的实现登录注册功能的文章。

在 加载图片页面代码中,使用了节流 throttle-debounce,节流的具体使用可以看官方文档。

点击跳转至节流的官方文档:https://www.npmjs.com/package/throttle-debounce

点击跳转至 element-ui 官方文档:https://element.eleme.cn/#/zh-CN/component/installation


1. 展示美食杰项目首页效果

实现后效果展示

美食杰首页


2. 引入 element-ui

  • 下载 element-ui
npm i element-ui -S
  • 在 main.js 中引入 element-ui
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

3. 头部代码

<template>
  <div class="box">
    <div class="top">
      <div class="center">
        <a href="" class="left">
          <img src="@/assets/logos.png" alt="" />
        </a>
        <!-- 判断是否登录,不登录则显示 -->
        <div class="right" v-if="!islogin">
          <router-link :to="{ name: 'login' }">登录</router-link>
          <router-link :to="{ name: 'login' }">注册</router-link>
        </div>
        <!-- 判断是否登录,登录则显示 -->
        <div class="right rights" v-if="islogin">
          <router-link :to="{ name: 'MyHomepage' }">
            <img :src="userInfo.avatar" alt="" />
          </router-link>
          <router-link :to="{ name: 'MyHomepage' }">{{
            userInfo.name
          }}</router-link>
          <router-link to="PublishRecipes">发布菜谱</router-link>
          <button @click="quit">退出</button>
        </div>
      </div>
    </div>
    <div class="bottom">
      <el-menu
        :default-active="activeIndex"
        class="el-menu-demo center"
        mode="horizontal"
      >
        <el-menu-item index="1" class="el-menu-item">
          <router-link :to="{ name: 'page' }">首页</router-link>
        </el-menu-item>
        <el-menu-item index="2">
          <router-link :to="{ name: 'recipes' }">菜谱大全</router-link>
        </el-menu-item>
      </el-menu>
    </div>
  </div>
</template>

<script>
import { mapGetters, mapState } from "vuex";
import { login_out } from "@/connector/api";
export default {
  data() {
    return {
      activeIndex: "1",
      activeIndex2: "1",
    };
  },
  computed: {
    // 获取 vuex 里的内容
    ...mapGetters(["islogin"]),
    ...mapState(["userInfo"]),
  },
  methods: {
    // 点击退出登录
    quit() {
      login_out().then((data) => {
        if (data.code === 0) {
          // 删除本地存储的 token
          localStorage.removeItem("token");
          // 跳转至首页
          window.location.href = "/";
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.box {
  width: 100%;
  .top {
    width: 100%;
    height: 129px;
    background-color: #c90000;
    .center {
      width: 990px;
      height: 100%;
      margin: 0 auto;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .left {
        width: 213.75px;
      }
      .right {
        width: 213.75px;
        a {
          font-size: 12px;
          text-decoration: none;
          color: #fff;
          margin-left: 5px;
        }
      }
      .rights {
        display: flex;
        align-items: center;
        a {
          img {
            width: 36px;
            height: 36px;
          }
        }
        button {
          font-size: 12px;
          color: #fff;
          margin-left: 5px;
          border: none;
          background-color: #c90000;
        }
      }
    }
  }
  .bottom {
    width: 100%;
    height: 60px;
    background-color: #ffffff;
    .center {
      width: 990px;
      height: 100%;
      margin: 0 auto;
      line-height: 60px;
      .el-menu-item {
        a {
          display: inline-block;
          width: 100%;
          height: 100%;
          text-decoration: none;
        }
      }
    }
  }
}
</style>

4. 首页内容总代码

<template>
  <div class="box">
    <!-- :banner="banner" 是父传子事件,和它类似的也是 -->
    <!-- @Scroll="Scroll" 是子传父事件 -->
    <!-- ref="Loading" 可以获取子组件的内容 -->
    <!-- Banner:轮播图,Roll:内容,Loading:加载图片 -->
    <Banner :banner="banner"></Banner>
    <Roll :menus="menus"></Roll>
    <Loading @Scroll="Scroll" ref="Loading"></Loading>
    <div class="bottom">Copyright © 2019 - 2019</div>
  </div>
</template>

<script>
import Banner from "./banner.vue";
import Roll from "./roll.vue";
import Loading from "./loading.vue";
import { getMenus, getBanner } from "@/connector/api";
export default {
  components: {
    Banner,
    Roll,
    Loading,
  },
  data() {
    return {
      // 轮播图
      banner: [],
      // 已发布菜品
      menus: [],
      // 页数
      pages: 1,
      // 总数
      total: "",
      // 一页显示多少个
      page_size: "",
    };
  },
  // 进入时触发
  mounted() {
    // 获取轮播图的内容
    getBanner().then(({ data }) => {
      //   console.log(data);
      // 赋值给 banner
      this.banner = data.list;
    });
    // 根据页数获取已发布菜品的内容
    getMenus({ page: this.pages }).then(({ data }) => {
      // console.log(data);
      // 内容
      this.menus = data.list;
      // 总数
      this.total = data.total;
      // 一页几条
      this.page_size = data.page_size;
    });
  },
  // 点击时触发
  methods: {
    Scroll() {
      // 页数 + 1
      this.pages++;
      // 判断当前页数是否等于最后的页数
      if (this.pages == Math.ceil(this.total / this.page_size)) {
        // 等于则关闭 加载图片
        this.$refs.Loading.loading = false;
        // 下面的代码不在执行
        return;
      }
      // 显示 加载图片
      this.$refs.Loading.loading = true;
      // 根据页数获取已发布菜品的内容
      getMenus({ page: this.pages }).then(({ data }) => {
        // console.log(loading);
        // 追加到 menus 里面
        this.menus.push(...data.list);
        // 关闭 加载图片
        this.$refs.Loading.loading = false;
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.box {
  width: 990px;
  margin: 20px auto 0;
  .bottom {
    text-align: center;
    margin-top: 20px;
  }
}
</style>

5. 轮播图代码

点击跳转至 element-ui 中轮播图使用方法:https://element.eleme.cn/#/zh-CN/component/carousel

<template>
  <div class="box">
    <!-- element-ui 里的轮播图 -->
    <el-carousel :interval="4000" type="card" height="300px">
      <el-carousel-item v-for="item in banner" :key="item._id">
        <router-link
          :to="{ name: 'DishesInformation', query: { menuId: item.menuId } }"
        >
          <img :src="item.product_pic_url" alt="" />
        </router-link>
      </el-carousel-item>
    </el-carousel>
  </div>
</template>

<script>
export default {
  // props 接收父组件传递过来的值
  props: {
    banner: {
      // type 元素类型
      type: Array,
      // default 默认值
      default: () => [],
    },
  },
};
</script>

<style>
.el-carousel__item a img {
  color: #475669;
  font-size: 14px;
  opacity: 0.75;
  line-height: 300px;
  margin: 0;
  width: 100%;
  height: 300px;
}

.el-carousel__item:nth-child(2n) {
  background-color: #99a9bf;
}

.el-carousel__item:nth-child(2n + 1) {
  background-color: #d3dce6;
}
</style>

6. 已发布菜品内容代码

<template>
  <div class="box">
    <!-- :class="{ h2: id === 234 }" 判断 id 是否为 234 不是的话使用前面的 class 标签 -->
    <h2 :class="{ h2: id !== 234 }">内容精选</h2>
    <ul class="banner">
      <li
        v-for="item in menus"
        :key="item._id"
        ref="list"
        :class="{ 'banner-li': id === 170 }"
      >
        <!-- 和上文大致意思相同 -->
        <router-link
          :to="{ name: 'DishesInformation', query: { menuId: item.menuId } }"
        >
          <img :src="item.product_pic_url" alt="" />
        </router-link>
        <div>
          <router-link
            :to="{ name: 'DishesInformation', query: { menuId: item.menuId } }"
          >
            <b>{{ item.title }}</b>
          </router-link>
          <p>{{ item.comments_len }} 评论</p>
          <router-link
            :to="{ name: 'MyHomepage', query: { userId: item.userId } }"
          >
            <p>{{ item.name }}</p>
          </router-link>
        </div>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  // props 接收父组件传递过来的值
  // type 元素类型
  // default 默认值
  props: {
    menus: {
      type: Array,
      default: () => [],
    },
    // 因为要在好几个地方使用所以传递过来一个值,用来判断在哪里使用
    id: {
      type: Number,
      default: 234,
    },
  },
};
</script>

<style lang="scss" scoped>
.box {
  width: 990px;
  padding: 0;
  h2 {
    text-align: center;
    font-weight: 400;
    padding: 20px 0;
  }
  .banner {
    display: flex;
    flex-wrap: wrap;
    padding: 0;
    width: 100%;
    li {
      display: inline-block;
      width: 234px;
      // width: 23.4%;
      height: 338px;
      list-style: none;
      background-color: #fff;
      margin: 0 0 20px 13px;
      border: 1px solid #ebeef5;
      a {
        text-decoration: none;
        img {
          width: 99.8%;
          height: 63%;
        }
        b {
          height: 24px;
          line-height: 24px;
          font-size: 12px;
          color: #333;
        }
        p {
          width: 95%;
          margin: 0 auto;
          font-size: 12px;
          height: 23px;
          line-height: 23px;
          color: #ff3232 !important;
        }
      }
      div {
        padding: 20px;
      }

      p {
        width: 204px;
        margin: 0 auto;
        font-size: 12px;
        height: 26px;
        line-height: 26px;
        color: #999;
      }
    }
    .banner-li {
      width: 160px !important;
      height: 264px;
    }
  }
  .h2 {
    display: none;
    padding: none;
  }
}
</style>

7. 加载图片页面代码

点击跳转至 element-ui 中加载使用方法:https://element.eleme.cn/#/zh-CN/component/loading

<template>
  <div class="box">
    <!-- element-ui 中加载的图片 -->
    <i
      v-loading="loading"
      element-loading-spinner="el-icon-loading"
      ref="loadings"
    >
    </i>
  </div>
</template>

<script>
// 引入节流
import { throttle } from "throttle-debounce";
export default {
  data() {
    return {
      // 是否显示
      loading: false,
    };
  },
  // 进入当前页面时触发
  mounted() {
    // 使用节流
    this.handleScroll = throttle(300, this.handleScroll.bind(this));
    // 给当前页面全局绑定 滚动条 事件
    window.addEventListener("scroll", this.handleScroll);
  },
  // 离开当前页面时触发
  destroyed() {
    // 删除 滚动条 事件
    window.removeEventListener("scroll", this.handleScroll);
  },
  methods: {
    handleScroll() {
      // 为 true 则停止向下执行
      if (this.loading) return;
      // 判断 加载图片距离顶部的高 是否小于 可视窗口
      if (
        this.$refs.loadings.getBoundingClientRect().bottom <
        document.documentElement.clientHeight
      ) {
        // console.log("滚动到指定位置");
        // 小于则显示 加载图片
        this.loading = true;
        // 子传父事件
        this.$emit("Scroll");
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.box {
  text-align: center;
  height: 20px;
}
</style>

总结:

总结:
以上就是 美食杰项目 中 首页的具体实现方法,不懂得也可以在评论区里问我,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风 与我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值