提交 d400165a 编写于 作者: C cangdu 提交者: GitHub

Merge pull request #43 from wahyd4/master

 登陆  => 登录
# 前言
初学vue时曾在网上搜索vue的实战项目源码,无奈大部分都是简单的demo,对于深究vue没有太大的帮助,剩下的一些大部分都是像音乐播放器之类的展示型项目,交互没有预期那么复杂。但我们实际在工作中,经常会遇到有购物车的项目,这类项目因为涉及到money,所以对逻辑严谨度要求高,页面之间交互复杂,又会伴随着登、注册、用户信息等等,常常会让我们很头疼。既然还没人用vue写过这样的项目,那不如我来写,开源出来对能看到的人也会有帮助。
初学vue时曾在网上搜索vue的实战项目源码,无奈大部分都是简单的demo,对于深究vue没有太大的帮助,剩下的一些大部分都是像音乐播放器之类的展示型项目,交互没有预期那么复杂。但我们实际在工作中,经常会遇到有购物车的项目,这类项目因为涉及到money,所以对逻辑严谨度要求高,页面之间交互复杂,又会伴随着登、注册、用户信息等等,常常会让我们很头疼。既然还没人用vue写过这样的项目,那不如我来写,开源出来对能看到的人也会有帮助。
这种功能性的项目很实用但是往往也很枯燥,没有音乐播放器那么看起来绚丽,思来想去发现饿了么是一个不错的素材,一来它足够复杂,开放的外卖平台比一般的公司独有商店更加复杂。二来 见到那么多美食,大家也不会感觉到厌烦。
为啥是饿了么,而不是百度,美团?原因很简单,三个外卖大佬里,饿了么的色调和布局是最漂亮的,看起来最舒服。
此项目大大小小共 45 个页面,涉及注册、登、商品展示、购物车、下单等等,是一个完整的流程。一般公司即便是官网的单页面项目都没这么复杂,如果这个项目能驾驭的了,相信大部分公司的其他单页面应用也就不在话下,即便更复杂,也不会比这个高到哪里去。
此项目大大小小共 45 个页面,涉及注册、登、商品展示、购物车、下单等等,是一个完整的流程。一般公司即便是官网的单页面项目都没这么复杂,如果这个项目能驾驭的了,相信大部分公司的其他单页面应用也就不在话下,即便更复杂,也不会比这个高到哪里去。
因为利用业余时间来做,年前就开始写,又跨个年,周期有点长,项目从零布局到完成共用了2个多月的时间,目前项目已经完成,正在进行一些性能的优化,增加详细的注释。
......@@ -24,7 +24,7 @@ vue2 + vuex + vue-router + webpack + ES6/7 + fetch + sass + flex + svg
# 项目运行
#### 注意:由于涉及大量的 ES6/7 等新属性,nodejs 必须是 6.0 以上版本 ,node 7 是先行版,有可能会出问题,建议使用 node 6 稳定版
#### 注意:由于涉及大量的 ES6/7 等新属性,nodejs 必须是 6.0 以上版本 ,node 7 是先行版,有可能会出问题,建议使用 node 6 稳定版
```
git clone https://github.com/bailicangdu/vue2-elm.git  
......@@ -75,7 +75,7 @@ npm run build
# 关于 demo 与 数据 的说明🤔
1、下载代码运行后,因为开启了反向代理,可以获取真实的官方数据,最终可以进行下单(真实的下单,而不是模拟,下单后可以在官方App中查看并付款,亲自试过,且成功付款点餐),但是为了安全起见,登的帐号为固定的帐号,以免泄露个人信息,不过照样可以点餐。
1、下载代码运行后,因为开启了反向代理,可以获取真实的官方数据,最终可以进行下单(真实的下单,而不是模拟,下单后可以在官方App中查看并付款,亲自试过,且成功付款点餐),但是为了安全起见,登的帐号为固定的帐号,以免泄露个人信息,不过照样可以点餐。
2、demo的数据为模拟的固定数据,只做为效果演示,因为反向代理必须在PC端运行代码才行。
......@@ -85,7 +85,7 @@ npm run build
#### (demo使用的是模拟数据,数据是固定的,只做为样式的演示,要获取真实的数据,请clone代码并运行);
[查看demo请戳这里](http://test.fe.ptdev.cn/elm/)(请用chrome手机模式预览)
### 移动端扫描下方二维码
![](https://github.com/bailicangdu/vue2-elm/blob/master/screenshots/elm_ewm.png)
......@@ -106,7 +106,7 @@ npm run build
- [x] 店铺评价页面 -- 完成
- [x] 单个食品详情页面 -- 完成
- [x] 商家详情页 -- 完成
- [x] 登、注册 -- 完成
- [x] 登、注册 -- 完成
- [x] 修改密码 -- 完成
- [x] 个人中心 -- 完成
- [x] 发送短信、语音验证 -- 完成
......@@ -119,7 +119,7 @@ npm run build
- [x] 服务中心 -- 完成
- [x] 红包 -- 完成
- [x] 上传头像 -- 完成
- [ ] 付款 -- 臣妾做不到啊~~
- [ ] 付款 -- 臣妾做不到啊~~
......@@ -131,7 +131,7 @@ npm run build
3、vue因其轻量级的框架在中小型项目中表现亮眼,在大型单页面应用中因为vuex的存在,表现依然出色,在处理复杂交互逻辑的时候,vuex的存在是不可或缺的。所以说利用 vue + vuex 完全可以去做大型的单页面项目。
4、项目写到现在,从 登注册到、首页、搜索、商家列表、购物车、下单、订单列表、个人中心 一个流程走完之后、不但对vue的理解更深一层,而且对以后掌控大型项目的时候也有非常多的帮助,做一个实际的项目才能对自己有很大的提升。
4、项目写到现在,从 登注册到、首页、搜索、商家列表、购物车、下单、订单列表、个人中心 一个流程走完之后、不但对vue的理解更深一层,而且对以后掌控大型项目的时候也有非常多的帮助,做一个实际的项目才能对自己有很大的提升。
5、曾一度怀疑,花几个月的时间做这样一个项目到底有没有意义,本来只是想做一个小项目练练手,没想到后来越写越多,不过坚持下来后我相信一切都是值得的。
......@@ -186,7 +186,7 @@ npm run build
<img src="https://github.com/bailicangdu/vue2-elm/blob/master/screenshots/search.gif" width="365" height="619"/>
### 登
### 登
<img src="https://github.com/bailicangdu/vue2-elm/blob/master/screenshots/login1.png" width="365" height="619"/>
<img src="https://github.com/bailicangdu/vue2-elm/blob/master/screenshots/login.gif" width="365" height="619"/>
......@@ -224,17 +224,17 @@ npm run build
| |-- mUtils.js // 常用的js方法
| |-- rem.js // px转换rem
| |-- images // 公共图片
| |-- pages
| |-- pages
| |-- balance // 余额页
| |--children
| |--detail // 余额说明
| |-- benefit // 红包页
| |--children
| |--commend // 推荐有奖
| |--coupon // 代金券说明
| |--exchange // 兑换红包
| |--hbDescription // 红包说明
| |--hbHistory // 历史红包
| |--coupon // 代金券说明
| |--exchange // 兑换红包
| |--hbDescription // 红包说明
| |--hbHistory // 历史红包
| |-- city // 当前城市页
| |-- food // 食品筛选排序页
| |-- confirmOrder // 确认订单页
......@@ -252,7 +252,7 @@ npm run build
| |-- find // 发现页
| |-- forget // 忘记密码,修改密码页
| |-- home // 首页
| |-- login // 登注册页
| |-- login // 登注册页
| |-- msite // 商铺列表页
| |-- order // 订单列表页
| |--children
......@@ -278,14 +278,14 @@ npm run build
| |--children
| |--questionDetail // 问题详情
|       |-- shop                     // 商铺筛选页
| |-- children
| |-- foodDetail // 商铺信息页
| |-- children
| |-- foodDetail // 商铺信息页
| |-- shopDetail // 单个商铺信息页
| |-- children
| |-- shopSafe // 商铺认证信息页
| |-- children
| |-- shopSafe // 商铺认证信息页
| |-- vipcard // 会员卡办理页
| |-- children
| |-- invoiceRecord // 购买记录
| |-- children
| |-- invoiceRecord // 购买记录
| |-- useCart // 使用卡号购买
| |-- vipDescription // 会员说明
|
......
......@@ -11,7 +11,7 @@
<svg class="user_avatar" v-if="userInfo">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#user"></use>
</svg>
<span class="login_span" v-else>|注册</span>
<span class="login_span" v-else>|注册</span>
</router-link>
<section class="title_head ellipsis" v-if="headTitle">
<span class="title_text">{{headTitle}}</span>
......@@ -28,7 +28,7 @@
export default {
data(){
return{
}
},
mounted(){
......@@ -37,7 +37,7 @@
},
mounted(){
},
props: ['signinUp', 'headTitle', 'goBack'],
computed: {
......
......@@ -8,7 +8,7 @@
<input type="search" name="city" placeholder="输入学校、商务楼、地址" class="city_input input_style" required v-model='inputVaule'>
</div>
<div>
<input type="submit" name="submit" class="city_submit input_style" @click='postpois'>
<input type="submit" name="submit" class="city_submit input_style" @click='postpois' value="提交">
</div>
</form>
<header v-if="historytitle" class="pois_search_history">搜索历史</header>
......@@ -16,7 +16,7 @@
<li v-for="(item, index) in placelist" @click='nextpage(index, item.geohash)' :key="index">
<h4 class="pois_name ellipsis">{{item.name}}</h4>
<p class="pois_address ellipsis">{{item.address}}</p>
</li>
</li>
</ul>
<div class="search_none_place" v-if="placeNone">很抱歉!无搜索结果</div>
</div>
......@@ -31,7 +31,7 @@
data(){
return{
inputVaule:'', // 搜索地址
cityid:'', // 当前城市id
cityid:'', // 当前城市id
cityname:'', // 当前城市名字
placelist:[], // 搜索城市列表
placeHistory:[], // 历史搜索记录
......@@ -79,7 +79,7 @@
nextpage(index, geohash){
let history = getStore('placeHistory');
let choosePlace = this.placelist[index];
if (history) {
if (history) {
let checkrepeat = false;
this.placeHistory = JSON.parse(history);
this.placeHistory.forEach(item => {
......
......@@ -19,7 +19,7 @@
</svg>
<span>女士</span>
</span>
</div>
</div>
</section>
</section>
<section class="section_list">
......@@ -35,7 +35,7 @@
<section class="section_list">
<span class="section_left">送餐地址</span>
<section class="section_right">
<router-link to="/confirmOrder/chooseAddress/addAddress/searchAddress" tag="div" class="choose_address">{{searchAddress? searchAddress.name : '小区/写字楼/学校等'}}</router-link>
<router-link to="/confirmOrder/chooseAddress/addAddress/searchAddress" tag="div" class="choose_address">{{searchAddress? searchAddress.name : '小区/写字楼/学校等'}}</router-link>
<input type="text" name="address_detail" placeholder="详细地址(如门牌号等)" v-model="address_detail" class="input_style">
</section>
......@@ -51,7 +51,7 @@
<alert-tip v-if="showAlert" @closeTip="showAlert = false" :alertText="alertText"></alert-tip>
<transition name="router-slid" mode="out-in">
<router-view></router-view>
</transition>
</transition>
</div>
</template>
......@@ -78,7 +78,7 @@
}
},
created(){
},
components: {
headTop,
......@@ -86,7 +86,7 @@
},
computed: {
...mapState([
'searchAddress', 'geohash', 'userInfo',
'searchAddress', 'geohash', 'userInfo',
]),
},
methods: {
......@@ -101,7 +101,7 @@
async addAddress(){
if (!(this.userInfo && this.userInfo.user_id)) {
this.showAlert = true;
this.alertText = '请登'
this.alertText = '请登'
}else if(!this.name){
this.showAlert = true;
this.alertText = '请输入姓名'
......@@ -135,10 +135,10 @@
}
}
</script>
<style lang="scss" scoped>
@import 'src/style/mixin';
.address_page{
position: fixed;
top: 0;
......
......@@ -119,7 +119,7 @@
<alert-tip v-if="showAlert" @closeTip="showAlert = false" :alertText="alertText"></alert-tip>
<transition name="router-slid" mode="out-in">
<router-view></router-view>
</transition>
</transition>
</div>
</template>
......@@ -250,7 +250,7 @@
//用户未登录时弹出提示框
if (!(this.userInfo && this.userInfo.user_id)) {
this.showAlert = true;
this.alertText = '请登';
this.alertText = '请登';
return
//未选择地址则提示
}else if(!this.choosedAddress){
......@@ -434,7 +434,7 @@
margin-top: .4rem;
header{
padding: .7rem;
border-bottom: 0.025rem solid #f5f5f5;
border-bottom: 0.025rem solid #f5f5f5;
img{
@include wh(1.2rem, 1.2rem);
vertical-align: middle;
......@@ -466,7 +466,7 @@
}
}
.total_price{
border-top: 0.025rem solid #f5f5f5;
border-top: 0.025rem solid #f5f5f5;
}
}
.confrim_order{
......
<template>
<div class="loginContainer">
<head-top :head-title="loginWay? '登录':'密码登录'" goBack="true">
<div slot="changeLogin" class="change_login" @click="changeLoginWay">{{loginWay? "密码登":"短信登陆"}}</div>
<div slot="changeLogin" class="change_login" @click="changeLoginWay">{{loginWay? "密码登":"短信登录"}}</div>
</head-top>
<form class="loginForm" v-if="loginWay">
<section class="input_container phone_number">
......@@ -38,10 +38,10 @@
</section>
</form>
<p class="login_tips">
温馨提示:未注册饿了么账号的手机号,登时将自动注册,且代表您已同意
温馨提示:未注册饿了么账号的手机号,登时将自动注册,且代表您已同意
<a href="https://h5.ele.me/service/agreement/">《用户服务协议》</a>
</p>
<div class="login_container" @click="mobileLogin"></div>
<div class="login_container" @click="mobileLogin"></div>
<router-link to="/forget" class="to_forget" v-if="!loginWay">忘记密码?</router-link>
<alert-tip v-if="showAlert" :showHide="showAlert" @closeTip="closeTip" :alertText="alertText"></alert-tip>
</div>
......@@ -56,11 +56,11 @@
export default {
data(){
return {
loginWay: true, //登陆方式,默认短信登陆
loginWay: true, //登录方式,默认短信登录
showPassword: false, // 是否显示密码
phoneNumber: null, //电话号码
mobileCode: null, //短信验证码
validate_token: null, //获取短信时返回的验证值,登时需要
validate_token: null, //获取短信时返回的验证值,登时需要
computedTime: 0, //倒数记时
userInfo: null, //获取到的用户信息
userAccount: null, //用户名
......@@ -88,7 +88,7 @@
...mapMutations([
'RECORD_USERINFO',
]),
//改变登方式
//改变登方式
changeLoginWay(){
this.loginWay = !this.loginWay;
},
......@@ -136,7 +136,7 @@
this.validate_token = res.validate_token;
}
},
//发送登信息
//发送登信息
async mobileLogin(){
if (this.loginWay) {
if (!this.rightPhoneNumber) {
......@@ -164,7 +164,7 @@
this.alertText = '请输入验证码';
return
}
//用户名登
//用户名登
this.userInfo = await accountLogin(this.userAccount, this.passWord, this.codeNumber);
}
//如果返回的值不正确,则弹出提示框,返回的值正确则返回上一页
......@@ -175,12 +175,12 @@
}else{
this.RECORD_USERINFO(this.userInfo);
this.$router.go(-1);
}
},
closeTip(){
this.showAlert = false;
}
}
}
}
......
......@@ -116,7 +116,7 @@
infotel:'', //用户手机
avatar:'', //用户头像
show:false, //显示提示框
isEnter:true, //是否登
isEnter:true, //是否登
isLeave:false, //是否退出
showAlert: false,
alertText: null,
......@@ -126,7 +126,7 @@
clearTimeout(this.timer)
},
components: {
headTop,
headTop,
alertTip,
},
mixins: [getImgPath],
......@@ -155,7 +155,7 @@
this.show=false;
},200)
},
//退出登
//退出登
outLogin(){
this.OUT_LOGIN();
this.waitingThing();
......@@ -198,10 +198,10 @@
}
}
</script>
<style lang="scss" scoped>
@import 'src/style/mixin.scss';
.rating_page{
position: absolute;
top: 0;
......@@ -242,7 +242,7 @@
.headportrait-div{
span{
display:inline-block;
svg{
@include wh(100%,100%);
}
......@@ -263,7 +263,7 @@
margin-top:0;
padding:.3rem .4rem;
.headportrait-div{
@include fj(left)
@include fj(left)
p{
text-align:left;
line-height:1.39rem;
......
......@@ -147,10 +147,10 @@ export default {
data(){
return{
profiletitle: '我的',
getUserinfo: {}, //得到数据
username: '/注册', //用户名
getUserinfo: {}, //得到数据
username: '/注册', //用户名
resetname: '',
mobile: '后享受更多特权', //电话号码
mobile: '后享受更多特权', //电话号码
balance: 0, //我的余额
count : 0, //优惠券个数
pointNumber : 0, //积分数
......@@ -159,7 +159,7 @@ export default {
}
},
mounted(){
},
mixins: [getImgPath],
components:{
......@@ -193,8 +193,8 @@ export default {
userInfo: function (value){
this.getUserinfo = value || {};
this.avatar = this.getUserinfo&&this.getUserinfo.avatar || '';
this.username = this.getUserinfo&&this.getUserinfo.username ||'/注册';
this.mobile = this.getUserinfo&&this.getUserinfo.mobile ||'后享受更多特权';
this.username = this.getUserinfo&&this.getUserinfo.username ||'/注册';
this.mobile = this.getUserinfo&&this.getUserinfo.mobile ||'后享受更多特权';
this.balance = this.getUserinfo&&this.getUserinfo.balance || '0';
this.count = this.getUserinfo&&this.getUserinfo.gift_amount || '0';
this.pointNumber = this.getUserinfo&&this.getUserinfo.point || '0';
......@@ -205,8 +205,8 @@ export default {
</script>
<style lang="scss" scoped>
@import 'src/style/mixin';
@import 'src/style/mixin';
.profile_page{
p, span{
font-family: Helvetica Neue,Tahoma,Arial;
......@@ -257,13 +257,13 @@ export default {
}
}
}
.arrow{
@include wh(.46667rem,.98rem);
display:inline-block;
svg{
@include wh(100%,100%);
@include wh(100%,100%);
}
}
}
......@@ -307,7 +307,7 @@ export default {
color:#ff5f3e;
}
}
}
.info-data-link:nth-of-type(3){
border:0;
......@@ -317,7 +317,7 @@ export default {
}
}
}
}
}
}
.profile-1reTe{
margin-top:.4rem;
......
......@@ -53,7 +53,7 @@ export default [{
path: '/',
component: App, //顶层路由,对应index.html
children: [ //二级路由。对应App.vue
//地址为空时跳转home页面
//地址为空时跳转home页面
{
path: '',
redirect: '/home'
......@@ -78,12 +78,12 @@ export default [{
path: '/food',
component: food
},
//搜索页
//搜索页
{
path: '/search/:geohash',
component: search
},
//商铺详情页
//商铺详情页
{
path: '/shop',
component: shop,
......@@ -99,7 +99,7 @@ export default [{
}, ]
}]
},
//确认订单页
//确认订单页
{
path: '/confirmOrder',
component: confirmOrder,
......@@ -128,12 +128,12 @@ export default [{
}, ]
}, ]
},
//登陆注册页
//登录注册页
{
path: '/login',
component: login
},
//个人信息页
//个人信息页
{
path: '/profile',
component: profile,
......@@ -162,12 +162,12 @@ export default [{
component: service,
},]
},
//修改密码页
//修改密码页
{
path: '/forget',
component: forget
},
//订单列表页
//订单列表页
{
path: '/order',
component: order,
......@@ -176,7 +176,7 @@ export default [{
component: orderDetail,
}, ]
},
//vip卡页
//vip卡页
{
path: '/vipcard',
component: vipcard,
......@@ -212,16 +212,16 @@ export default [{
},
//余额
{
path: 'balance',
path: 'balance',
component: balance,
children: [{
path: 'detail', //余额说明
component: balanceDetail,
}, ]
},
//我的优惠页
//我的优惠页
{
path: 'benefit',
path: 'benefit',
component: benefit,
children: [{
path: 'coupon', //代金券说明
......@@ -242,7 +242,7 @@ export default [{
},
//我的积分页
{
path: 'points',
path: 'points',
component: points,
children: [{
path: 'detail', //积分说明
......
......@@ -224,7 +224,7 @@ if (process.env.NODE_ENV == 'development') {
/**
* 账号密码登
* 账号密码登
*/
var accountLogin = (username, password, captcha_code) => fetch('POST', '/v2/login', {username, password, captcha_code});
......@@ -433,7 +433,7 @@ if (process.env.NODE_ENV == 'development') {
// /**
// * 手机号登
// * 手机号登
// */
// var sendLogin = (code, mobile, validate_token) => fetch('POST', '/v1/login/app_mobile', {
......
......@@ -27,7 +27,7 @@ const state = {
orderParam: null,//订单的参数
orderMessage: null, //订单返回的信息
orderDetail: null, //订单详情
login: true,//是否登
login: true,//是否登
imgPath:null,//头像地址
removeAddress:[],//移除地址
addAddress:'', //新增地址
......
......@@ -250,7 +250,7 @@ export default {
[SAVE_ORDER](state, orderDetail) {
state.orderDetail = orderDetail;
},
//退出登
//退出登
[OUT_LOGIN](state) {
state.userInfo = null;
state.login = false;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册