konglingwen94 / vue-elm-seller Goto Github PK
View Code? Open in Web Editor NEW:shopping_cart:高仿饿了么商家店铺的单页面应用
Home Page: http://123.57.204.48:5000
:shopping_cart:高仿饿了么商家店铺的单页面应用
Home Page: http://123.57.204.48:5000
本篇文章从应用功能和技术实现一些方面剖析此项目的开发过程以及当中采到的坑,特此写下一篇总结文章。
前端
vue
开发项目核心框架axios
HTTP请求模块lib-flexible
移动端屏幕适配方案better-scroll
仿IOS
效果的移动端滚动库normalize.css
第三方css
样式初始化模块es 6/7
下一代javascript
语法后端
express
搭建服务端应用核心框架开发
vue-cli
项目初始化脚手架vue-devtools
项目开发环境调试工具vscode
chrome
git
macbookpro
部署
代码托管仓库
https://github.com/konglingwen94/vue-elm-sell线上地址
123.56.124.33:5000商品页
评论页
是否有内容的评论
商家页
bounce
效果的滑动显示应用头部
购物车
应用局部优化
bounce效果
是指在应用中页面位置滚动到一个端点继续滑动时出现反弹的效果,常见场景是IOS
系统应用滑动效果
完整的组件代码点https://github.com/konglingwen94/vue-elm-sell/blob/master/src/views/goods/index.vue。
由于商品导航和内容是两个独立的滚动容器,当滚动到一个目标内容块时怎么才能激活它所关联的导航项呢?我们知道导航项列表和内容列表在排列顺序上是一致的,如果能计算出内容滚动位置处在对应区间块的索引,也就得到了导航列表应该激活的目标索引,然后就可以用Vue
数据驱动视图的**去实现这一切。
容器的左右联动效果是指容器滚动到目标内容时激活其关联的导航菜单项并滚动到可视区域。
找到要激活的目标导航项索引的第一步需要把商品内容的各个类别块在容器内的纵坐标位置存储起来(给之后找到激活的目标索引提供比较对象),由于列表内容时动态渲染的,所以这里需要等所有数据已经渲染完成后才能操作,下面直接看代码演示吧!
template
部分
<template>
/* 这里只显示部分代码*/
<ul class="foods-list">
<li ref="foodsGroup" class="foods-group" v-for="(item,index) in data" :key="index">
<dl class="foods-group-wrapper">
<dt :class="{fixed:currentIndex===index}" class="foods-group-name">{{item.name}}</dt>
<dd
class="foods-group-item"
v-for="(food ,key) in item.foods"
:key="key"
>
{{food.name}}
</dd>
</dl>
</li>
</ul>
</template>
script
部分
export default {
data(){
return {
currentIndex: 0,//导航项激活的索引
currentFood: {},
data:[],
sectionHeight: [0],//第一个高度块坐标`y`值为`0`
// 渲染完成后的值为 `[0,1281,1459,1612,2000,2270,2565,2952,3574,4436]`
}
},
created() {
request
.get("/goods")
.then(response => {
this.data = response;
})
.then(() => {
setTimeout(() => {
const sections = this.$refs.foodsGroup;
sections.reduce((prevTotal, current) => {
const sectionHeight = prevTotal + current.clientHeight;
this.sectionHeight.push(sectionHeight);
return sectionHeight;
}, 0);
});
});
}
}
有了各个商品块的y
坐标,下一步就需要注册容器元素的滚动事件了,在回调函数里通过找到实时滚动位置disanceY
处在sectionHeight
数组中两个相邻元素之间的位置从而就得到了待激活导航索引currentIndex
的值,具体代码实现如下
<template>
<div>
<!--导航菜单-->
<scroll class="menu">
<ul class="menu-list">
<li
@tap="selectMenu(index)"
class="menu-item"
:class="{selected:currentIndex===index}"
v-for="(item,index) in data"
:key="index"
>
<span>{{ item.name}}</span>
</li>
</ul>
</scroll>
<!--商品内容-->
<scroll ref="foodsScroll" @scroll="onFoodScroll" class="foods">
<!--这里省略商品内容模板的代码-->
</scroll>
</div>
</template>
export default {
// 这里省略其他代码
methods:{
onFoodScroll({ x, y }) {
const distanceY = Math.abs(Math.round(y));
for (let index = 0; index < this.sectionHeight.length; index++) {
if (
distanceY >= this.sectionHeight[index] &&
distanceY < this.sectionHeight[index + 1]
) {
this.currentIndex = index;
}
}
}
}
}
完整的组件代码点https://github.com/konglingwen94/vue-elm-sell/blob/master/src/views/goods/index.vue。由于左右两侧的布局容器都是基于
better-scroll
实现的页面滚动,所以这里需要侦听better-scroll
提供的scroll
事件而不是浏览器原生的滚动事件。查看better-scroll
的scroll
事件API
点这里。
完整代码https://github.com/konglingwen94/vue-elm-sell/blob/master/src/components/food-picker/index.vue
添加商品到购物车是一个多场景的功能,由于这里的购物车功能是一个多页面联动的效果,购物车商品数量的实时更改也需要同步到商品内容页和商品详情页。从功能映射到javascript
语言数据结构层面的话,不难想到对象引用传递的特点可以作为实现此功能的底层架构思路,那就让我们去实现它吧。
为了统计商品的数量。首先需要给每一个商品信息对象添加一个默认值为0
的count
属性,添加后的对象长这样
{
"count": 0, // 此变量用来存储添加到购物车的数量
"name": "皮蛋瘦肉粥",
"price": 10,
"oldPrice": "",
"description": "咸粥",
"sellCount": 229,
"rating": 100,
"info": "一碗皮蛋瘦肉粥,总是我到粥店时的不二之选。香浓软滑,饱腹暖心,皮蛋的Q弹与瘦肉的滑嫩伴着粥香溢于满口,让人喝这样的一碗粥也觉得心满意足",
"ratings": [
{
"username": "3******b",
"rateTime": 1469261964000,
"rateType": 1,
"text": "",
"avatar": "http://static.galileo.xiaojukeji.com/static/tms/default_header.png"
}
],
"icon": "http://fuss10.elemecdn.com/c/cd/c12745ed8a5171e13b427dbc39401jpeg.jpeg?imageView2/1/w/114/h/114",
"image": "http://fuss10.elemecdn.com/c/cd/c12745ed8a5171e13b427dbc39401jpeg.jpeg?imageView2/1/w/750/h/750"
}
由于每一个商品项都有一个添加到购物车的数量选择器功能,这样我们直接给商品数量选择器组件设计一个名为foodInfo
的对象类型props
,这样在增加/减少商品数量的时候直接操作foodInfo
的count
属性来实现同步数据的效果。
<template>
<div class="food-picker" @click.stop>
<div class="reduce-wrapper" @click="reduce">
<i class="iconfont reduce"></i>
</div>
<div class="counter">{{foodInfo.count}}</div>
<div class="add-wrapper" @click="add">
<i class="iconfont add"></i>
</div>
</div>
</template>
<script>
export default {
name: "food-picker",
props: {
foodInfo: {
type: Object,
default: () => ({})
}
},
methods: {
reduce() {
if (parseInt(this.foodInfo.count) > 0) {
this.foodInfo.count--;
}
},
add() {
this.foodInfo.count++;
}
}
};
</script>
<style lang="less" scoped>
.food-picker {
min-width: 180px;
max-width: 200px;
display: flex;
align-items: center;
width: 100%;
justify-content: space-between;
.iconfont {
color: #00a0dc;
font-size: 38px;
}
.counter {
// margin: 0 20px;
}
}
</style>
基于目前已经实现的功能,整个应用的数据都是以json
文件的格式存储在服务器,服务端并没有可以用来增删改查的API
接口可供使用。下一步我计划做出管理后台和服务端API
用来管理前端页面的数据,使所有模块的数据都是可配置的,这样前端所渲染出来的数据也都是动态的,能够整合三端到一个项目也满足了当下Web
全栈开发的场景需要。
通过真实的开发这样一个复杂交互的应用,自己对Vue
在实际业务场景中的使用和理解有深入了一步。深入理解了Vue
的数据驱动视图改变的**,熟练的掌握了组件化开发项目的流程,同时也感受到所带来的便利,为自己接下来预备做的中大型项目建筑好了桥梁。
如果本项目对您学习有帮助,请您动手点个star
https://github.com/konglingwen94/vue-elm-sell。也希望您继续关注我的动态https://github.com/konglingwen94,有了您的支持我会有动力开源更多有趣的项目。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.