Vue 当当网购物车实践总结

Vue 廖标敏

在学习Vue框架基础语法后,第一个实践便是常见的购物车组件,基本使用了到目前第三章学的各种基础Vue语法,体会到了Vue的强大之处 。

1  重复结构的节点可以只写一个然后自动重复生成和渲染数据 ,

2 操作数据时  变化数据   视图也会变化 

3 input双向绑定 减少对数据操作 

4  在事件中可以使用事件修饰符 和data中bool变量 来限制事件的执行条件  传参也能使用date中变量

5 有深度监听 可以很方便的对变化的数据进行操作

6 计算属性 很方便的计算数据然后将结果渲染到页面 数据变化 计算结果也会变化

7生命周期函数  可以在生命周期中 按照需求对数据进行处理

还有其他未列举的 相信在以后的使用中会感受到更多Vue的强大之处


下面便是我此次当当网购物车的部分代码 分多个模块


一  html代码 

1 载入Vue 时加入判断 是否存在Vue框架 没有则调用备用CDN  注意使用document.write 时最后<\/script>要加转义 否则会不起作用  

2主要使用v-if 显示隐藏商品列表 使用v-bind:class 绑定 active样式

3使用v-for 渲染商品列表 和 购物车表格

4@click中传参使用 渲染数据中的id属性 也可以直接传参对象 或者data中的数据 也可以配合data中某个bool变量 例如@click=“ bool&&add()”来限制事件的触发

5 标签中的属性也可以使用渲染数据 或者拼接

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<link rel="stylesheet" type="text/css" href="css/shopping.css" />
		<script type="text/javascript">
			if (typeof Vue == 'undefined') {
				console.log('载入Vue备用CDN')
				document.write('<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.0/vue.min.js"><\/script>')
			}
		</script>
	</head>
	<body>
		<div class="main">

			<!-- 商品列表 -->
			<div class="booklist">
				<p class="title"> <img src="images/shopping_myshopping.gif"> <a href="javascript:void(0)"> 全场免运费活动中</a>
				</p>
				<div class="allBook_box">
					<p>根据您挑选的商品,当当为您推荐 <img :class="{active:allBookbool}" src="images/shopping_arrow_down.gif"
							@click="allBookshow"></p>
					<ul class="allBook" v-show="allBookbool">
						<li v-for="item in allbook">
							<ul>
								<li><a href="javascript:void(0)">·{{item.bookname}}</a></li>
								<li>¥{{item.price}}</li>
								<li>¥{{item.discount}}</li>
								<li><a href="javascript:void(0)" @click="add(item.id)">购买</a></li>
							</ul>
						</li>
					</ul>
				</div>
			</div>

			<!-- 购物车表格 -->
			<div class="shopCar">
				<p><b>您已选购以下商品</b></p>
				<table border="0" cellspacing="0" cellpadding="0" id="shopBook">
					<tr>
						<th>商品名</th>
						<th>单品积分</th>
						<th>市场价</th>
						<th>当当价</th>
						<th>数量 </th>
						<th>删除</th>
					</tr>
					<tr v-for="item in buygoods">
						<td><a href="javascript:void(0)">{{item.bookname}}</a></td>
						<td>{{item.discount*10}}</td>
						<td>¥{{item.price}}</td>
						<td>¥{{item.discount}}({{parseInt(item.discount*100/item.price)}}折)</td>
						<td><button type="button" class="bnt" @click="btndown(item.id)">-</button> <input size="1"
								v-model="item.num" /> <button type="button" class="bnt"
								@click="btnadd(item.id)">+</button></td>
						<td><button type="button" @click="del(item.id)">删除</button></td>
					</tr>
				</table>
				<div class="content">
					<div>
						<p>您总共节省:<span>¥{{savemoney}}</span></p>
						<p>可获商品积分:<span>{{sumprice*10}}</span></p>
					</div>
					<div>
						<p>商品金额总计:<span><b>¥{{sumprice}}</b></span> <img src="images/shopping_balance.gif"> </p>
					</div>
				</div>
			</div>
		</div>
		<script src="js/shopping.js" type="text/javascript" charset="utf-8"></script>
	</body>
</html>


二 css样式

/* 布局 */
body,
p,
ul,
li {
	padding: 0px;
	margin: 0px;
	list-style: none;
}

.main {
	width: 950px;
	height: 800px;
	margin: auto;
}

a {
	text-decoration: none;
}

