Vue shopCart 組件開發(fā)詳解
一、shopCart組件
(1) goods 父組件和 子組件 shopCart 傳參
deliveryPrice:{ // 單價(jià) 從json seller 對(duì)象數(shù)據(jù)中獲取
type:Number,
default:0
},
minPrice:{ // 最低起送價(jià) 從json seller 對(duì)象數(shù)據(jù)中獲取
type:Number,
default:20
}
其中 deliveryPrice 和 minPrice 的數(shù)據(jù)都是從 data.json數(shù)據(jù) 中 seller 對(duì)象下 獲得。所以在goods 組件中還要 獲取到 seller對(duì)象 的數(shù)據(jù),否則會(huì)報(bào)錯(cuò):
[Vue warn]: Error in render: "TypeError: Cannot read property 'deliveryPrice' of undefined"
解決方法:根組件 App.vue 中 router-view 組件獲取seller 數(shù)據(jù),傳到 goods 組件中
1-1.app.vue (根組件 也是 goods 的父組件)
<keep-alive> <router-view :sell="sellerObj"></router-view> </keep-alive>
注意:sellerObj 是data 定義 的 對(duì)象里用來接收 data.json 數(shù)據(jù),相當(dāng)于 實(shí)參
1-2.goods.vue (相對(duì)于跟組件的子組件 且 shopCart 的父組件)
通過props 屬性 進(jìn)行組件之間的通信
props: {
sell: Object // 相當(dāng)于 形參
},
1-3.shopCart.vue ( goods 的子組件)
<shopCart :delivery-price="sell.deliveryPrice" :min-price="sell.minPrice"></shopCart>
(2) 選中商品 的 計(jì)算功能
1-1. 傳入用戶選中商品的集合
說明:從父組件會(huì) 傳入一個(gè)用戶選中商品的 數(shù)組,數(shù)組里會(huì)存放著 n 個(gè)對(duì)象,每個(gè)對(duì)象里存放著該 商品的 價(jià)格 和 數(shù)量。
props:{ // 通過父組件傳過來的 ( 相當(dāng)于形參 )
selefoodsArr:{ // 用戶選中的商品存放在一個(gè)數(shù)組里 接收的是 data.json數(shù)據(jù)的 goods(數(shù)組)
type:Array, // 當(dāng)父組件傳過來的 類型是對(duì)象或者 是數(shù)組時(shí), default 就是一個(gè)函數(shù)
default (){
return [] // 返回?cái)?shù)組 存放著選中 商品 對(duì)應(yīng)的 goods下的 foods 數(shù)組(由 父組件 的 實(shí)參 決定的返回值)
}
}
1-2. 利用計(jì)算屬性 選中商品數(shù)量的變化,商品總價(jià),動(dòng)態(tài)改變描述等功能
computed:{
totalPrice (){ //計(jì)算總價(jià),超過起送額度后提示可付款
let total=0 // 定義一個(gè)返回值
this.selefoodsArr.forEach((rfoods) =>{ // 遍歷 這個(gè) goods 數(shù)組 取到 價(jià)格 和 數(shù)量 (當(dāng)然在這里數(shù)據(jù)庫(kù)沒有count 這個(gè)屬性,稍后 我們會(huì)利用 vue.set() 新建一個(gè)count 屬性)
total += rfoods.price * rfoods.count // 形參 rfoods 實(shí)參 是 foods
});
return total;
},
totalCount (){ // //計(jì)算選中的food數(shù)量,在購(gòu)物車圖標(biāo)處顯示,采用絕對(duì)定位,top:0;right:0;顯示在購(gòu)物車圖標(biāo)右上角
let count=0
this.selefoodsArr.forEach((rfoods) =>{ // 形參 rfoods 實(shí)參 是 foods
count += rfoods.count
});
return count;
},
payDesc (){ //控制底部右邊內(nèi)容隨food的變化而變化,payDesc()控制顯示內(nèi)容,enough 添加類調(diào)整顯示樣式
let diff = this.minPrice - this.totalPrice
if (!this.totalPrice) {
return `¥${this.minPrice}起送`
} else if (diff > 0) {
return `還差¥${diff}元`
} else {
return '去結(jié)算'
}
}
}
這樣就渲染到 template 里了
<div class="shopCart">
<div class="content">
<div class="content-left">
<div class="logo-wrapper">
<!--徽章 展示選中商品的個(gè)數(shù)-->
<div class="badge" v-show="totalCount">
{{totalCount}}
</div>
<!--購(gòu)物車 圖標(biāo) 選擇商品和未選擇商品 時(shí) 動(dòng)態(tài)改變 樣式 條件:只要選擇了商品即總價(jià)不為0 ,樣式變-->
<div class="logo" :class="{'active':totalCount}">
<i class="icon-shopping_cart"></i>
</div>
</div>
<!--同理: 總價(jià) 不為0 字體高亮-->
<div class="price" :class="{'active':totalPrice}">
¥{{totalPrice}}
</div>
<!--配送費(fèi) data.json 提供-->
<div class="desc">
另需要配送費(fèi)¥{{deliveryPrice}}元
</div>
</div>
<!--根據(jù)條件 動(dòng)態(tài) 改變樣式-->
<div class="content-right" :class="{'enough':totalPrice>=minPrice}">
{{payDesc}}
</div>
</div>
</div>
相關(guān)樣式
&.active color white &.enough background #00b43c color white
總結(jié):通過以上學(xué)習(xí)我們能發(fā)現(xiàn),selectFoods()的變化起著關(guān)鍵作用,它的變化會(huì)引起DOM的變化,并最終體現(xiàn)到界面上,而我們不用關(guān)注DOM內(nèi)部的具體實(shí)現(xiàn),這就是vue的一大好處。如果采用jQuery完成這些功能會(huì)略顯繁雜。
二、cartControl 組件
說明:這個(gè)組件是控制購(gòu)物車小球的。其中涉及到小球的動(dòng)畫
(1) 新增屬性 count
說明:
在goods 下的 foods 添加一個(gè)屬性 count,用來存儲(chǔ)用戶選中的商品個(gè)數(shù),計(jì)算商品總價(jià) 以及 關(guān)聯(lián)徽章(顯示用戶選擇商品的個(gè)數(shù))的變化
方法:通過import Vue from 'vue';使用set接口,通過vue.set()添加屬性,當(dāng)它變化時(shí)就能被檢測(cè)到,從而父組件能獲取到count值(遍歷選中的商品時(shí)使用)
methods:{
addCart(event){ // 點(diǎn)擊count 加,
//console.log(event.target);
if (!event._constructed) { // 去掉自帶click事件的點(diǎn)擊
return;
}
if(!this.foodsele.count){
Vue.set(this.foodsele, 'count', 1)
}else{
this.foodsele.count++
}
},
decreaseCart (event){ // 點(diǎn)擊減少
if (!event._constructed) { // 去掉自帶click事件的點(diǎn)擊
return;
}
if(this.foodsele.count){
this.foodsele.count --
}
}
}
(2)添加按鈕 實(shí)現(xiàn)transtion 過渡
我們要實(shí)現(xiàn)的效果是:當(dāng)點(diǎn)擊添加按鈕時(shí),減少按鈕出現(xiàn) 并伴隨著 旋轉(zhuǎn)、平移以及透明度變化的 一些 動(dòng)畫效果
<transition name='move'> <!--平移動(dòng)畫--> <div class="cart-decrease" v-show="foodsele.count" @click='decreaseCart($event)'> <span class="icon-remove_circle_outline inner"></span><!--旋轉(zhuǎn)、透明度動(dòng)畫--> </div> </transition>
.cart-decrease
display inline-block
padding 6px
transition: all .4s linear /*過渡效果的 CSS 屬性的名稱、過渡效果需要多少時(shí)間、速度效果的速度曲線*/
.inner
line-height 24px
font-size 24px
color rgb(0,160,220)
transition all 0.4s linear
&.move-enter-active, &.move-leave-active
transform translate3d(0,0,0) /* 這樣可以開啟硬件加速,動(dòng)畫更流暢,3D旋轉(zhuǎn),X軸位移24px */
.inner
display inline-block /* 設(shè)置成inline-block才有高度,才能有動(dòng)畫 */
transform rotate(0)
&.move-enter, &.move-leave-active
opacity: 0
transform translate3d(24px,0,0)
.inner
transform rotate(180deg)
三、拋物線小球動(dòng)畫
通過兩個(gè)層來控制小球,外層控制一個(gè)方向的變化,內(nèi)層控制另外一個(gè)方向的變化(寫兩層才會(huì)有拋物線的效果),采用fixed布局(是相對(duì)于視口的動(dòng)畫)
事件發(fā)射和接收
擴(kuò)展
Vue1.0組件間傳遞
- 使用$on()監(jiān)聽事件;
- 使用$emit()在它上面觸發(fā)事件;
- 使用$dispatch()派發(fā)事件,事件沿著父鏈冒泡;
- 使用$broadcast()廣播事件,事件向下傳導(dǎo)給所有的后代
(1) Vue2.0 組件之間傳遞數(shù)據(jù)
1-1. 當(dāng)點(diǎn)擊 添加數(shù)量時(shí) 在 cartControl 組件里的 addCount 方法里 通過 $emit 屬性 派發(fā)一個(gè)事件 , 傳入點(diǎn)擊的對(duì)象
addCart(event){ // 點(diǎn)擊count 加,
// console.log(event.target);
if (!event._constructed) { // 去掉自帶click事件的點(diǎn)擊
return;
}
if(!this.foodsele.count){
Vue.set(this.foodsele, 'count', 1)
}else{
this.foodsele.count++
}
// 當(dāng)點(diǎn)擊 添加數(shù)量時(shí) 通過 $emit 屬性 提交一個(gè)名為 add 給父組件
// 子組件通過 $emit觸發(fā) add事件 ,將參數(shù)傳遞給父組件
this.$emit('add', event.target);
}
1-2. 操作 goods 組件
購(gòu)物車組件如果提交了addCart事件就調(diào)用add函數(shù)
<cart-control :foodsele='food' @add="addFood"></cart-control>
父組件使用 @add="addFood"監(jiān)聽由子組件vm.$emit觸發(fā)的事件,通過addFood()接受從子組件傳遞過來的數(shù)據(jù),通知父組件數(shù)據(jù)改變了。
addFood(target) {
this._drop(target);
}
1-3. 父組件訪問子組件 vue 提供了接口 ref
<shopCart ref="shopCart" :delivery-price="sell.deliveryPrice" :min-price="sell.minPrice" :selefoods-arr='selectfoods' ></shopCart>
_drop(target) {
// 體驗(yàn)優(yōu)化,異步執(zhí)行下落動(dòng)畫
this.$nextTick(() => {
this.$refs.shopCart.balldrop(target);// 將target傳入shopCart子組件中的balldrop方法,所以drop方法能獲得用戶點(diǎn)擊按鈕的元素,即能獲取點(diǎn)擊按鈕的位置
});
}
區(qū)別 訪問DOM 變量
1-3. 操作 shopCart 組件
data (){ // 定義一個(gè)數(shù)組 來 控制小球的狀態(tài) 定義多個(gè)對(duì)象,表示頁(yè)面中做多同時(shí)運(yùn)動(dòng)的小球
return{ // 定義 5 個(gè) 小球
balls:[{show:false},{show:false},{show:false},{show:false},{show:false}],
dropBalls:[] // 接收下落小球
}
}
methods:{
balldrop(ele) {
// console.log(el) 取到點(diǎn)擊 對(duì)象
for(var i=0;i<this.balls.length;i++){
let ball=this.balls[i]
if(!ball.show){
ball.show=true
ball.ele=ele
this.dropBalls.push(ball)
return;
}
}
}
}
動(dòng)畫過程開始,利用vue 提供的鉤子函數(shù)
beforeEnter (el){ //找到所以設(shè)為true的小球
let count=this.balls.length
while(count--){
let ball = this.balls[count];
if(ball.show){
let pos=ball.el.getBoundingClientRect() //返回元素相對(duì)于視口偏移的位置
let x=pos.left-32 // 點(diǎn)擊的按鈕與小球(fixed)之間x方向的差值
let y=-(window.innerHeight-pos.top-22)
el.style.display = ''; //設(shè)置初始位置前,手動(dòng)置空,覆蓋之前的display:none,使其顯示
el.style.webkitTransform = `translate3d(0,${y}px,0)`; //外層元素做縱向的動(dòng)畫,y是變量
el.style.transform = `translate3d(0,${y}px,0)`;
let inner = el.getElementsByClassName('inner_hook')[0];//內(nèi)層元素做橫向動(dòng)畫,inner-hook(用于js選擇的樣式名加上-hook,表明只是用 //于js選擇的,沒有真實(shí)的樣式含義)
inner.style.webkitTransform = `translate3d(${x}px,0,0)`;
inner.style.transform = `translate3d(${x}px,0,0)`;
}
}
},
enter(el) {
/* eslint-disable no-unused-vars */
let rf = el.offsetHeight;
this.$nextTick(() => {//異步執(zhí)行
el.style.webkitTransform = 'translate3d(0,0,0)'; //重置回來
el.style.transform = 'translate3d(0,0,0)';
let inner = el.getElementsByClassName('inner_hook')[0];
inner.style.webkitTransform = 'translate3d(0,0,0)';
inner.style.transform = 'translate3d(0,0,0)';
});
},
afterEnter(el) {
let ball = this.dropBalls.shift(); //取到做完動(dòng)畫的球,再置為false,即重置,它還可以接著被利用
if (ball) {
ball.show = false;
el.style.display = 'none';
}
}
<div class="ball-container">
<div v-for="ball in balls">
<transition name="drop" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
<div class="ball" v-show="ball.show">
<div class="inner inner_hook"></div>
</div>
</transition>
</div>
</div>
&.drop-enter,&.drop-enter-active
transition all 0.4s cubic-bezier(0.49,-0.29,0.75,0.41)
.inner
width 16px
height 16px
border-radius 50%
background rgb(0,160,220)
transition all 0.4s linear
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue-star評(píng)星組件開發(fā)實(shí)例
- Vue header組件開發(fā)詳解
- Vue框架之goods組件開發(fā)詳解
- Vue組件開發(fā)之LeanCloud帶圖形校驗(yàn)碼的短信發(fā)送功能
- vue webuploader 文件上傳組件開發(fā)
- Vue.js彈出模態(tài)框組件開發(fā)的示例代碼
- vue.js學(xué)習(xí)之UI組件開發(fā)教程
- Vue.js手風(fēng)琴菜單組件開發(fā)實(shí)例
- Vue組件開發(fā)初探
- Vue 短信驗(yàn)證碼組件開發(fā)詳解
- 深入淺析Vue組件開發(fā)
- vue多級(jí)多選菜單組件開發(fā)
- vue.js表格組件開發(fā)的實(shí)例詳解
- Vue組件開發(fā)技巧總結(jié)
相關(guān)文章
vue?router?動(dòng)態(tài)路由清除方式
這篇文章主要介紹了vue?router?動(dòng)態(tài)路由清除方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
vue-router結(jié)合vuex實(shí)現(xiàn)用戶權(quán)限控制功能
這篇文章主要介紹了vue-router結(jié)合vuex實(shí)現(xiàn)用戶權(quán)限控制功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
使用vue引入maptalks地圖及聚合效果的實(shí)現(xiàn)
這篇文章主要介紹了使用vue引入maptalks地圖及聚合效果的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue啟動(dòng)報(bào)錯(cuò)‘vue-cli-service serve‘問題及解決
這篇文章主要介紹了vue啟動(dòng)報(bào)錯(cuò)‘vue-cli-service serve‘問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10
Vue3+Vue Router實(shí)現(xiàn)動(dòng)態(tài)路由導(dǎo)航的示例代碼
隨著單頁(yè)面應(yīng)用程序(SPA)的日益流行,前端開發(fā)逐漸向復(fù)雜且交互性強(qiáng)的方向發(fā)展,在這個(gè)過程中,Vue.js及其生態(tài)圈的工具(如Vue Router)為我們提供了強(qiáng)大的支持,本文將介紹如何在Vue 3中使用Vue Router實(shí)現(xiàn)動(dòng)態(tài)路由導(dǎo)航,需要的朋友可以參考下2024-08-08
vue.js仿hover效果的實(shí)現(xiàn)方法示例
這篇文章主要介紹了vue.js仿hover效果的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了vue.js事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-01-01
vue element插件this.$confirm用法及說明(取消也可以發(fā)請(qǐng)求)
這篇文章主要介紹了vue element插件this.$confirm用法及說明(取消也可以發(fā)請(qǐng)求),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
element的表單校驗(yàn)證件號(hào)規(guī)則及輸入“無”的情況校驗(yàn)通過(示例代碼)
這篇文章主要介紹了element的表單校驗(yàn)證件號(hào)規(guī)則及輸入“無”的情況校驗(yàn)通過,使用方法對(duì)校驗(yàn)數(shù)據(jù)進(jìn)行過濾判斷,本文通過示例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2023-11-11

