vue网易严选购物商城项目

  • 项目展示
    • 项目上线(移动端访问):http://182.92.226.242:8080/#/indexlist
    • 项目源码: https://github.com/wy-linux/yan_xuan
    • 项目截图:
  • 项目模块
    • 登录模块
      • 页面布局
        • 密码与验证码登录切换
        • 密码输入框的密码显示与隐藏
      • 业务逻辑
        • 验证码发送
        • 登录功能
        • 警告提示框
        • 用户的持久登陆
    • 购物车模块
      • 页面布局
        • vue动画
      • 业务逻辑
        • 购物车添加商品
        • 购物车的全选与单选
        • 购物车的商品结算
        • 购物车商品的删除
        • 购物车的状态维持
      • 首页模块
        • 首页商品列表的渲染
        • 首页商品详情页的渲染
      • 值得买模块
        • 轮播图的数据处理
        • 评论页的数据处理
  • 注意事项
    • axios配置跨域访问携带cookie
    • 使用swiper插件创建实例的时间

项目展示

项目上线(移动端访问):http://182.92.226.242:8080/#/indexlist
项目源码: https://github.com/wy-linux/yan_xuan
项目截图:






项目模块

登录模块

页面布局

        <form @submit.prevent="login"><div class="first " :class="{on: way}"><section ><input type="text" placeholder="请输入手机号" v-model="phone"></section><section style="position: relative; margin-top: .7rem"><input type="password" placeholder="请输入短信验证码" v-model="msg"><button class="yan_zh" :class="{color: count}" @click.prevent="getMsg">{{count ? `已发送(${count}s)` : '获取验证码'}}</button><span class="phone" :class='{on: checkPhone}'>请输入正确的手机号</span><span class="phone" :class='{on: idenCode}'>验证码是{{idenCode}}</span></section><section style="margin-top: .8rem"><div style="overflow: hidden"><button>登录</button></div></section></div><div class="second " :class="{on: !way}"><section ><input type="text" placeholder="请输入手机号" v-model="phone"></section><section style="position: relative"><input type="password" placeholder="请输入密码" v-model="pwd" v-show="!showPwd"><input type="text" placeholder="请输入密码" v-model="pwd" v-show="showPwd"><div class="switchBtn" :class="{green: showPwd}" @click='showPwd = !showPwd'><div class="circle" :class="{scroll: showPwd}"></div><span style="float: left; font-size: .3rem">{{showPwd ? 'abc' : ''}}</span></div><div class="tishi" style="font-size: .25rem; font-weight: 700; width: 7rem; margin-top: .1rem; text-align: left">* 提示: 登录密码为用户第一次输入的密码,请务必牢记。<br />* 如有遗忘,请使用验证码登录</div></section><section><div style="overflow: hidden; margin-top: .4rem"><button>登录</button></div></section></div></form>

密码与验证码登录切换

设置两个登录表单,用户点击时改变:class="{on: way}"中way的值来实现密码与验证码登录的切换

密码输入框的密码显示与隐藏

放置两个输入框

<input type="password" placeholder="请输入密码" v-model="pwd" v-show="!showPwd">
<input type="text" placeholder="请输入密码" v-model="pwd" v-show="showPwd">
<div class="switchBtn" :class="{green: showPwd}" @click='showPwd = !showPwd'><div class="circle" :class="{scroll: showPwd}"></div><span style="float: left; font-size: .3rem">{{showPwd ? 'abc' : ''}}</span></div>

1.两个输入框绑定相同数据pwd, 用户切换时隐藏其中一项表单
2.用户切换文本输入框时,给切换按钮添加类名scroll,实现按钮的滚动动画

业务逻辑

验证码发送

