从零开始,搭建一个简单的购物平台(十四)前端商城部分

本文涉及的产品
图片翻译,图片翻译 100张
语种识别,语种识别 100万字符
文本翻译,文本翻译 100万字符
简介: 从零开始,搭建一个简单的购物平台(十四)前端商城部分

从零开始,搭建一个简单的购物平台(十三)前端商城部分:

https://blog.csdn.net/time_____/article/details/108514710

项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping


本篇文章介绍实现部分组件和首页部分,首页组件如下,首页中的数据通过分批异步加载,也就是每个组件的数据单独请求,减少数据请求堵塞,下面介绍一下实现过程

image.png


pageTitle(页面标题)

首先要考虑到标题的返回功能,在methods里写个路由返回函数

methods: {
    goBack() {
      this.$router.go(-1);
    }
  }


接着通过组件属性传参数(标题内容,是否有返回按钮) ,通过props将组件属性放在当前data中


props: ["title", "isBack"],


标签中根据isBack决定是否有返回按钮,并显示title值


<template>
  <div id="top">
    <span v-if="isBack" class="back iconfont icon-fanhui" @click="goBack"></span>
    <span class="title">{{title}}</span>
  </div>
</template>


banner(主页轮播)

轮播图组件中的图片是单独请求的,所以用了model管理数据,bussiness进行请求,后面的组件有数据请求交互都是用这种写法

image.png

model.js内容,保存banner列表,vue实例,页面配置信息


export default class BannerModel {//banner数据存取
constructor() {
    this._bannerList = []
    this._pageConfig = {}
  }
  static getInstance() { //单例写法
    if (!BannerModel._instance) {
      Object.defineProperty(BannerModel, "_instance", {
        value: new BannerModel()
      })
    }
    return BannerModel._instance;
  }
  set vueComponent(val) {
    this._vueComponent = val
  }
  get vueComponent() {
    return this._vueComponent
  }
  set pageConfig(val) {
    this._pageConfig = val
    this._pageConfig.picType = 1
  }
  get pageConfig() {
    return this._pageConfig
  }
  set bannerList(val) {
    this._bannerList = val
    this._vueComponent.list = this.bannerList
  }
  get bannerList() {
    return this._bannerList
  }
}

bussiness.js 做请求和逻辑处理

import Vue from 'vue'
import config from "../../config/config"
import BannerModel from "./model";
import Clone from "../../utils/clone"
const {
  DefaultPageConfig,
  ServerApi
} = config
export default class BannerBussiness extends Vue {//业务处理
  constructor(_vueComponent) {
    super()
    BannerModel.getInstance().vueComponent = _vueComponent//取到显示层vue实例
    this.initPageConfig()
    this.getBanner()
  }
  initPageConfig() {//拷贝分页默认配置,并且不更改原常量
    BannerModel.getInstance().pageConfig = Clone.shallowClone(DefaultPageConfig)
  }
  getBanner() {//请求处理,this.$crypto.setCrypto加密
    this.$axios
      .get(ServerApi.shop.shopList, {
        params: {
          crypto: this.$crypto.setCrypto(BannerModel.getInstance().pageConfig)
        },
      }).then(res => {
        switch (res.result) {
          case 1:
            BannerModel.getInstance().bannerList = res.data.list
            break;
          default:
            break;
        }
      })
  }
}

banner.vue页面展示

<template>
  <div class="swiper">
    <mt-swipe :auto="3000">
      <mt-swipe-item v-for="(item,index) in list" :key="index">
        <img class="imgs" :src="imgPath+item.shopPic" @click="clickHandler(item)" />
      </mt-swipe-item>
    </mt-swipe>
  </div>
</template>
<script>
import { Swipe, SwipeItem } from "mint-ui";
import Config from "../../config/config";
import BannerBussiness from "./bussiness";
export default {
  name: "banner",
  data() {
    return {
      list: [],//图片列表
      imgPath: Config.RequestPath//图片根路径
    };
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      new BannerBussiness(this);//初始化banner请求
    },
    clickHandler(_shop) {//banner点击跳转
      this.$router.push({
        name: "ShopTheme",
        query: { _type: _shop.shopType, _shopName: _shop.shopName }
      });
    }
  }
};
</script>
<style lang="less" scoped>
@import "../../style/init.less";
.imgs {
  .h(500);
  width: 100%;
}
.swiper {
  width: 100%;
  .h(500);
}
</style>


tableBar(导航栏)

