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

本文详细介绍了基于Vue的前端开发中,包括菜单、图书分类、广告图片轮播、热门推荐和新书上市等组件的实现。每个组件都结合了Vue的模板、脚本和样式,以及与后台服务端接口的交互,展示了如何在不同场景下构建和使用组件。
摘要由CSDN通过智能技术生成

本章概要

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

17.3.2 菜单组件

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

Menus.vue

<template>
    <div class="menus">
        <ul>
            <li>
                <router-link to="/home">首页</router-link>
            </li>
            <li>
                <router-link to="/newBooks">新书</router-link>
            </li>
            <li>
                <a href="javascript:;">特价书</a>
            </li>
            <li>
                <a href="javascript:;">教材</a>
            </li>
            <li>
                <a href="javascript:;">视听教程</a>
            </li>
        </ul>
    </div>
</template>
<script>
export default {
    name: 'Menus'
}
</script>
<style scoped>
.menus {
    position: relative;
    width: 100%;
}

a {
    text-decoration: none;
    display: block;
    color: #fff;
    height: 40px;
    line-height: 40px;
    border: solid 1px #fff;
    border-width: 1px 1px 0 0;
    background: #255f9e;
}

li {
    width: 20%;
    list-style-type: none;
    float: left;
    text-align: center;
    position: relative;
}

li a:hover {
    color: #fff;
    background: #ffb100;
}
</style>

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

export default {
  components: {
    Header,
    Menus
  }
}
</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>

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

17.3.3 图书分类组件

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

HomeCategory.vue

<template>
    <div class="category">
        <h3>图书分类</h3>
        <div v-for="category in categorys" :key="category.id">
            <h5>{{ category.name }}</h5>
            <router-link v-for="child in category.children" :key="child.id" :to="'/category' + child.id">{{ child.name
                }}</router-link>
        </div>
    </div>
</template>
<script>
export default {
    name: 'HomeCategory',
    data() {
        return {
            categories: []
        }
    },
    created() {
        this.axios.get('/category').then(res => {
            if(res.status == 200){
                this.categories = res.data;
            }
        }).catch(err => {
            console.log(err)
        })
    }
}
</script>
<style scoped>
.scrollPic {
    width: 610px;
    height: 220px;
    float: left;
    margin: 10px 50px auto 50px;
}

.scrollPic img {
    width: 610px;
    height: 220px;
}
</style>

在 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

<template>
    <div class="scrollpic">
        <img src="/p1.jpg" style="width: 610px; height: 220px;" />
    </div>
</template>
<script>
export default {};
</script>
<style scoped>
.scrollPic {
    width: 610px;
    height: 220px;
    float: left;
    margin: 10px 50px auto 50px;
}

.scrollPic img {
    width: 610px;
    height: 220px;
}
</style>

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

17.3.5 热门推荐组件

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

HomeBooksHot.vue

<template>
    <div class="bookRecommend">
        <h3>热门推荐</h3>
        <ul>
            <li v-for="book in books" :key="book.id">
                <router-link :to="'/book/' + book.id">
                    {{ book.title }}
                    <span>{{ currency(factPrice(book.price, book.discount))}}</span>
                </router-link>
            </li>
        </ul>
    </div>
</template>
<script>
export default {
    name: 'HomeBooksHot',
    data() {
        return {
            books: []
        }
    },
    inject: ['factPrice', 'currency'],
    created() {
        this.axios.get('/book/hot').then(res => {
            if (res.status == 200) {
                this.books = res.data
            }
        }).catch(err => {
            console.log(err)
        })
    }
}
</script>
<style scoped>
.bookRecommend {
    width: 18%;
    height: 220px;
    border: solid 1px #ccc;
    float: left;
    margin-top: 10px;
}

.bookRecommend li {
    list-style: none;
    text-align: left;
    padding-left: 0;
    margin-left: -20px;
}
</style>

在 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

