说明:本总结来源于慕课网 @ustbhuangyi老师的课程《Vue.js2.5+cube-ui重构饿了么App》课程,本博客做了项目总结梳理便于回顾,需要学习的伙伴可以移步学习。与君共勉! 之前章节传送: 项目总结:vue.js2.5饿了么APP(1)概述+项目准备 项目总结:vue.js2.5饿了么APP(2)主要组件实现 – 头部 Goods组件是整个项目最复杂的部分。有一个商品列表,可以显示商品的分类,左右是可以联动的,底部有一个购物车组件。购物车组件主要包含(shop-cart ,shop-control , shop-cart-list , shop-cart-sticky)4个部分,本节主要讲解前两个 。 速看 1. scroll-nav组件 使用cube-ui提供的scroll-nav简化了better-scroll的使用,实现左右联动显示分类显示,当点击某一栏会高亮显示,右侧商品列表详细显示在拖动时回有吸附效果。 2. shop-cart组件 购物车shop-cart组件有多种状态:(1)没有购买商品时,购物车全部灰色(2)当购买商品时,购物车右上角回有商品件数,并且会按照商品计算出价格,(3)当达到配送金额会显示“去结算”,不然就显示“还差XX元起送”。其中对于购物车的设计主要使用了flex布局主要维护选择的商品。 Seller会在goods中声明成计算属性。Goods组件会接收一些tab组件传入的props,而tab的数据也是从app.vue中传入的。因此当动态获取seller之后props的获取是一个响应式的,可以一层层通过tab达到goods组件。 3. shop-control组件 主要分为三个部分(减号 数字 加号),其中点击加号会触发两个动画:(1)cart-control组件的渐出,(2)购物车小球下落动画。 对于(1):首先,使用v-show控制组件只有商品件数大于零显示。每个按钮维护一个food,并且对于按钮点击绑定add()和decease()事件用于记录商品的数量count。同时在父组件goods中维护计算属性selectFood(),用于计算商品数量,父组件将selectfood作为props传入shop-cart,从而实现两个兄弟组件之间的数据交互。对于过渡动画,使用<transition>组件通过v-show驱动。外层偏移内层rotate滚动,从而实现一边偏移一边滚动的渐出效果显示。 对于(2):想象购物车里面有很多隐藏的小球,点击按钮,小球会变到当前点击位置并显示,然后经过一个动画飞入购物车,并且支持多个小球同时在动画。首先定义balls数组用于存放所有小球,属性show默认设置为false。并在shop-cart中定义小球容器,v-show遍历小球,拿到true的小球做动画。并监听几个vue的钩子函数before-enter ,enter ,after-enter来做动画。在beforedrop中拿到点击的位置,并将购物车中的小球显示在该位置。在dropping中触发重绘reflow,并让做动画回到原来位置,从而实现小球下落,动画之后监听transtionend事件,触发afterDrop,修改小球show显示状态为false,回收小球,并将小球元素display设置为null。从而实现了一次小球下落。 目录 使用cube-ui提供的scroll-nav简化了better-scroll的使用,实现左右联动显示分类显示,当点击某一栏会高亮显示,右侧商品列表详细显示在拖动时回有吸附效果。 最外层是一个两栏布局。左侧栏是商品的分类,右侧就是每个分类具体有哪些商品内容。左侧固定宽高,右侧自适应。(flex布局),对于显示:如果超出页面内容会被隐藏,可以实现滚动(position:absolute)。 cube-ui的ScrollNav组件实现左右联动显示分类显示,当点击某一栏会高亮显示,右侧商品列表详细显示在拖动时回有吸附效果。 scroll-nav提供了默认插槽,<cube-scroll-nav-panel>可以写内部的内容。 对于<cube-scroll-nav>可以传入props,把goods传入data,click设置为false,是因为每一个scroll都会派发事件,可能会出现嵌套从而事件触发两次(也可以使用stop.propegation)。 本来是会在created或者mounted生命周期获取,但是这里任何一个声明周期都是不合适的。在评价页面下无需请求商品和商家页面数据,是一种浪费。因此希望数据的请求是在tab切换到该页面时做,其实就是之前的onchange事件在goods组件内部获取数据。Fetch方法是在tab下的onchange中调用。 购物车shop-cart组件有多种状态:(1)没有购买商品时,购物车全部灰色(2)当购买商品时,购物车右上角回有商品件数,并且会按照商品计算出价格,(3)当达到配送金额会显示“去结算”,不然就显示“还差XX元起送”。其中对于购物车的设计主要使用了flex布局主要维护选择的商品。 Seller会在goods中声明成计算属性。Goods组件会接收一些tab组件传入的props,而tab的数据也是从app.vue中传入的。因此当动态获取seller之后props的获取是一个响应式的,可以一层层通过tab达到goods组件。 分为左块(logo+price+des)和右块(pay),右边的部分宽度固定,左侧自适应的flex布局。左侧有一个购物车logo,显示总金额,配送费部分 右侧结算。 购物车有多种状态:(1)没有购买商品时,购物车全部灰色(2)当购买商品时,购物车右上角回有商品件数,并且会按照商品计算出价格,(3)当达到配送金额会显示“去结算”,不然就显示“还差XX元起送”。 另外当购物车不为空时点击购物车会弹出浮层,显示购买的商品,也可以清空购物车,或者在里面添加或者删除商品。 其中logo相对于父元素有超出的部分,因此需要设置宽度和定位。使用relative,并设置top: -10px。 box-sizing: border-box,圆角设置border-radius:50% 在goods组件中引入,并做一些绑定。 Seller会在goods中声明成计算属性。Goods组件会接收一些tab组件传入的props,而tab的数据也是从app.vue中传入的。因此当动态获取seller之后props是一个响应式的,可以一层层通过tab达到goods组件。 购物者主要要维护选择的商品。通过props传入。SelectFoods表示已选择的商品,是通过用户选择动态获取的,还有配送费delivery Price和最小起送费minPrice,这两个是直接可以从后台数据拿到。 1) totalPrice是商品总和,遍历所选择的商品,拿到商品的价格和数量计算而得。 2)TotalCount是计算商品的总数量,便于显示在购物车部分。 3) payDesc是对于支付的描述:根据totalprice计算,有三种状态(当价格为空,显示“起送价”;当商品总价小与最小起送价,显示“还差XX起送”;其他,显示“去结算”) 4)PayClass当右边的按钮到达结算状态会被点亮,因而控制class的样式显示。 shop-control组件主要分为三个部分(减号 数字 加号),其中点击加号会触发两个动画:(1)cart-control组件的渐出,(2)购物车小球下落动画。 对于(1):首先,使用v-show控制组件只有商品件数大于零显示。每个按钮维护一个food,并且对于按钮点击绑定add()和decease()事件用于记录商品的数量count。同时在父组件goods中维护计算属性selectFood(),用于计算商品数量,父组件将selectfood作为props传入shop-cart,从而实现两个兄弟组件之间的数据交互。对于过渡动画,使用<transition>组件通过v-show驱动。外层偏移内层rotate滚动,从而实现一边偏移一边滚动的渐出效果显示。 主要分为三个部分(减号 数字 加号)减号部分有一个过渡动画 v-show控制显示,当商品大于零才会显示。 对于每个按钮都会接收和维护一个food,当点击添加时触发add(),修改count值(对于vue来说count是我们自己定义的变量,不是data.json的,因此使用要用this.$set()赋值,而不能直接使用this.food.count++)同理decrease()做减法 同时goods中需要维护一个计算属性selectFood(),遍历goods对于每一个good下面的food,判断商品数量,从而可以拿到已选商品数组。并将selectfood并且作为props传入shop-cart。(详细可以查看上面购物车组件代码) 一期:有两个方位的滚动,基础组件要有一个内层组件,外层组件负责平移,内层组件负责滚动。所有的动画都会基于vue的transition过渡动画。添加transition=move 使用transform:translate3D(0,0,0)(3D可以开启硬件加速使得动画更加流畅)transition 0.4s 线性缓动 对于inner的transform:rotate(0) 二期:使用<transition>组件name=’’move’通过v-show驱动。对于外层会有一个偏移操作,内层是一个span会有一个rotate滚动效果,从而实现一边偏移一边滚动的渐出效果显示 点击shop-control组件的加号会触发两个动画:(1)cart-control组件的渐出,(2)购物车小球下落动画。 对于(2):设计思路:想象购物车里面有很多隐藏的小球,点击按钮,小球会变到当前点击位置并显示,然后经过一个动画飞入购物车,并且支持多个小球同时在动画。首先定义balls数组用于存放所有小球,属性show默认设置为false。并在shop-cart中定义小球容器,v-show遍历小球,拿到true的小球做动画。并监听几个vue的钩子函数before-enter ,enter ,after-enter来做动画。在beforedrop中拿到点击的位置,并将购物车中的小球显示在该位置。在dropping中触发重绘reflow,并让做动画回到原来位置,从而实现小球下落,动画之后监听transtionend事件,触发afterDrop,修改小球show显示状态为false,回收小球,并将小球元素display设置为null。从而实现了一次小球下落。 问题(1)小球是根据按钮的位置处飞入,落点是购物车(2)连续点击小球动画是不会断的,可以有多个小球在页面上显示。 思路:想象小球都放在购物车里,里面有很多隐藏的小球,点击某一个按钮时,小球会变到当前点击位置,并显示,然后经过一个动画飞入购物车。并且支持多个小球同时存在。 首先,点击cart-control触发事件,需要知道按钮的DOM元素。 定义一个事件EVENT_ADD=add,触发一个事件,派发到DOM元素,通过event.target可以拿到按钮。 之后可以在外层goods组件中的<cart-control>监听到事件@onAdd,从而驱动购物车做小球飞入。 并且修改goods组件中的onAdd(),在函数中驱动drop()方法 在购物车shop-cart中定义一个方法drop() ,接收el也就是DOM元素,(按钮的位置)。 在goods组件中,拿到shop-cart的引用,添加ref=”shopCart”,并且修改goods组件中的onAdd(),在函数中驱动drop()方法。 因此就完成了点击按钮,驱动shop-cart组件的下落动画。 1)首先,需要购物车中放入一些隐藏的小球。因此,在shop-cart组件中的data中添加一些ball,数组中是对象小球以及状态。 2)定义一个辅助函数CreateBalls,向数组中Push放入小球对象,小球的属性show的默认值为false,并返回数组。 在shop-cart组件中定义小球容器ball-container,使用fixed布局,内部<div>遍历ball。 使用transition驱动过渡动画(外层下落ball,内层平移inner)。使用v-show遍历小球,默认小球全都是隐藏的。监听几个vue的钩子函数before-enter enter after-enter。 1)当调用drop时(shop-cart组件中的方法),会驱动小球的transition过渡。因此需要遍历小球数组,找到第一个隐藏的小球,显示状态修改为true,并且保存按钮DOM到ball。 2)此时,还需要一个下落的小球数组dropBalls。因此,在钩子函数created中定义数组dropballs保存正在下落的小球,把隐藏的小球放到下落小球里面。(不放在data中的原因:不需要响应式的) 3)然后通过v-show驱动过渡,需要在<transition>中监听几个钩子函数@before-enter @enter @after-enter,然后写一下几个钩子函数。 当我们点击按钮会触发shop-cart组件的drop方法,从小球中拿到隐藏小球,修改其状态为true,并且放在下落小球的数组drop Balls中。 1)钩子函数beforedrop,从dropBalls中拿到当前正在做过渡的元素,找到最新的正在下落的小球(最后一个,因为每次点击都会push一个,因此数组中最后一个就是最新的),拿到小球后就知道了对应的元素,即可以求按钮的位置。计算需要偏移的xy,写transform。此时需要把小球从购物车放在点击DOM处。在外层移动y内层移动x。(使用webkit为了兼容低安卓版本) 2)钩子函数dropping 需要触发重绘reflow,做动画回到原来位置 动画之后监听transtionend事件,当动画完成之后执行done, 告诉<transition组件>动画执行结束,从而触发afterDrop 3)钩子函数afterDrop 动画完成之后,可以从dropBalls中拿到最新的ball(队列shift),修改show显示状态为false,回收小球,将display设置为null。 该组件就是一个在购物车上方的小球,主要的props就是num
一、scroll Nav组件
1. 概括
2. 布局
<div class="goods"> <div class="scroll-nav-wrapper"> <cube-scroll-nav> <template slot="bar" slot-scope="props"> <cube-scroll-nav-bar <template slot-scope="props"> <div class="text"> <support-ico></support-ico> <span><bubble :num="props.txt.count"></bubble></span> </div> </template> </cube-scroll-nav-bar> </template> <cube-scroll-nav-panel> <div class="icon"></div> <div class="content"> <div class="cart-control-wrapper"><cart-control></cart-control></div> </div> </cube-scroll-nav-panel> </cube-scroll-nav> </div> <div class="shop-cart-wrapper"> <shop-cart></shop-cart> </div> </div>
3. 实现
(1)组件传值
props: { data: { type: Object, default() { return {} } } }, data() { return { goods: [], selectedFood: {}, scrollOptions: { click: false, directionLockThreshod: 0 } } },
(2)动态获取Goods数据
fetch() { if (!this.fetched) { this.fetched = true getGoods().then((goods) => { this.goods = goods }) } }, methods: { onChange(current) { this.index = current const component = this.$refs.component[current] component.fetch && component.fetch() }, }
二、购物车shop-cart组件
1. 概括
2. 布局
<template> <div> <div class="shopcart"> <div class="content" > <div class="content-left"> <div class="logo-wrapper"> <div class="logo" :class="{'highlight':totalCount>0}"></div> </div> <div class="price" >¥{{totalPrice}}</div> <div class="desc">另需配送费¥{{deliveryPrice}}元</div> </div> <div class="content-right"> <div class="pay">{{payDesc}}</div> </div> </div> <div class="ball-container"></div> </div> </div> </template>
3. 实现
(1)页面样式
(2)组件引入
<div class="shop-cart-wrapper"> <shop-cart ref="shopCart" :select-foods="selectFoods" :delivery-Price="seller.deliveryPrice" :min-price="seller.minPrice"> </shop-cart> </div>
computed: { seller() { return this.data.seller },
props: { selectFoods: { type: Array, default() { return [] } }, deliveryPrice: { type: Number, default: 0 }, minPrice: { type: Number, default: 0 }, }
(3)计算属性
totalPrice() { let total = 0 this.selectFoods.forEach((food) => { total += food.price * food.count }) return total }, totalCount() { let count = 0 this.selectFoods.forEach((food) => { count += food.count }) return count },
payDesc() { if (this.totalPrice === 0) { return `¥${this.minPrice}元起送` } else if (this.totalPrice < this.minPrice) { const diff = this.minPrice - this.totalPrice return `还差¥${diff}元起送` } else { return '去结算' } }, payClass() { if (!this.totalCount || this.totalPrice < this.minPrice) { return 'not-enough' } else { return 'enough' } }
三、购物车cart-control组件
1. 概括
2. 布局
<div class="cartcontrol"> <transition name="move"> <div class="cart-decrease" v-show="food.count>0" @click.stop="decrease"> <span class="inner icon-remove_circle_outline"></span> </div> </transition> <div class="cart-count" v-show="food.count>0">{{food.count}}</div> <div class="cart-add icon-add_circle" @click.stop="add"></div> </div>
3. 实现
(1)添点击事件
props: { food: { type: Object } }, methods: { add(event) { if (!this.food.count) { this.$set(this.food, 'count', 1) } else { this.food.count++ } this.$emit(EVENT_ADD, event.target) }, decrease() { if (this.food.count) { this.food.count-- } } }
(2)组件传值和使用
selectFoods() { const ret = [] this.goods.forEach((good) => { good.foods.forEach((food) => { if (food.count) { ret.push(food) } }) }) return ret },
(3)过渡动画的实现
.cart-decrease display: inline-block padding: 6px opacity: 1 .inner display: inline-block line-height: 24px font-size: $fontsize-large-x color: $color-blue transition: all 0.4s linear transform: rotate(0) &.move-enter-active, &.move-leave-active transition: all 0.4s linear &.move-enter, &.move-leave-active opacity: 0 transform: rotate(180deg)
四、购物车小球飞入动画
1. 概括
2. 实现
(1)获取按钮位置
add(event) { if (!this.food.count) { this.$set(this.food, 'count', 1) } else { this.food.count++ } this.$emit(EVENT_ADD, event.target) },
(2)添加动画触发函数
<div class="cart-control-wrapper"> <cart-control @add="onAdd" :food="food"></cart-control> </div>
onAdd(target) { this.$refs.shopCart.drop(target) },
(3)购物车组件中添加drop方法
drop(el) { for (let i = 0; i < this.balls.length; i++) { const ball = this.balls[i] if (!ball.show) { ball.show = true ball.el = el this.dropBalls.push(ball) return } } },
<shop-cart ref="shopCart" :select-foods="selectFoods" :delivery-Price="seller.deliveryPrice" :min-price="seller.minPrice"> </shop-cart>
(4)实现drop()方法 – 添加小球
const BALL_LEN = 10 const innerClsHook = 'inner-hook' data() { return { balls: createBalls(), listFold: this.fold } },
function createBalls() { const ret = [] for (let i = 0; i < BALL_LEN; i++) { ret.push({ show: false }) } return ret }
(5)实现drop()方法 – 添加小球容器
<div class="ball-container"> <div v-for="(ball, index) in balls" :key="index"> <transition @before-enter="beforeDrop" @enter="dropping" @after-enter="afterDrop"> <div class="ball" v-show="ball.show"> <div class="inner inner-hook"></div> </div> </transition> </div> </div>
(6)实现drop()方法
drop(el) { for (let i = 0; i < this.balls.length; i++) { const ball = this.balls[i] if (!ball.show) { ball.show = true ball.el = el this.dropBalls.push(ball) return } } },
created() { this.dropBalls = [] },
<transition @before-enter="beforeDrop" @enter="dropping" @after-enter="afterDrop"> <div class="ball" v-show="ball.show"> <div class="inner inner-hook"></div> </transition>
(7)几个钩子函数的实现
// const innerClsHook = 'inner-hook' beforeDrop(el) { const ball = this.dropBalls[this.dropBalls.length - 1] const rect = ball.el.getBoundingClientRect() const x = rect.left - 32 const y = -(window.innerHeight - rect.top - 22) el.style.display = '' el.style.transform = el.style.webkitTransform = `translate3d(0, ${y}px, 0)` const inner = el.getElementsByClassName(innerClsHook)[0] inner.style.transform = inner.style.webkitTransform = `translate3d(${x}px, 0, 0)` },
dropping(el, done) { this._reflow = document.body.offsetHeight el.style.transform = el.style.webkitTransform = 'translate3d(0, 0, 0)' const inner = el.getElementsByClassName(innerClsHook)[0] inner.style.transform = inner.style.webkitTransform = 'translate3d(0, 0, 0)' el.addEventListener('transitionend', done) },
afterDrop(el) { const ball = this.dropBalls.shift() if (ball) { ball.show = false el.style.display = 'none' } },
五、Bubble组件
<template> <span class="bubble">{{ num }}</span> </template> <script> export default { name: 'bubble', props: { num: { type: Number } } } </script>
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算