在iconfont下载相对应的图标字体资源,我这里直接下载在style目录下,用类名的方式显示,在tabbar文件夹新建model.js用于取数据(其实这个可以放到config)

export default class TableBarModel {
  static MenuList = [{
      name: "主页",
      path: "/Home",
      icon: "icon-shouye li iconfont"
    },
    {
      name: "分类",
      path: "/Kind",
      icon: "icon-fenlei li iconfont"
    },
    {
      name: "购物车",
      path: "/ShopCar",
      icon: "icon-daohang-gouwuche li iconfont"
    },
    {
      name: "我的",
      path: "/Info",
      icon: "icon-wode li iconfont"
    }
  ]
}

tabbar.vue ,通过列表

<template>
  <ul id="tab">
    <router-link
      v-for="(item, index) in menuList"
      :key="index"
      :to="item.path"
      tag="li"
      :class="item.icon"
      active-class="change"
      replace
    >
      <br />
      {{item.name}}
    </router-link>
  </ul>
</template>
<script>
import tableBarModel from "./model";
export default {
  name: "tabBar",
  data() {
    return {
      menuList: tableBarModel.MenuList
    };
  }
};
</script>
<style lang='less' scoped>
@import "../../style/init.less";
#tab {
  display: flex;
  box-shadow: -1px 0 8px #999;
  z-index: 100;
  justify-content: space-around;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  .h(130);
  .bcolor();
  .li {
    .h(130);
    box-sizing: border-box;
    padding-top: unit(10 / @pxtorem, rem);
    width: 25%;
    text-align: center;
    .fontColorOff();
  }
  .li::before {
    .f_s(58);
  }
  .li {
    .f_s(26);
  }
  .change {
    .fontColorOn();
  }
}
</style>


title(标题)

title用h2简单做了个样式修改

<template>
  <div>
    <h2>{{title}}</h2>
  </div>
</template>
<script>
export default {
  props: ["title"]
};
</script>
<style lang="less" scoped>
@import "../../style/init.less";
h2 {
  .h2Font();
}
</style>

shopItem(商品列表)

新建model.js存放可读写商品列表,vue组件实例和默认分页配置

export default class ItemModel {//存放可读写商品列表,vue组件实例和默认分页配置

constructor() {
    this._shopList = []//商品列表
    this._pageConfig = {}//默认分页配置
  }
  static getInstance() { //单例写法
    if (!ItemModel._instance) {
      Object.defineProperty(ItemModel, "_instance", {
        value: new ItemModel()
      })
    }
    return ItemModel._instance;
  }
  set vueComponent(val) {
    this._vueComponent = val
  }
  get vueComponent() {
    return this._vueComponent
  }
  set pageConfig(val) {
    this._pageConfig = val
    this._pageConfig.picType = 0//默认商品类型:单个商品
  }
  get pageConfig() {
    return this._pageConfig
  }
  set shopList(val) {
    this._shopList = val
    this._vueComponent.list = this._shopList//获取到商品列表后重新渲染
  }
  get shopList() {
    return this._shopList
  }
}


新建做业务处理的bussiness.js

import Vue from 'vue';
import config from "../../config/config";
import ItemModel from "./model";
import Clone from "../../utils/clone";
const {
  DefaultPageConfig,
  ServerApi
} = config
export default class ItemBussiness extends Vue {
  constructor(_vueComponent) {
    super()
    ItemModel.getInstance().vueComponent = _vueComponent//Vue组件实例
    this.initPageConfig(_vueComponent.shopType)
    this.getShopItem()
  }
  initPageConfig(_shopType) {//获取默认分页配置
    ItemModel.getInstance().pageConfig = Clone.shallowClone(DefaultPageConfig)
    ItemModel.getInstance().pageConfig.shopType = _shopType
  }
  getShopItem() {//获取商品列表
    this.$axios
      .get(ServerApi.shop.shopList, {
        params: {
          crypto: this.$crypto.setCrypto(ItemModel.getInstance().pageConfig)
        },
      }).then(res => {
        switch (res.result) {
          case 1:
            ItemModel.getInstance().shopList = res.data.list//渲染页面
            break;
          default:
            break;
        }
      })
  }
}

在shopItem.vue中进行列表渲染,并添加点击事件,跳转至商品详情页

<template>
  <ul class="more">
    <li v-for="(item,index) in list" :key="index" @click="clickHandler(item)">
      <img :src="imgPath+item.shopPic" alt :class="'imgs'+index" />
      <span>{{item.shopName}} {{item.shopScale}}克</span>
      <div>¥{{item.shopPrice}}</div>
    </li>
  </ul>
