首页 > web前端 > js教程 > Vue shopCart 组件开发实例详解

Vue shopCart 组件开发实例详解

小云云
发布: 2018-01-31 10:10:32
原创
1708 人浏览过

本文主要和大家介绍Vue shopCart 组件开发详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。

一、shopCart组件

(1) goods 父组件和 子组件 shopCart 传参


1

2

3

4

5

6

7

8

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 的父组件)


1

2

3

<keep-alive>

 <router-view :sell="sellerObj"></router-view>

</keep-alive>

登录后复制

注意:sellerObj 是data 定义 的 对象里用来接收 data.json 数据,相当于 实参

1-2.goods.vue (相对于跟组件的子组件 且 shopCart 的父组件)

通过props 属性 进行组件之间的通信


1

2

3

props: {

  sell: Object // 相当于 形参

 },

登录后复制

1-3.shopCart.vue ( goods 的子组件)


1

<shopCart :delivery-price="sell.deliveryPrice" :min-price="sell.minPrice"></shopCart>

登录后复制

(2) 选中商品 的 计算功能

1-1. 传入用户选中商品的集合

说明:从父组件会 传入一个用户选中商品的 数组,数组里会存放着 n 个对象,每个对象里存放着该 商品的 价格 和 数量。


1

2

3

4

5

6

7

props:{       // 通过父组件传过来的 ( 相当于形参 )

 selefoodsArr:{   // 用户选中的商品存放在一个数组里  接收的是 data.json数据的 goods(数组)

 type:Array, // 当父组件传过来的 类型是对象或者 是数组时, default 就是一个函数

 default (){

 return []  // 返回数组 存放着选中 商品 对应的 goods下的 foods 数组(由 父组件 的 实参 决定的返回值)

 }

}

登录后复制

1-2. 利用计算属性 选中商品数量的变化,商品总价,动态改变描述等功能


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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 &#39;去结算&#39;

    }

 

}

登录后复制

这样就渲染到 template 里了


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

<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="{&#39;active&#39;:totalCount}">

   <i class="icon-shopping_cart"></i>

  </p>

 </p>

 <!--同理: 总价 不为0 字体高亮-->

 <p class="price" :class="{&#39;active&#39;:totalPrice}">

  ¥{{totalPrice}}

 </p>

 <!--配送费 data.json 提供-->

 <p class="desc">

  另需要配送费¥{{deliveryPrice}}元

 </p>

  </p>

  <!--根据条件  动态 改变样式-->

  <p class="content-right" :class="{&#39;enough&#39;:totalPrice>=minPrice}"

 {{payDesc}} 

 </p>

 </p>

</p>

登录后复制

相关样式


1

2

3

4

5

6

&.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值(遍历选中的商品时使用)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

methods:{

 addCart(event){ // 点击count 加,

  //console.log(event.target);

 if (!event._constructed) { // 去掉自带click事件的点击

    return;

   }

 if(!this.foodsele.count){

 Vue.set(this.foodsele, &#39;count&#39;, 1)

 }else{

 this.foodsele.count++

 

 },

 decreaseCart (event){ // 点击减少

 if (!event._constructed) { // 去掉自带click事件的点击

    return;

    }

 if(this.foodsele.count){

 this.foodsele.count --

  }

  }

}

登录后复制

(2)添加按钮 实现transtion 过渡

我们要实现的效果是:当点击添加按钮时,减少按钮出现 并伴随着 旋转、平移以及透明度变化的 一些 动画效果


1

2

3

4

5

<transition name=&#39;move&#39;> <!--平移动画--> 

 <p class="cart-decrease" v-show="foodsele.count" @click=&#39;decreaseCart($event)&#39;>

  <span class="icon-remove_circle_outline inner"></span><!--旋转、透明度动画-->

  </p>

</transition>

登录后复制


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

.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组件间传递

  1. 使用$on()监听事件;

  2. 使用$emit()在它上面触发事件;

  3. 使用$dispatch()派发事件,事件沿着父链冒泡;

  4. 使用$broadcast()广播事件,事件向下传导给所有的后代

(1) Vue2.0 组件之间传递数据

1-1. 当点击 添加数量时 在 cartControl 组件里的 addCount 方法里 通过 $emit 属性 派发一个事件 , 传入点击的对象


1

2

3

4

5

6

7

8

9

10

11

12

13

14

addCart(event){ // 点击count 加,

//  console.log(event.target);

 if (!event._constructed) { // 去掉自带click事件的点击

    return;

   }

 if(!this.foodsele.count){

 Vue.set(this.foodsele, &#39;count&#39;, 1)

 }else{

 this.foodsele.count++

 }

// 当点击 添加数量时 通过 $emit 属性 提交一个名为 add 给父组件

// 子组件通过 $emit触发 add事件 ,将参数传递给父组件

 this.$emit(&#39;add&#39;, event.target);

}

登录后复制

1-2. 操作 goods 组件

购物车组件如果提交了addCart事件就调用add函数


1

<cart-control :foodsele=&#39;food&#39; @add="addFood"></cart-control>

登录后复制

父组件使用 @add="addFood"监听由子组件vm.$emit触发的事件,通过addFood()接受从子组件传递过来的数据,通知父组件数据改变了。


1

2

3

addFood(target) {

  this._drop(target);

}

登录后复制

1-3. 父组件访问子组件 vue 提供了接口 ref

复制代码 代码如下:




1

2

3

4

5

6

_drop(target) {

  // 体验优化,异步执行下落动画

  this.$nextTick(() => {

   this.$refs.shopCart.balldrop(target);// 将target传入shopCart子组件中的balldrop方法,所以drop方法能获得用户点击按钮的元素,即能获取点击按钮的位置

  });

}

登录后复制

区别 访问DOM 变量

1-3. 操作 shopCart 组件


1

2

3

4

5

6

data (){ // 定义一个数组 来 控制小球的状态  定义多个对象,表示页面中做多同时运动的小球

 return{ // 定义 5 个 小球 

 balls:[{show:false},{show:false},{show:false},{show:false},{show:false}],

 dropBalls:[] // 接收下落小球

  }

}

登录后复制


1

2

3

4

5

6

7

8

9

10

11

12

13

14

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 提供的钩子函数


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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 = &#39;&#39;;  //设置初始位置前,手动置空,覆盖之前的display:none,使其显示

       el.style.webkitTransform = `translate3d(0,${y}px,0)`; //外层元素做纵向的动画,y是变量

       el.style.transform = `translate3d(0,${y}px,0)`;

       let inner = el.getElementsByClassName(&#39;inner_hook&#39;)[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 = &#39;translate3d(0,0,0)&#39;;  //重置回来

   el.style.transform = &#39;translate3d(0,0,0)&#39;;

   let inner = el.getElementsByClassName(&#39;inner_hook&#39;)[0];

   inner.style.webkitTransform = &#39;translate3d(0,0,0)&#39;;

   inner.style.transform = &#39;translate3d(0,0,0)&#39;;

  });

 },

 afterEnter(el) {

  let ball = this.dropBalls.shift(); //取到做完动画的球,再置为false,即重置,它还可以接着被利用

  if (ball) {

   ball.show = false;

   el.style.display = &#39;none&#39;;

  }

 }

登录后复制


1

2

3

4

5

6

7

8

9

<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>

登录后复制


1

2

3

4

5

6

7

8

&.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 header组件开发实例代码

Vue组件及数据传递详解

vuejs使用递归组件实现树形目录

以上是Vue shopCart 组件开发实例详解的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板