.bnt {
	line-height: 13px;
	width: 16px;
	height: 16px;
	font-weight: bold;
	font-size: 12px;
	padding: 0px;
}

/* 商品列表 */
.booklist .title {
	height: 50px;
	line-height: 55px;
}

.booklist .title img {
	vertical-align: -1px;
}

.booklist a:hover {
	text-decoration: underline;
}

.allBook_box p {
	line-height: 21px;
	font-size: 14px;
	background: url(../images/shopping_commend_bg.gif);
	box-sizing: border-box;
	border: 1px #000000 solid;
	text-indent: 10px;
}

.allBook_box p img {
	float: right;
	margin-top: 3px;
	margin-right: 8px;
}

.allBook {
	display: flex;
	justify-content: space-between;
	flex-wrap: wrap;
	box-sizing: border-box;
	padding: 10px 12px;
	border: 1px #000000 solid;
	border-top-width: 0px;
}

.allBook>li {
	width: 50%;
	box-sizing: border-box;
}

.allBook>li:nth-child(2n) {
	border-left: 1px dashed #999;
}

.allBook ul {
	display: flex;
	justify-content: space-between;
	font-size: 12px;
}

.allBook ul li {
	line-height: 30px;
}

.allBook ul li:nth-child(1) {
	width: 220px;
	padding-left: 10px;
}

.allBook ul li:nth-child(2) {
	width: 45px;
	color: #3549cc;
	text-decoration: line-through;
}

.allBook ul li:nth-child(3) {
	width: 45px;
}

.allBook ul li:nth-child(4) {
	padding-right: 10px;
}

.allBook ul li:nth-child(4) a {
	color: #ED610C;
}

/* 购物车表格 */
.shopCar {
	margin-top: 20px;
}

.shopCar p {
	font-size: 15px;
	padding-bottom: 10px;
}

#shopBook {
	width: 100%;
	line-height: 40px;
	border: 1px #999 solid;
	border-bottom-width: 0px;
}

#shopBook th {
	font-weight: normal;
	font-size: 14px;
}
#shopBook tr:not(:nth-child(1)):hover{
	background-color: #edfada;
}
#shopBook tr:nth-child(1) {
	line-height: 30px;
	background-color: #d8e4c6;
}

#shopBook tr:not(:nth-child(1)) {
	background-color: #fefbf2;
	font-size: 12px;
}

#shopBook tr:not(:nth-child(1)) td {
	border-bottom: 1px dashed #CCCCCC;
}

#shopBook td:not(:nth-child(1)) {
	text-align: center;
}

#shopBook td:nth-child(1) {
	text-indent: 25px;
	width: 320px;
}

#shopBook input {
	text-align: center;
}
#shopBook button{
	cursor: pointer;
}

.active {
	transform: rotate(180deg);
}

.content {
	display: flex;
	justify-content: flex-end;
	height: 60px;
	background-color: #cddbb8;
	line-height: 26px;
	padding: 10px 10px;
	border: 1px #999 solid;
	border-top-width: 0px;
}

.content>div:nth-child(1) {
	width: 160px;
	border-right: 1px solid black;
}

.content>div:nth-child(2) {
	margin-left: 18px;
	line-height: 55px;
}

.content>div:nth-child(2) img {
	vertical-align: middle;
	padding-left: 12px;
	cursor: pointer;
}

.content span {
	color: red;
	font-size: 12px;
	padding-left: 10px;
}

.content span b {
	font-size: 14px;
}


三   javas Vue代码

1 使用data 属性渲染网页数据  和保存需要的数据 例如购物车内的商品

2使用methods 绑定点击事件

3使用computed 计算属性 渲染价格等

4使用watch 监听网页中的商品数量变化 相对的为data中的对象数据变化 必须使用深度监听

5使用生命周期函数 Created在创建Vue对象成功未载入节点数据 其他数据载入时

调用本地数据进行替换