</template>
<script>
import ShopBussiness from "./bussiness";
import Config from "../../config/config";
export default {
  name: "shopItem",
  props: ["shopType"],
  data() {
    return {
      list: [],
      imgPath: Config.RequestPath
    };
  },
  mounted() {
    new ShopBussiness(this);
  },
  methods: {
    clickHandler(data) {
      this.$router.push({ name: "ShopInfo", query: { ...data } });
    }
  }
};
</script>
<style lang="less" scoped>
@import "../../style/init.less";
.more {
  li {
    .shopItem();
  }
}
</style>


最后的商品主题组件和商品列表相似,添加点击事件跳转至主题详情页


home页面

在page文件夹下新建home文件夹以及home.vue文件,将以上组件在home中引入并构成页面,效果如下

image.png

home.vue


<template>
  <div>
    <Top title="零食商贩"></Top>
    <div class="content">
      <Banner></Banner>
      <H2 title="精选主题"></H2>
      <Theme></Theme>
      <H2 title="最近新品"></H2>
      <ShopItem :shopType="shopType"></ShopItem>
    </div>
    <TabBar></TabBar>
  </div>
</template>
<script>
import TabBar from "../../components/tabBar/tabBar";
import Top from "../../components/top/top";
import Banner from "../../components/banner/banner";
import Theme from "../../components/theme/theme";
import ShopItem from "../../components/shopItem/shopItem";
import H2 from "../../components/h2/h2";
export default {
  name: "Home",
  data() {
    return {
      shopType: ""
    };
  },
  components: {
    Top,
    H2,
    Banner,
    Theme,
    ShopItem,
    TabBar
  }
};
</script>
<style lang="less" scoped>
@import "../../style/init.less";
</style>
相关文章
|
7月前
|
安全 JavaScript 前端开发
购物全返商城平台系统开发步骤流程/需求设计/教程指南/源码功能
开发购物全返商城平台系统涉及多个步骤和考虑因素。
|
5天前
|
小程序 安全 网络安全
清晰易懂!陪玩系统源码搭建的核心功能,陪玩小程序、陪玩app的搭建步骤!
陪玩系统源码包含多种约单方式、实时语音互动、直播间与聊天室、大神申请与抢单、动态互动与社交及在线支付与评价等核心功能。搭建步骤包括环境准备、源码上传与解压、数据库配置、域名与SSL证书绑定、伪静态配置及后台管理。注意事项涵盖源码安全性、二次开发、合规性和技术支持。确保平台安全、合规并提供良好用户体验是关键。
|
前端开发 JavaScript 数据库
从零开始,搭建一个简单的购物平台(十五)前端商城部分
从零开始,搭建一个简单的购物平台(十五)前端商城部分
224 1
从零开始,搭建一个简单的购物平台(十五)前端商城部分
|
前端开发
从零开始,搭建一个简单的购物平台(十六)前端商城部分
从零开始,搭建一个简单的购物平台(十六)前端商城部分
245 1
从零开始,搭建一个简单的购物平台(十六)前端商城部分
|
前端开发 数据库连接 数据库
从零开始,搭建一个简单的购物平台(二)
从零开始,搭建一个简单的购物平台(二)
195 1
从零开始,搭建一个简单的购物平台(二)
|
前端开发 测试技术 数据库
从零开始,搭建一个简单的购物平台(三)
从零开始,搭建一个简单的购物平台(三)
112 1
从零开始,搭建一个简单的购物平台(三)
|
前端开发 数据管理
从零开始,搭建一个简单的购物平台(五)
从零开始,搭建一个简单的购物平台(五)
321 1
从零开始,搭建一个简单的购物平台(五)
|
前端开发 JavaScript 数据安全/隐私保护
从零开始,搭建一个简单的购物平台(十七)前端商城部分
从零开始,搭建一个简单的购物平台(十七)前端商城部分
135 0
从零开始,搭建一个简单的购物平台(十七)前端商城部分
|
缓存 前端开发 JavaScript
从零开始,搭建一个简单的购物平台(十九)前端商城部分
从零开始,搭建一个简单的购物平台(十九)前端商城部分
291 0
从零开始,搭建一个简单的购物平台(十九)前端商城部分
|
前端开发 数据安全/隐私保护
从零开始,搭建一个简单的购物平台(十八)前端商城部分
从零开始,搭建一个简单的购物平台(十八)前端商城部分
200 0
从零开始,搭建一个简单的购物平台(十八)前端商城部分