async getMsg() {if(/^1\d{10}$/.test(this.phone)) {let result = ''if(!this.count) {//防止用户重复点击this.count = 30var intervalId = setInterval(() => {this.count--;if(this.count <=  0) {clearInterval(intervalId)}}, 1000);result  = await axios.get('/idenCode?phone='+ this.phone)}if(result.status == 0) {this.checkPhone = false;if(this.count) {clearInterval(intervalId)this.count = 0;}this.idenCode = result.code;}} else {this.idenCode = ''this.checkPhone = true}},

1.使用正则表达式检验用户输入手机号是否合法
2.在data中定义数据count,用户点击发送验证码时,触发定时器每1秒count减1;

登录功能

async login() {let r;if(this.way) {if (!/^1\d{10}$/.test(this.phone)) {this.text = '手机号输入不正确',this.alertShow = truereturn}  else if(!/^\d{6}$/.test(this.msg)) {this.text = '验证码格式错误',this.alertShow = truereturn} else {r = await axios.post('/login_c', {phone: this.phone,code: this.msg})}} else {if(!/^1\d{10}$/.test(this.phone)) {this.text = '手机号输入不正确',this.alertShow = truereturn} else if (!/^\w{8,16}$/.test(this.pwd)) {this.text = '密码必须8-16位数字或者字母',this.alertShow = truereturn} else {r = await axios.post('/login_pwd', {phone: this.phone,pwd: this.pwd,})}}this.checkPhone = falseif(this.count) {clearInterval(intervalId)this.count = 0;}if(r.status == 0) {this.$store.commit('userChange',r.user)this.$router.replace('/profile')} else {this.alertShow = truethis.text = r.msgreturn}},

1.使用正则表达式对用户输入内容的校检
2.根据用户登录方式向后端发送请求。当返回data.status == 0 时,将拿到的数据放到vuex中管理,并跳转到登陆页;否则,将后端的错误信息展示在页面上

警告提示框

<alert-tip :msg='text' @destroy='change' v-show='alertShow' />
<template><div class="alertTip"><div class="contain"><div class="tap_icon"><span class="top"></span><span class="foot"></span></div><p>{{msg}}</p><div class="enter" @click="$emit('destroy')">确认</div></div></div>
</template>

1.封装alert-tip组件,用自定义属性将警告信息传递到组件中
2.用户点击确认时触发自定义事件destory,将组件的状态重置为隐藏

用户的持久登陆

  mounted() {this.$store.dispatch('userGet')},async userGet(context) {let res = await axios('/session')if (res.status == 0) {context.commit('userChange', res.user)}},

在app根组件中触发axios请求拿到对应的用户信息

        <router-link :to="user.phone ? '/cared' : '/car'"> <i class="iconfont icon-cart" :class="{on: $route.path == '/car' || $route.path == '/cared'}"></i>  <span class="text" :class="{on: $route.path == '/car' ||  $route.path =='/cared'}">购物车</span> </router-link ><router-link :to="user.phone ? '/profile' : '/login'"> <i class="iconfont icon-nickname" :class="{on: $route.path == '/login' || $route.path=='/profile'}"></i> <span class="text" :class="{on: $route.path == '/login'|| $route.path == '/profile'}">个人</span> </router-link>

根据vuex中是否有用户手机号动态去往登陆与非登录页面

购物车模块

页面布局

vue动画

.move-enter-active,.move-leave-active {transition: all .3s;
}
.move-enter, .move-leave-to {transform: translateY(15rem)
}

在用户点击加入购物车时,将购物车的v-if设置为true,vue加载过渡动画的弹出效果

业务逻辑

购物车添加商品

      this.$store.dispatch('carput',{index: this.$store.state.indexGoodDetails.select[this.index],value: this.value,img: this.$store.state.indexGoodDetails.swiper[0],title: this.$store.state.indexGoodDetails.title,price: this.$store.state.indexGoodDetails.price,check: 0,} )this.$store.commit('countAdd')this.carShow = !this.carShow

1.首先判断用户是否选择商品规格
2.而后向后端发送请求,后端查询到用户列表下的购物车列表后用push方法新增当前项而后更新到数据库中

    let user = await User.findOne({ phone: req.body.phone });user.carlist.push(req.body.carlist)let a = await User.updateOne({ phone: req.body.phone }, { carlist: user.carlist })

购物车的全选与单选

1.设置一个checkOne的类名,当拥有这个类名时处于选中状态
2.用户点击选中框时判断当前项是否有checkOne类名,如果有
则添加类名;反之,移除类名

        checkshop(e,index) {if(e.target.classList.contains('checked')) {e.target.classList.remove('checked')this.count--this.$store.state.user.carlist[index].check = 0} else {e.target.classList.add('checked')this.count++this.$store.state.user.carlist[index].check = 1}},

3.每一次类名添加时将count值加1,渲染列表中当前项的check属性置为1

 selectAll() {var is = document.querySelectorAll('.checkbox')if(!this.checkAll) {for(var i = 0 ; i < is.length; i++){is[i].classList.add('checked')}this.count = this.$store.state.user.carlist.lengthfor(let j = 0; j < this.$store.state.user.carlist.length; j++) {this.$store.state.user.carlist[j].check = 1} } else {for(var i = 0 ; i < is.length; i++){is[i].classList.remove('checked')}this.count = 0for(let j = 0; j < this.$store.state.user.carlist.length; j++) {this.$store.state.user.carlist[j].check = 0} }this.checkAll = !this.checkAll},

4.用户点击全选按钮时,给每一项添加checkOne类名,将count的值置为列表数据的长度,每一项的check属性置为1

        count() {var is = document.querySelectorAll('.checkbox')if(this.count == this.$store.state.user.carlist.length && this.count != 0) {this.checkAll = truefor(var i = 0 ; i < is.length; i++){is[i].classList.add('checked')}} else {this.checkAll = false}},

5.在watch中监听count的变化, 当count的值等于列表长度时,将全选框添加checkAlll类名,其余项添加checkOne类名;否则,移除全选框的选中状态

购物车的商品结算

    computed: {total() {let sum = 0;for(let i = 0; i < this.$store.state.user.carlist.length; i++) {sum += Number(this.$store.state.user.carlist[i].price.slice(1)) * Number(this.$store.state.user.carlist[i].value) * Number(this.$store.state.user.carlist[i].check)}return sum}},

添加计算属性total,循环购物车的商品列表,结算总价格 = 每一项商品的价格 * 商品数量 * 商品是否选中(选中为1,未选中是0)

购物车商品的删除

        mode() {var is = document.querySelectorAll('.checkbox')var is = document.querySelectorAll('.checkbox')for(var i = 0 ; i < is.length; i++){is[i].classList.remove('checked')}for(let j = 0; j < this.$store.state.user.carlist.length; j++) {this.$store.state.user.carlist[j].check = 0} this.checkAll = falsethis.count = 0}}

1.当用户点击编辑时, 将mode = true。编辑按钮隐藏,删除按钮出现;
2.在watch中监听mode值的变化(mode值的变化标志用户在结算模式与删除模式的切换),将全选框与单选框的状态置为未选中状态, count = 0 ,所有项的check属性 = 0)

       moded() {for(let j = 0; j < this.$store.state.user.carlist.length; j++) {if(this.$store.state.user.carlist[j].check) {this.$store.state.user.carlist.splice(j, 1)j-- //注意}}this.$store.commit('countChange', this.$store.state.user.carlist.length)Axios.post('/cardelete', {carlist: this.$store.state.user.carlist})this.mode = false}

3.用户点击删除时,遍历购物车列表,将check属性1的项全部删除(注意splice方法删除数组时,数组的后一项会自动变成前一项,记得循环计数器器 j --),然后将列表中的数据同步到后端

router.post('/cardelete', async(req, res) => {console.log(req.body);let a = await User.updateOne({ phone: req.session.phone }, { carlist: req.body.carlist })
})

4.后端拿到数据时,将数据库中的carlist列表更新为当前列表

购物车的状态维持

    mounted() {this.$store.dispatch('userGet')},

用户每次刷新购物车页面时, 向后端发送请求;后端接收请求,下发购物车列表数据

首页模块

首页商品列表的渲染

        watch: {index() {if(this.index <= 2) {this.$store.dispatch('indexGet', this.index)this.$store.dispatch('indexHeadGet', this.index)if(this.$route.path !== '/indexlist') {this.$router.replace('/indexlist')} } else if(this.index == 3){this.$store.dispatch('indexHeadGet', this.index)if(this.$route.path !== '/default') {this.$router.replace('/default')}} else {return}}

1.用户点击tab栏时将tab栏的索引传递datade的index中
2.index发生变化时向后端发送请求,并携带请求的索引

router.get('/goods/:index', async(req, res) => {req.session.index = req.params.indexconsole.log(req.session.index);switch (req.params.index) {case '0':let good0 = await Family.find({})if (good0) {res.send({status: 0,good0})}break;case '1':let good1 = await clothes.find({})if (good1) {res.send({status: 0,good1})}break;case '2':let good2 = await wine.find({})if (good2) {res.send({status: 0,good2})}break;}})

3.后端根据请求的索引,查询不同的数据库并返回不同都商品列表

首页商品详情页的渲染

  mounted() {this.$store.dispatch('indexGoodDetailsGet', this.$route.params.index)},

1.通过路由params传参,将点击的商品索引传递到详情页。
详情页携带索引向后端发送请求

router.get('/goodsDetails/:index', async(req, res) => {switch (req.session.index) {case '0':let good0 = await FamilyDetails.find({}).limit(1).skip(Number(req.params.index))if (good0) {res.send({status: 0,good0: good0[0],index: req.session.index})}break;case '1':let good1 = await clothesdetails.find({}).limit(1).skip(Number(req.params.index))if (good1) {res.send({status: 0,good1: good1[0],index: req.session.index})}break;case '2':let good2 = await winedetails.find({}).limit(1).skip(Number(req.params.index))if (good2) {res.send({status: 0,good2: good2[0],index: req.session.index})}break;}})

2.后端在session中查询用户上次访问的数据库序列并确定本次查询的数据库序列,而后根据本次请求携带的索引跳过查询,限制查询获取当前的详情页数据

值得买模块

轮播图的数据处理

        pay_swippers(state) {var min = [];var arr = []state.pay_swipper.forEach(value => {min.push(value)if (min.length % 8 === 0) {arr.push(min);min = []}})return arr},

1.该页面轮播图为两页, 每页8个商品
2.后端返回数据为16个商品的数组,使用foreach方法遍历每一个项,当小数组的值等于8 个时将整个小数组添加到整个大数组中

评论页的数据处理

        paylistPack(state) {var min = [];var arr = [];state.paylist.forEach(value => {min.push(value)if (min.length == state.paylist.length / 2) {arr.push(min);min = [];}})return arr}}

1.评论页为左右两个盒子, 每个盒子内部的项目个数不固定
2.后端返回数据为16个项目的数组,使用foreach方法遍历每一项,当小数组的值等于遍历数组长度的一半时,将小数组添加到大数组中

注意事项

axios配置跨域访问携带cookie

axios.defaults.withCredentials = true

1.在axios的默认设置中把withCredentials = true

app.all('*', function(req, res, next) {res.header("Access-Control-Allow-Origin", req.headers.origin);res.header("Access-Control-Allow-Credentials", true)res.header("Access-Control-Allow-Headers", "Content-Type");res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");next();
});

2.后端需要配置
res.header(“Access-Control-Allow-Credentials”, true)
注意: res.header(“Access-Control-Allow-Origin”, req.headers.origin);其中req.headers.origin 不能为 ’ * ',
*会与credentials起冲突
3.新版chrome 的cookie中新增了一个SameSite属性,默认http请求时不携带session id SameSite = Lax ;手动将SameSite = NONE时 站点必须开启https传输, 否则无效
4. 查阅资料

将以上三个选项禁用, 终于能够跨域携带session id

使用swiper插件创建实例的时间

watch : {list() {this.$nextTick(function () {new Swiper ('.swiper-container', {pagination: {el: '.swiper-pagination',},}}) }
}

使用this.$nextTick等待页面渲染完成后创建组件

vue网易严选购物商城项目相关推荐

  1. Vue购物商城项目(二) 数据请求使用

    Vue购物商城项目(二) 文章目录 Vue购物商城项目(二) 前言 一.请求数据 request.js home.js Home.vue 二.使用数据 总结 前言 1.这里面包含了大量的.我的个人理解 ...

  2. vue尚品汇商城项目-day04【29.加入购物车操作(难点)】

    文章目录 29.加入购物车操作(难点) 29.1加入购物车按钮 29.2addCartSuce 29.3购物车 29.3.1 向服务器发送ajax请求,获取购物车数据 29.3.2UUID临时游客身份 ...

  3. vue尚品汇商城项目-day07【vue插件-49.(了解)自定义插件】

    文章目录 49.(了解)自定义插件 本人其他相关文章链接 49.(了解)自定义插件 自定义插件好处: 功能:用于增强Vue 本质:包含install方法的一个对象,install的第一个参数是Vue, ...

  4. vue尚品汇商城项目-day00【项目介绍:此项目是基于vue2的前台电商项目和后台管理系统】

    文章目录 本人其他相关文章链接 项目介绍:此项目是基于vue2的前台电商项目和后台管理系统 此项目为在线电商Web App (SPA) 包括首页, 搜索列表, 商品详情, 购物车, 订单, 支付, 用 ...

  5. vue尚品汇商城项目-day03【vue插件-19.mockjs模拟数据(开发Home首页当中的ListContainer组件与Floor组件)】

    文章目录 19.mockjs模拟数据(开发Home首页当中的ListContainer组件与Floor组件) 本人其他相关文章链接 19.mockjs模拟数据(开发Home首页当中的ListConta ...

  6. Django 20购物商城项目(注册、登录页面:生成动态验证码)

    dDjango 20购物商城项目 1.安装pillow 2.在注册页面加入验证码 2.1.register.html (增加内容) 2.2.register.js(增加内容) 2.2.路由.视图(增加 ...

  7. Django 19购物商城项目(收货地址:添加、修改)

    dDjango 19购物商城项目 1.新建axf_addr,收货地址表 2.路由 3.cart页面,添加默认收货地址 4.视图(主要修改了cart.新建了收货地址相关方法) 5.收货地址列表 6.收货 ...

  8. Jieyue捷阅网购物商城项目介绍说明

    jieyue捷阅网是基于springboot开发的轻量级单体架构购物商城网站,并分为用户.商户.后台三大模块.用户模块能够进行商品搜索浏览.在线下单.微信支付等功能:商户模块则可以对收益情况以及订单成 ...

  9. 基于SpringBoot + Vue的小程序商城项目(附源码),支持分销、团购、秒杀、优惠券。。。...

    前些时候一直有粉丝让我分享带分销的商城项目,网上收集了一波,希望能帮到大家. 面向对象 该程序是企业在创立初期很好的技术基础框架,加快公司项目开发进度,当然也可以对现有的系统进行升级: 个人开发者也可 ...

  10. 基于SpringBoot vue的小程序商城项目(附源码),支持分销、团购

    来源:微同科技 前些时候一直有粉丝让我分享带分销的商城项目,网上收集了一波,希望能帮到大家. # 面向对象 该程序是企业在创立初期很好的技术基础框架,加快公司项目开发进度,当然也可以对现有的系统进行升 ...

最新文章

  1. jvm性能调优实战 - 43OOM内存溢出发生的原因及可能发生OOM的内存区域
  2. gnuplot绘图学习
  3. C语言学习记录_2019.02.02
  4. insertAfter()
  5. gradle groovy_适用于Java开发人员的Groovy吗? 认识Gradle,Grails和Spock
  6. pyqt5下pushButton框保留用户历史输入
  7. [黑金原创教程][连载][iBoard 电子学堂][第八卷 设计任意波发生器]第三篇 直接数字合成(DDS)原理...
  8. 音乐播放插件Aplayer+WebAPI的使用【附下载】
  9. Hadoop集群常用命令
  10. 软件工程导论 实验三 软件设计
  11. 百度编辑器ueditor表格无法显示边框以及边框颜色等系列问题解决方案
  12. 分类问题中正负样本分布不均衡问题的解决方法
  13. P68-70 王者荣耀
  14. easyui treegrid
  15. 【2018年7月英语学习】--零散中星星点点
  16. unl文件导入orcle数据库
  17. 【PCB软件技巧】OrCAD与PADS相互搭配使用的相关要点
  18. 三国志战略版:SP吕蒙携手都督重出江湖
  19. lol6月五日服务器维护,lol5月6日维护公告
  20. 18 Issues in Current Deep Reinforcement Learning from ZhiHu

热门文章

  1. 后端速成JavaScript
  2. 制作QQ微信支付宝三合一收款码
  3. 华中科技大学计算机学院陈迪,华中科技大学2011届“优秀毕业生”公示名单
  4. SPF算法计算过程--例
  5. 干货 | 携程度假数据治理之数据标准管理实践
  6. 记录linux历史命令,Linux历史记录命令
  7. 矩阵的广义逆——减号、加号广义逆的求法
  8. Mybatis使用关联查询由于表名字段重复导致的问题
  9. 优美诗词(持续更新)
  10. 第1章第26节:如何通过幻灯片母版统一管理相同类型的幻灯片2 [PowerPoint精美幻灯片实战教程]