let vm = new Vue({
	el: '.main',
	data: {
		allbook: [{
				id: 1,
				bookname: 'JavaScript DOM编程艺术',
				price: '39.00',
				discount: '29.30'
			},
			{
				id: 2,
				bookname: '解禁(当当网独家首发)',
				price: '28.00',
				discount: '19.40'
			},
			{
				id: 3,
				bookname: '地王之王(金融危机下房地产行...',
				price: '32.80',
				discount: '25.10'
			},
			{
				id: 4,
				bookname: '逃庄',
				price: '36.00',
				discount: '27.70'
			},
			{
				id: 5,
				bookname: '深入浅出MySQL数据库开发、优...',
				price: '59.00',
				discount: '47.20'
			},
			{
				id: 6,
				bookname: '大玩家(马未都、王刚推荐!央...',
				price: '34.80',
				discount: '30.50'
			},
			{
				id: 7,
				bookname: '都市风水师--官场风水小说:一...',
				price: '39.80',
				discount: '20.60'
			},
			{
				id: 8,
				bookname: '国戏(以麻将术语解读宦海沉浮...',
				price: '25.00',
				discount: '17.30'
			},
		],
		allBookbool: true,
		buygoods: [{
			id: 1,
			bookname: 'JavaScript DOM编程艺术',
			price: '39.00',
			discount: '29.30',
			num: 1
		}] //已购买数组
	},
	methods: {
		allBookshow() { //图书列表显示隐藏
			this.allBookbool = !this.allBookbool
		},
		add(id) { //新图书添加
			let repbool = false
			let allbook = this.allbook
			let buygoods = this.buygoods
			for (let i = 0; i < buygoods.length; i++) { //判断id是否存在已购买数组中
				if (buygoods[i].id == id) {
					buygoods[i].num++
					repbool = true
				}
			}
			if (!repbool) { //不重复则执行
				let index = ''; //重复商品在数组中下标
				for (let i = 0; i < allbook.length; i++) {
					if (allbook[i].id == id) {
						let arr = {
							...allbook[i]
						} //创建新数组 加默认数量属性 放入已购买数组中
						arr.num = 1
						buygoods.push(arr)
						// console.log(arr)
					}
				}
			}
		},
		btnadd(id) { //按键添加数量 通过传参id 调用add(id)新图书添加事件
			// alert(id)
			this.add(id)
		},
		btndown(id) { //按键减少数量 
			// alert(id)
			let buygoods = this.buygoods
			for (let i = 0; i < buygoods.length; i++) {
				if (buygoods[i].id == id) { //判断id与数组中一致  num属性减一
					if (buygoods[i].num > 1) {
						buygoods[i].num--
					} else {
						console.log('数量至少为1');
					}
				}
			}
		},
		del(id) { //在已购买的数组中根据id删除数据
			if (confirm('确定删除该行商品?')) {
				// console.log(id);
				let buygoods = this.buygoods
				for (var i = 0; i < buygoods.length; i++) {
					if (buygoods[i].id == id) {
						buygoods.splice(i, 1)
					}
				}
			}
		}
	},
	computed: {
		sumprice() { //总价 积分为总价*10
			let sum = 0
			for (let s of this.buygoods) {
				sum += s.discount * s.num
			}
			return sum.toFixed(2)
		},
		savemoney() { //节省
			let sum = 0
			for (let s of this.buygoods) {
				sum += (s.price - s.discount) * s.num
			}
			return sum.toFixed(2)
		},
	},
	watch: {
		buygoods: {
			handler(newval, oldval) { //深度监听  输入num 非>=1 的数字或其他字符时 或者小数 会被赋值为1
				for (let s of newval) {
					if (!(s.num >= 1 && s.num % 1 == 0)) {
						s.num = 1
					}
				};
				let str = JSON.stringify(this.buygoods) //数据变化 本地重新存储
				sessionStorage.buygoods = str
			},
			deep: true
		}
	},
	created() {
		if (sessionStorage.buygoods) { //存在本地数据则载入
			let buygoods = JSON.parse(sessionStorage.buygoods)
			this.buygoods = buygoods
			console.log('本地有数据');
		} else {
			console.log('本地没有数据');
		}
	}
})

效果图:

Vue当当网购物车.png

在此次事件中遇到的问题

1 多层数据结构如何在网页中渲染?

2 深度监听的使用方法是什么?

3事件中 需要传参的数据选择  ?

4使用Vue时在网页渲染时   如何拼接 属性 变量 实际参数 等?

通过查阅资料  已经解决部分 问题  其他还在学习中


四 总结 

       经过此次使用Vue编写 当当网购物车 的实践 ,增强了对Vue的了解 和使用规范 以及使用方法  也体会到了渐进式开发 或 MVVM框架 开发的乐趣  与操作Dom来开发 的确是另一个完全不同的编写模式 希望在后面的学习中再接再厉 在脑中建立好Vue的整体使用思维。

还能输出{{restrictNumber}}个字符  
  • {{reply.author}}

    {{CommonUtil.formateDate(reply.ac_CommentDate).shortTime}}
  • 回复了{{Comments.author}} :