<template>
    <div class="booksNew">
        <h3>新书上市</h3>
        <div class="book" v-for="book in books" :key="book.id">
            <figure>
                <router-link :to="'/book/' + book.id">
                    <img :src="book.imgUrl">
                    <figcaption>{{ book.title }}</figcaption>
                </router-link>
            </figure>
            <p>
                {{ currency(factPrice(book.price, book.discount)) }}
                <span>{{ currency(book.price) }}</span>
            </p>
        </div>
    </div>
</template>

<script>
export default {
    name: '',
    props: [''],
    data() {
        return {
            books: []
        }
    },
    inject: ['factPrice', 'currency'],
    created() {
        this.axios.get("/book/new").then(res => {
            if (res.status == 200) {
                this.loading = false;
                this.books = res.data;
            }
        }).catch(err => {
            console.log(err)
        })
    }
}
</script>
<style scoped>
.booksNew {
    float: left;
}

.booksNew .book {
    display: inline-block;
    width: 19%;
    border-right: solid 1px #ccc;
    margin-left: 10px;
}

.booksNew a:hover {
    color: red;
}

.booksNew img {
    width: 120px;
    height: 100px
}

.booksNew span {
    color: #cdcdcd;
    text-decoration: line-through;
}
</style>

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

17.3.7 首页组件

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

src/views/Home.vue

<template>
    <div class="home">
        <HomeCategory />
        <HomeScrollPic />
        <HomeBooksHot />
        <BooksNew />
    </div>
</template>

<script>
import HomeCategory from '@/components/HomeCategory.vue'
import HomeScrollPic from '@/components/HomeScrollPic.vue';
import HomeBooksHot from '@/components/HomeBooksHot.vue';
import BooksNew from '@/components/BooksNew.vue';

export default {
    name: 'home',
    components: {
        HomeCategory,
        HomeScrollPic,
        HomeBooksHot,
        BooksNew
    }
}
</script>

<style scoped>
.home {
    float: left;
    text-align: center;
    width: 100%;
}

[v-cloak] {
    display: none;
}
</style>

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

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

在这里插入图片描述

修改 .eslintrc.js,如下:

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

在这里插入图片描述

数据治理是确保数据准确性、可靠性、安全性、可用性和完整性的体系和框架。它定义了组织内部如何使用、存储、保护和共享数据的规则和流程。数据治理的重要性随着数字化转型的加速而日益凸显,它能够提高决策效率、增强业务竞争力、降低风险,并促进业务创新。有效的数据治理体系可以确保数据在采集、存储、处理、共享和保护等环节的合规性和有效性。 数据质量管理是数据治理中的关键环节,它涉及数据质量评估、数据清洗、标准化和监控。高质量的数据能够提升业务决策的准确性,优化业务流程,并挖掘潜在的商业价值。随着大数据和人工智能技术的发展,数据质量管理在确保数据准确性和可靠性方面的作用愈发重要。企业需要建立完善的数据质量管理和校验机制,并通过数据清洗和标准化提高数据质量。 数据安全与隐私保护是数据治理中的另一个重要领域。随着数据量的快速增长和互联网技术的迅速发展,数据安全与隐私保护面临前所未有的挑战。企业需要加强数据安全与隐私保护的法律法规和技术手段,采用数据加密、脱敏和备份恢复等技术手段,以及加强培训和教育,提高安全意识和技能水平。 数据流程管理与监控是确保数据质量、提高数据利用率、保护数据安全的重要环节。有效的数据流程管理可以确保数据流程的合规性和高效性,而实时监控则有助于及时发现并解决潜在问题。企业需要设计合理的数据流程架构,制定详细的数据管理流程规范,并运用数据审计和可视化技术手段进行监控。 数据资产管理是将数据视为组织的重要资产,通过有效的管理和利用,为组织带来经济价值。数据资产管理涵盖数据的整个生命周期,包括数据的创建、存储、处理、共享、使用和保护。它面临的挑战包括数据量的快速增长、数据类型的多样化和数据更新的迅速性。组织需要建立完善的数据管理体系,提高数据处理和分析能力,以应对这些挑战。同时,数据资产的分类与评估、共享与使用规范也是数据资产管理的重要组成部分,需要制定合理的标准和规范,确保数据共享的安全性和隐私保护,以及建立合理的利益分配和权益保障机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一只小熊猫呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值