本文主要跟大家介紹Vue shopCart 組件開發詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。
一、shopCart元件
(1) goods 父元件與子元件shopCart 傳參
deliveryPrice:{ // 单价 从json seller 对象数据中获取 type:Number, default:0 }, minPrice:{ // 最低起送价 从json seller 对象数据中获取 type:Number, default:20 }
其中deliveryPrice 和minPrice 的資料都是從data.json資料中seller 物件下取得。所以在goods 元件中也要取得seller物件的數據,否則會報錯:
[Vue warn]: Error in render: "TypeError: Cannot read property 'deliveryPrice' of undefined"
解決方法:根組件App.vue 中router-view 組件獲取seller 數據,傳到goods 組件中
1-1.app.vue (根組件也是goods 的父組件)
<keep-alive> <router-view :sell="sellerObj"></router-view> </keep-alive>
注意:sellerObj 是data 定義的物件裡用來接收data.json 數據,相當於實參
1-2.goods. vue (相對於跟元件的子元件且shopCart 的父元件)
透過props 屬性進行元件之間的通訊
props: { sell: Object // 相当于 形参 },
1-3. shopCart.vue ( goods 的子元件)
<shopCart :delivery-price="sell.deliveryPrice" :min-price="sell.minPrice"></shopCart>
(2) 選取商品的運算功能
#1-1. 傳入使用者選取商品的集合
說明:從父元件會傳入一個使用者選取商品的數組,數組裡會存放著n 個對象,每個對象裡存放著該商品的價格和數量。
props:{ // 通过父组件传过来的 ( 相当于形参 ) selefoodsArr:{ // 用户选中的商品存放在一个数组里 接收的是 data.json数据的 goods(数组) type:Array, // 当父组件传过来的 类型是对象或者 是数组时, default 就是一个函数 default (){ return [] // 返回数组 存放着选中 商品 对应的 goods下的 foods 数组(由 父组件 的 实参 决定的返回值) } }
1-2. 利用計算屬性選取商品數量的變化,商品總價,動態改變描述等功能
computed:{ totalPrice (){ //计算总价,超过起送额度后提示可付款 let total=0 // 定义一个返回值 this.selefoodsArr.forEach((rfoods) =>{ // 遍历 这个 goods 数组 取到 价格 和 数量 (当然在这里数据库没有count 这个属性,稍后 我们会利用 vue.set() 新建一个count 属性) total += rfoods.price * rfoods.count // 形参 rfoods 实参 是 foods }); return total; }, totalCount (){ // //计算选中的food数量,在购物车图标处显示,采用绝对定位,top:0;right:0;显示在购物车图标右上角 let count=0 this.selefoodsArr.forEach((rfoods) =>{ // 形参 rfoods 实参 是 foods count += rfoods.count }); return count; }, payDesc (){ //控制底部右边内容随food的变化而变化,payDesc()控制显示内容,enough 添加类调整显示样式 let diff = this.minPrice - this.totalPrice if (!this.totalPrice) { return `¥${this.minPrice}起送` } else if (diff > 0) { return `还差¥${diff}元` } else { return '去结算' } } }
這樣就渲染到template 裡了
<p class="shopCart"> <p class="content"> <p class="content-left"> <p class="logo-wrapper"> <!--徽章 展示选中商品的个数--> <p class="badge" v-show="totalCount"> {{totalCount}} </p> <!--购物车 图标 选择商品和未选择商品 时 动态改变 样式 条件:只要选择了商品即总价不为0 ,样式变--> <p class="logo" :class="{'active':totalCount}"> <i class="icon-shopping_cart"></i> </p> </p> <!--同理: 总价 不为0 字体高亮--> <p class="price" :class="{'active':totalPrice}"> ¥{{totalPrice}} </p> <!--配送费 data.json 提供--> <p class="desc"> 另需要配送费¥{{deliveryPrice}}元 </p> </p> <!--根据条件 动态 改变样式--> <p class="content-right" :class="{'enough':totalPrice>=minPrice}"> {{payDesc}} </p> </p> </p>
相關樣式
&.active color white &.enough background #00b43c color white
總結:透過以上學習我們能發現,selectFoods()的變化起著關鍵作用,它的變化會引起DOM的變化,並最終體現到介面上,而我們不用專注於DOM內部的具體實現,這就是vue的一大好處。如果採用jQuery完成這些功能會略顯繁雜。
二、cartControl 元件
說明:這個元件是控制購物車小球的。其中涉及小球的動畫
(1) 新增屬性count
說明:
在goods 下的foods 新增一個屬性count,用來儲存使用者選取的商品數量,計算商品總價以及關聯徽章(顯示使用者選擇商品的個數)的變化
方法:透過import Vue from 'vue';使用set接口,透過vue.set()新增屬性,當它變化時就能被偵測到,從而父元件能取得到count值(遍歷選取的商品時使用)
methods:{ addCart(event){ // 点击count 加, //console.log(event.target); if (!event._constructed) { // 去掉自带click事件的点击 return; } if(!this.foodsele.count){ Vue.set(this.foodsele, 'count', 1) }else{ this.foodsele.count++ } }, decreaseCart (event){ // 点击减少 if (!event._constructed) { // 去掉自带click事件的点击 return; } if(this.foodsele.count){ this.foodsele.count -- } } }
(2)新增按鈕實作transtion過渡
我們要實現的效果是:當點擊新增按鈕時,減少按鈕出現並伴隨著旋轉、平移以及透明度變化的一些動畫效果
<transition name='move'> <!--平移动画--> <p class="cart-decrease" v-show="foodsele.count" @click='decreaseCart($event)'> <span class="icon-remove_circle_outline inner"></span><!--旋转、透明度动画--> </p> </transition>
.cart-decrease display inline-block padding 6px transition: all .4s linear /*过渡效果的 CSS 属性的名称、过渡效果需要多少时间、速度效果的速度曲线*/ .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) /* 这样可以开启硬件加速,动画更流畅,3D旋转,X轴位移24px */ .inner display inline-block /* 设置成inline-block才有高度,才能有动画 */ transform rotate(0) &.move-enter, &.move-leave-active opacity: 0 transform translate3d(24px,0,0) .inner transform rotate(180deg)
三、拋物線小球動畫
透過兩層來控制小球,外層控制一個方向的變化,內層控制另外一個方向的變化(寫兩層才會有拋物線的效果),採用fixed佈局(是相對於視口的動畫)
事件發射和接收
組件之間傳值-1
元件之間傳值-2
擴充
Vue1.0元件間傳遞
#使用$on()監聽事件;
使用$emit()在它上面觸發事件;
使用$dispatch()派發事件,事件沿著父鏈冒泡;
使用$broadcast()廣播事件,事件向下傳導給所有的後代
(1) Vue2.0 元件之間傳遞資料
1-1. 當點擊新增數量時在cartControl 元件裡的addCount 方法裡透過$emit 屬性派發一個事件, 傳入點擊的物件
addCart(event){ // 点击count 加, // console.log(event.target); if (!event._constructed) { // 去掉自带click事件的点击 return; } if(!this.foodsele.count){ Vue.set(this.foodsele, 'count', 1) }else{ this.foodsele.count++ } // 当点击 添加数量时 通过 $emit 属性 提交一个名为 add 给父组件 // 子组件通过 $emit触发 add事件 ,将参数传递给父组件 this.$emit('add', event.target); }
1-2. 操作goods 元件
#購物車元件如果提交了addCart事件就呼叫add函數
<cart-control :foodsele='food' @add="addFood"></cart-control>
父元件使用@add="addFood"監聽由子元件vm.$emit觸發的事件,透過addFood()接受從子元件傳遞過來的數據,通知父元件資料改變了。
addFood(target) { this._drop(target); }
1-3. 父元件存取子元件vue 提供了介面ref
複製程式碼 程式碼如下:
c9cb38f6d0313394adb8ae386a769cf916806ed5fafa880e2b2d16b7e7eeba31
_drop(target) { // 体验优化,异步执行下落动画 this.$nextTick(() => { this.$refs.shopCart.balldrop(target);// 将target传入shopCart子组件中的balldrop方法,所以drop方法能获得用户点击按钮的元素,即能获取点击按钮的位置 }); }區別存取DOM 變數 1-3.操作shopCart 元件
#
data (){ // 定义一个数组 来 控制小球的状态 定义多个对象,表示页面中做多同时运动的小球 return{ // 定义 5 个 小球 balls:[{show:false},{show:false},{show:false},{show:false},{show:false}], dropBalls:[] // 接收下落小球 } }
methods:{ balldrop(ele) { // console.log(el) 取到点击 对象 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; } } } }動畫過程開始,利用vue 提供的鉤子函數
beforeEnter (el){ //找到所以设为true的小球 let count=this.balls.length while(count--){ let ball = this.balls[count]; if(ball.show){ let pos=ball.el.getBoundingClientRect() //返回元素相对于视口偏移的位置 let x=pos.left-32 // 点击的按钮与小球(fixed)之间x方向的差值 let y=-(window.innerHeight-pos.top-22) el.style.display = ''; //设置初始位置前,手动置空,覆盖之前的display:none,使其显示 el.style.webkitTransform = `translate3d(0,${y}px,0)`; //外层元素做纵向的动画,y是变量 el.style.transform = `translate3d(0,${y}px,0)`; let inner = el.getElementsByClassName('inner_hook')[0];//内层元素做横向动画,inner-hook(用于js选择的样式名加上-hook,表明只是用 //于js选择的,没有真实的样式含义) 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(() => {//异步执行 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(); //取到做完动画的球,再置为false,即重置,它还可以接着被利用 if (ball) { ball.show = false; el.style.display = 'none'; } }
#
<p class="ball-container"> <p v-for="ball in balls"> <transition name="drop" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <p class="ball" v-show="ball.show"> <p class="inner inner_hook"></p> </p> </transition> </p> </p>
&.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
以上是Vue shopCart 元件開發實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!