Newbee移动商城开发日志之HOME页面

403 阅读3分钟

Newbee移动商城

前言

Newbee是一个有另一个博主@我是十三 的开源项目,其中对移动端的优化和一些规范非常值得我们学习,下面的一些就是我自己个人对Newbee项目前后端分离部分的前端做的一些个人分析和见解,有不对的请大家指出来。

HOME界面知识点解析

轮播图 token 状态管理

HTML 讲解

我们先看划分的

<div>
    <!-- 头部栏 -->
    <header class="home-header wrap" :class="{ active: headerScroll }">
      <!-- 左边 -->
      <router-link tag="i" to="./category"
        ><i class="nbicon nbmenu2"></i
      ></router-link>
      <!-- 中间 -->
      <div class="header-search">
        <span class="app-name">新蜂商城</span>
        <i class="iconfont icon-search"></i>
        <router-link
          tag="span"
          class="search-title"
          to="./product-list?from=home"
          >山河无恙,人间皆安</router-link
        >
      </div>
      <!-- 右边 -->
      <router-link class="login" tag="span" to="./login" v-if="!isLogin"
        >登录</router-link
      >
      <router-link class="login" tag="span" to="./user" v-else>
        <van-icon name="manager-o" />
      </router-link>
    </header>

    <!-- 导航栏fixed -->
    <nav-bar></nav-bar>

    <!-- 轮播图 -->
    <swiper :list="swiperList"></swiper>
    <!-- 分类展示 -->
    <div class="category-list">
      <div v-for="item in categoryList" v-bind:key="item.categoryId">
        <img :src="item.imgUrl" />
        <span>{{ item.name }}</span>
      </div>
    </div>
    <!-- 商品展示 -->
    <div class="good">
      <header class="good-header">新品上线</header>
      <div class="good-box">
        <div
          class="good-item"
          v-for="item in newGoodses"
          :key="item.goodsId"
          @click="goToDetail(item)"
        >
          <img :src="prefix(item.goodsCoverImg)" alt="" />
          <div class="good-desc">
            <div class="title">{{ item.goodsName }}</div>
            <div class="price">¥ {{ item.sellingPrice }}</div>
          </div>
        </div>
      </div>
    </div>
    <div class="good">
      <header class="good-header">热门商品</header>
      <div class="good-box">
        <div
          class="good-item"
          v-for="item in hots"
          :key="item.goodsId"
          @click="goToDetail(item)"
        >
          <img :src="prefix(item.goodsCoverImg)" alt="" />
          <div class="good-desc">
            <div class="title">{{ item.goodsName }}</div>
            <div class="price">¥ {{ item.sellingPrice }}</div>
          </div>
        </div>
      </div>
    </div>
    <div class="good" :style="{ paddingBottom: '100px' }">
      <header class="good-header">最新推荐</header>
      <div class="good-box">
        <div
          class="good-item"
          v-for="item in recommends"
          :key="item.goodsId"
          @click="goToDetail(item)"
        >
          <img :src="prefix(item.goodsCoverImg)" alt="" />
          <div class="good-desc">
            <div class="title">{{ item.goodsName }}</div>
            <div class="price">¥ {{ item.sellingPrice }}</div>
          </div>
        </div>
      </div>
    </div>
  </div>

newbee-mall的结构很清晰从上至下的模块化,比较适合新人去学习,

1. 头部模块:=>header
      三个route-link组成各自跳转到功能路由,用户登录状态根据isLogin状态显示,没什么多说的
      css略
2. 导航栏:=>navBar
      这里建议分离做父子路由嵌套,这样的好处可以减少组件复用,如果对理解比较困难可以向项目中做的
      直接复用就可以
      解决防范
      APP.vue =><router-view> </router-view>
      layout.vue=> <templet>
                      <router-view>动态可选择窗口</router-view> 
                      <nav-bar> 导航栏</nav-bar>
                   </templet>
      layout布局组件其实是很大的约束了我们的布局规范
3. 轮播图:=>swiper 
      vant ui 略
4. goodsList=>goods
      各种的goods进行展示,
      一般不超过10条加载,
      css:flex布局进行约束
      img: prefix可以做为baseURL使用,个人建议使用vuex状态管理工具去请求使用,这样增加了baseUrl的灵活性
      
     

