十七、网上商城项目(2)

本章概要

  • 菜单组件
  • 图书分类组件
  • 广告图片轮播组件
  • 热门推荐组件
  • 新书上市组件
  • 首页组件

17.3.2 菜单组件

菜单是单独定义的一个组件,本项目的菜单只有一级,如果需要定义多级菜单,可参照 《5.3.1》小节的实现。在 components 目录下新建 Menus.vue 。如下:

Menus.vue




这个组件比较简单,都是静态代码。由于本项目只是用于演示基于 Vue 前端开发涉及的各个功能的实现,所以暂时只提供了首页和新书菜单的实现,其它 3 个(特价书、教材、视听教程)功能的实现是类似的,只需要服务端提供相应的接口即可。
首页和新书菜单组件渲染的位置(即 router-view)在 App.vue 中指定。App.vue 的代码如下:

App.vue





本项目没有用到嵌套路由,所有页面级路由组件的渲染都是在这里。换句话说,即所有渲染的页面都有头部和菜单。

17.3.3 图书分类组件

图书分类组件用于显示商品的分类,每个分类都是一个链接,单击链接将跳转到展示该分类下所有商品的页面。
在 components 目录下新建 HomeCategory.vue。如下:

HomeCategory.vue




在 created 生命周期钩子中向服务端请求所有分类数据。服务端提供的该数据的内容如下:
http://111.229.37.167/api/category

[{
	"id": 1,
	"name": "Java EE",
	"root": true,
	"parentId": null,
	"children": [{
		"id": 3,
		"name": "Servlet/JSP",
		"root": false,
		"parentId": 1,
		"children": []
	}, {
		"id": 4,
		"name": "应用服务器",
		"root": false,
		"parentId": 1,
		"children": []
	}, {
		"id": 5,
		"name": "MVC框架",
		"root": false,
		"parentId": 1,
		"children": []
	}]
}, {
	"id": 2,
	"name": "程序设计",
	"root": true,
	"parentId": null,
	"children": [{
		"id": 6,
		"name": "C/C++",
		"root": false,
		"parentId": 2,
		"children": [{
			"id": 9,
			"name": "C11",
			"root": false,
			"parentId": 6,
			"children": []
		}]
	}, {
		"id": 7,
		"name": "Java",
		"root": false,
		"parentId": 2,
		"children": []
	}, {
		"id": 8,
		"name": "C#",
		"root": false,
		"parentId": 2,
		"children": []
	}]
}]

子分类是放到 children 数组属性中的,本项目中未用到 root 和 parentId 属性,前者可用于列出某个根分类下的所有商品,后者可以用于查找某个分类的父分类,甚至反向查找所有上级分类。
清楚了数据接口返回的数据结构,那么 HomeCategory 组件的代码也就清楚了。

17.3.4 广告图片轮播组件

广告图片轮播功能在电商网站属于标配的功能,其实是通过 JavaScript 代码控制图片的轮播,并处理一些控制图片显示的单击事件。
由于 Vue 3.0 推出的时间还不是特别长,之前 Vue 2.x 下的很多好用的图片轮播插件还没有移植到 Vue 3.0 下,如果自己编写一个成熟的图片轮播组件,又会增加本项目的复杂度,因此这里暂时先用一张静止的图片代替图片轮播。如果对图片轮播功能的实现有兴趣,可以在网上找到很多案例,将其封装为组件使用即可。(不过,此时网上应该已经有支持 Vue 3.0 的图片轮播插件了)。

在 components 目录下新建 HomeScrollPic.vue 。如下:

HomeScrollPic.vue




图片是保存在 public 目录下的,该目录下的资源直接通过根路径“/”引用即可。

17.3.5 热门推荐组件

热门推荐组件用于显示热门商品,用户如果对某一热门商品感兴趣,可以单击该商品链接,进入商品详情页面。
在 components 目录下新建 HomeBooksHot.vue 。如下:

HomeBooksHot.vue




在 created 声明周期钩子中向服务端请求热门商品数据。服务端提供的该数据接口如下:
http://111.229.37.167/api/book/hot
返回的数据结构如下:

[
    {
        "id":1,
        "title":" VC++深入详解(第3版)",
        "author":"孙鑫",
        "price":168,
        "discount":0.95,
        "bookConcern":null,
        "imgUrl":"/api/img/vc++.jpg",
        "bigImgUrl":"/api/img/vc++big.jpg",
        "publishDate":null,
        "brief":null,
        "inventory":1000
    },
    {
        "id":2,
        "title":"Java编程思想",
        "author":"Bruce Eckel",
        "price":108,
        "discount":0.5,
        "bookConcern":null,
        "imgUrl":"/api/img/javathink.jpg",
        "bigImgUrl":"/api/img/javathinkbig.jpg",
        "publishDate":null,
        "brief":null,
        "inventory":500
    },
    {
        "id":3,
        "title":"C Primer Plus 第6版",
        "author":"Stephen Prata",
        "price":89,
        "discount":0.5,
        "bookConcern":null,
        "imgUrl":"/api/img/c++primer.jpg",
        "bigImgUrl":"/api/img/c++primerbig.jpg",
        "publishDate":null,
        "brief":null,
        "inventory":400
    },
    {
        "id":4,
        "title":"Servlet/JSP深入详解",
        "author":"孙鑫",
        "price":139,
        "discount":0.9,
        "bookConcern":null,
        "imgUrl":"/api/img/jsp.jpg",
        "bigImgUrl":"/api/img/jspbig.jpg",
        "publishDate":null,
        "brief":null,
        "inventory":1000
    }
]

实际上,热门推荐组件用不到全部信息,只是服务端的数据接口返回的数据就是如此,那么从这些数据中选择游泳的数据使用即可。

一般电商网站的商品有定价和实际销售价格,在前端展示商品的时候需要同时显示这两种价格。从这里返回的数据来看,服务端只提供了商品的定价和折扣,并没有实际销售价格,那么实际销售价格就需要我们自己来处理。这在实际开发中也很常见,不能期望服务端的开发人员专门为你(当然老板除外)的需求提供一个接口,也许还有其他前端也要用到该接口。

实际价格是定价与折扣相乘得到的,由于实际价格在多处要用到,因此编写一个单独的函数来计算价格。此外,还要考虑价格显示问题,价格只是显示到分就可以了,而在计算过程中,由于是浮点数,可能会出现小数点后两位之后的数据,所以要进行处理。除此之外,价格一般还会加上货币符号,如国内会加上人民币符号¥。为此,再编写一个函数,专门负责价格的格式化问题。

将这两个函数放到单独的 JS 文件中,在 src 目录下新建 utils 文件夹,在该文件夹下新建 util.js。如下:

util.js

const digitsRE = /(\d{3})(?=\d)/g

export function factPrice(value, discount) {
    value = parseFloat(discount);
    if (!discount) {
        return value
    }
    return value * discount;
}

export function currency(value, currency, decimals) {
    value = parseFloat(value);
    if (!isFinite(value) || (!value && value !== 0)) {
        return ''
    }
    currency = currency != null ? currency : '¥';
    decimals = decimals != null ? decimals : 2;
    var stringified = Math.abs(value).toFixed(decimals);
    var _int = decimals ? stringified.slice(0, -1 - decimals) : stringified;
    var i = _int.length % 3;
    var head = i > 0 ? (_int.slice(0, i) + (_int.length > 3 ? ',' : '')) : '';
    var _float = decimals ? stringified.slice(-1 - decimals) : '';
    var sign = value < 0 ? '-' : '';
    return sign + currency + head + _int.slice(i).replace(digitsRE, '$1,') + _float
}

为了方便在各个组件内使用这两个函数,在 App 组件内通过 provide 选项向所有后代组件提供这两个函数。编辑 App.vue ,修改后的代码如下:

App.vue

<template>
  <div id="app">
    <Header />
    <Menus />
    <router-view />
  </div>
</template>

<script>
import Header from '@/components/Header.vue'
import Menus from '@/components/Menus.vue';
import { factPrice,currency } from './utils/util';

export default {
  components: {
    Header,
    Menus
  },
  provide(){
    return {
      factPrice,
      currency
    }
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  width: 1200px;
}
</style>

之后记得在组件内使用 inject 选项注入这两个函数,如下:

inject:['factPrice','currency']

17.3.6 新书上市组件

新书上市组件用于显示刚上市的商品,用户如果对某一商品感兴趣,可以单击该商品链接,进入商品详情页面。
在 components 目录下新建 BooksNew.vue,由于该组件会被复用,所以这里没有使用主页的前缀 Home。

BooksNew.vue





在 created 生命周期钩子中向服务端请求新书的数据。服务端提供的该数据接口如下:
http://111.229.37.167/api/book/new
返回的数据形式同 /book/hot。

17.3.7 首页组件

首页的各个组成部分编写完成后,就可以开始集成这几个部分了。首页作为页面级组件,放到 views 目录下。在 views 目录下新建 Home.vue 。如下:

src/views/Home.vue






Home 组件比较简单,只是用于拼接各个子组件

其它,后面启动的时候可能会出现以下命名规则错误

在这里插入图片描述

修改 .eslintrc.js,如下:

//在rules中添加自定义规则
//关闭组件命名规则
"vue/multi-word-component-names": "off",

十七、网上商城项目(2)_第1张图片

你可能感兴趣的:(Vue.js,3.0,从入门到实战,菜单组件,图书分类组件,热门推荐组件,新书上市组件,首页组件)