案例实现购物车, 跨组件传参。这里用的是事件总线eventBus .。
动态组件。
点击购买按钮后,购物车数量统计自动++
,相同产品自加1,没有的商品添加到购物车。
点击购物车时,能看到加入的商品数据。
刷新页面数据不会丢失。
(计算属性要有return 返回值得。)
代码如下
<style>
html,
body,
ul,
li {
margin: 0;
padding: 0;
}
ul li {
list-style: none;
}
.product {
display: flex;
justify-content: center;
align-items: center;
border-bottom: solid 0.01rem fuchsia;
padding: 0.5rem 1.5rem;
flex-direction: column;
}
.product img {
width: 75%;
}
.product h5 {
color: deeppink;
}
html,
body,
#app {
height: 100%;
}
#app {
display: flex;
flex-direction: column;
overflow: hidden;
}
.list {
flex: 1;
height: 100%;
overflow: auto;
}
.nav {
height: 60px;
}
.nav ul {
display: flex;
justify-content: space-around;
}
.nav .active {
color: deeppink;
}
.nav ul li {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
.nav ul li img {
width: 26px;
margin: 0.5rem;
}
.nav ul li span {
font-size: 0.8rem;
}
.dot {
position: absolute;
z-index: 10;
width: 20px;
height: 20px;
padding: 0.2rem;
border-radius: 50%;
background-color: rgba(200, 0, 0, 0.7);
color: white;
text-align: center;
top: -6px;
left: 20px;
}
.btn {
border: none;
background-color: orangered;
text-align: center;
color: white;
width: 5rem;
height: 1.5rem;
}
.title {
padding: 0;
margin: 0.5rem 1rem;
}
.sum-price {
position: fixed;
background-color: #4bd67c;
bottom: 70px;
right: 5px;
padding: 0.5rem 1rem;
color: white;
}
</style>
<div id="app">
<!-- 动态组件,通过设置is属性绑定当前显示的组件内容 -->
<component style="height: 100%;" :is="currentComponent"></component>
<div class="nav">
<ul>
<li @click="setPage('list', 0)" :class="{active: selectIndex == 0}">
<img
:src="selectIndex==0? './assets/images/list-sel.png': './assets/images/list.png'"
/>
<span>商品列表</span>
</li>
<li @click="setPage('cart', 1)" :class="{active: selectIndex == 1}">
<img
:src="selectIndex==1? './assets/images/cart-sel.png': './assets/images/cart.png'"
/>
<span>购物车</span>
<span class="dot">{{cartCount}}</span>
</li>
</ul>
</div>
</div>
<!-- 就会找一个离我们最近的服务器进行访问,加快访问速度 -->
<!-- cdn服务器部署和开发人员没有关系,是运维的环节 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@2.1.1/dist/jquery.min.js"></script>
<script>
// 非相关组件之间传参 使用事件总线
// 所谓事件总线是一种开发思想,所有的事件派发和监听都是同一个空白实例中进行
var eventBus = new Vue();
// 我们在vue对象的prototype属性上定义一个变量
// 此属性在vue实例中能被访问到
Vue.prototype.$eventBus = eventBus;
// 首页
var list = {
template: `<ul class="list">
<li class="product" v-for="item in products" :key="item.skuId">
<img :src="item.image" :alt="item.name" />
<h5>{{item.name}}</h5>
<button class="btn" @click="buy(item)">购买</button>
</li>
</ul>`,
data() {
return { products: [] }; //
},
created() {
$.getJSON(
"https://o2api.jd.com/data?body=%7B%22query%22%3A%22query%20getCommodities(%24ids%3A%20String)%7Bcommodities(ids%3A%20%24ids)%7BgroupId%2C%20groupName%2C%20productList%7BcanSell%20skuId%20name%20image%20commentCount%20goodRate%20jdPrice%20pcpPrice%20plusPrice%20tag%20copyWriting%20copyWritingDown%20backUpWords%7D%7D%7D%22%2C%22operationName%22%3A%22getCommodities%22%2C%22variables%22%3A%7B%22ids%22%3A%22%5B03504985%2C03505081%5D%22%7D%2C%22config%22%3A%7B%22cache%22%3Afalse%2C%22trim%22%3Atrue%2C%22map%22%3A%7B%22keyBy%22%3A%22groupId%22%2C%22valueField%22%3A%22productList%22%7D%7D%7D&_=1568689310891"
).then((res) => {
this.products = res.data["03504985"];
});
},
methods: {
buy(product) {
// 事件派发, 参数一叫事件名字,参数二是传递的参数
this.$eventBus.$emit("buyClick", product);
},
},
};
// 购物车页面
var cart = {
template: `
<div class="list">
<h1 class="title">购物车</h1>
<ul>
<li class="product" v-for="item in products" :key="item.skuId">
<img :src="item.image" :alt="item.name" />
<h5>{{item.name}}</h5>
<p>
<button @click="subj(item)">-</button>
<input v-model="item.isChecked" type="checkbox"/>
{{item.jdPrice}}X{{item.amount}}
<button @click="item.amount+=1">+</button>
</p>
</li>
</ul>
<div class="sum-price">
<p>总价:¥{{sumPrice}}元</p>
</div>
</div>`,
data() {
return {
products: [],
};
},
created() {
// 在购物车页面,当已进入这个页面就从本地取数据
var strShopCarts = localStorage.getItem("shop-carts");
if (strShopCarts) {
this.products = JSON.parse(strShopCarts);
}
},
computed: {
// 计算属性设置总价
sumPrice() {
return this.products
.filter((item) => item.isChecked) // 过滤
.reduce((pre, cur) => pre + cur.jdPrice * cur.amount, 0); // 求和
},
},
methods:{
subj(item){
console.log(item, ‘是接受减法时的参数对象’)
item.amount--
if(item.amount<1){ // 对象的数量小于1时,数量为0.
item.amount = 0
}
}
}
};
var app = new Vue({
el: "#app",
data: {
selectIndex: 0,
currentComponent: "list",
// cartCount: 0,
shopCarts: [], // 购物车数据
},
// 注册组件
components: {
list,
cart,
},
methods: {
// 动态接受页面组件
setPage(page, index) {
// 设置当前选中的组件
this.currentComponent = page;
// 设置当前选中的底部索引
this.selectIndex = index;
},
},
created() {
// 做事件监听 v代表传递过来的商品信息
this.$eventBus.$on("buyClick", (v) => {
// console.log(v);
// 查找符合条件的数据的下标 findIndex()
var index = this.shopCarts.findIndex(
(item) => item.skuId === v.skuId
);
if (index > -1) {
// this.shopCarts
// 如果存在这个商品数量就加1
this.shopCarts[index].amount += 1;
} else { // 如果没有就新加入购物车一个商品数据
// 使用了对象的扩展运算符
this.shopCarts.push({ ...v, amount: 1, isChecked: false });
}
// 存储到本地 为了点击购物车的时候可以看到加入购物车的数据
localStorage.setItem("shop-carts", JSON.stringify(this.shopCarts));
// if(this.shopCarts.findIndex())
// this.cartCount++;
});
var strShopCarts = localStorage.getItem("shop-carts");
if (strShopCarts) {
this.shopCarts = JSON.parse(strShopCarts);
}
},
computed: {
cartCount() {
// 根据当前的shopCarts数据计算总数量
return this.shopCarts.reduce((pre, cur) => {
return pre + cur.amount;
}, 0);
},
},
});
</script>