JavaScript区块

import navBar from "@/components/NavBar";
import swiper from "@/components/Swiper";
import { getHome } from "../service/home";
import { getUserInfo } from "../service/user";
import { getLocal } from "@/common/js/utils";
import { Toast } from "vant";
export default {
  name: "home",
  data() {
    return {
      swiperList: [], //轮播图数据
      isLogin: false, //是否登录
      headerScroll: false, //头部是否滚动
      hots: [], //热门商品list
      newGoodses: [], //新商品的list
      recommends: [], //最新推荐
      categoryList: [
        {
          name: "新蜂超市",
          imgUrl: "//s.weituibao.com/1583585285461/cs.png",
          categoryId: 100001
        },
        {
          name: "新蜂服饰",
          imgUrl: "//s.weituibao.com/1583585285468/fs.png",
          categoryId: 100003
        },
        {
          name: "全球购",
          imgUrl: "//s.weituibao.com/1583585285470/qq.png",
          categoryId: 100002
        },
        {
          name: "新蜂生鲜",
          imgUrl: "//s.weituibao.com/1583585285472/sx.png",
          categoryId: 100004
        },
        {
          name: "新蜂到家",
          imgUrl: "//s.weituibao.com/1583585285467/dj.png",
          categoryId: 100005
        },
        {
          name: "充值缴费",
          imgUrl: "//s.weituibao.com/1583585285465/cz.png",
          categoryId: 100006
        },
        {
          name: "9.9元拼",
          imgUrl: "//s.weituibao.com/1583585285469/pt.png",
          categoryId: 100007
        },
        {
          name: "领劵",
          imgUrl: "//s.weituibao.com/1583585285468/juan.png",
          categoryId: 100008
        },
        {
          name: "省钱",
          imgUrl: "//s.weituibao.com/1583585285471/sq.png",
          categoryId: 100009
        },
        {
          name: "全部",
          imgUrl: "//s.weituibao.com/1583585285470/qb.png",
          categoryId: 100010
        }
      ]
    };
  },
  components: {
    navBar,
    swiper
  },
  //挂载钩子函数
  async mounted() {
    //获取token
    const token = getLocal("token");
    //如果有token显示登录状态
    if (token) {
      this.isLogin = true;
    }
    //挂载全局事件流
    window.addEventListener("scroll", this.pageScroll);
    //开启转圈圈加载icon
    Toast.loading({
      message: "加载中...",
      forbidClick: true
    });
    //建议抽离别写在一起 首页数据
    const { data } = await getHome();
    this.swiperList = data.carousels;
    this.newGoodses = data.newGoodses;
    this.hots = data.hotGoodses;
    this.recommends = data.recommendGoodses;
    Toast.clear();
  },
  methods: {
    //滑动监听 加入到事件流中
    pageScroll() {
      let scrollTop =
        window.pageYOffset ||
        document.documentElement.scrollTop ||
        document.body.scrollTop;
      scrollTop > 100
        ? (this.headerScroll = true)
        : (this.headerScroll = false);
    },
    //跳转详情
    goToDetail(item) {
      this.$router.push({ path: `product/${item.goodsId}` });
    }
  }
};
  1. 数据请求:这里直接用了异步请求挂载到了周期函数里,个人建议不要这么做,getList方法请在方法区(methods)定义
  2. token验证:个人建议vuex控制用户状态view页面只需要判断状态,这样做到状态业务逻辑模块和用户模块的耦合
  3. 路由跳转:没有什么多说的
  4. 全局滑动监听:建议多写一个销毁生命周期方法,进行监听的提出,不要使用匿名函数

CSS部分:

less预编译器的函数处理以及flex布局引用,请移步less官网和阮一峰老师的flex引用

转载和鸣谢

鸣谢新蜂商城对开源社区做的贡献,站在巨人肩膀上才能看的更远,@我是十三 大大
以下是开源项目github地址:

newbee-mall 在 GitHub 和国内的码云都创建了代码仓库,如果有人访问 GitHub 比较慢的话,建议在 Gitee 上查看该项目,两个仓库会保持同步更新。