目录
1. 项目准备
1.1 项目描述
该项目基于vue2实现的一个外卖软件,可以实现登录、注册、查看外卖商家等功能
1.2 技术选型
1.3 API接口
1) 根据经纬度获取位置信息
2)获取食品分类列表
3) 根据经纬度获取商铺列表
1.4 从中学到什么?
1)项目的搭建
使用脚手架搭建项目
npm install -g @vue/cli //安装vue脚手架,如果之前安装过就不再需要安装
npm create 项目名 //创建vue2项目
npm install //安装package.json里面的内容
npm run serve //启动热加载
有关npm的相关指令说明
npm install moduleName 安装模块到项目node_modules目录下
npm install -g moduleName 安装模块到全局,不会在项目node_modules目录中保存模块包
npm install --save moduleName 安装模块到项目node_modules目录下,在package.json文件的dependencies节点写入依赖
npm install --save-dev moduleName安装模块到项目node_modules目录下,在package.json文件的devDependencies节点写入依赖
使用原则
开发时需要使用--save-dev,如gulp ,压缩css、js的模块;
部署后需要使用--save,如express, router等
2 路由的使用
详见以下文章
Vue学习笔记|路由、详细、入门_***无名小卒的博客-CSDN博客
3 stylus
npm install stylus@0.54.8 stylus-loader@3.2.2
需要主要版本冲突,以上指令适用于vue2框架
stylus是css预处理器,作用让css代码的编写更加结构化
4 swiper组件的使用
swiper是实现轮播图的一个插件
5 vuex
管理从后台获取的状态数据
Vue学习笔记|vuex_***无名小卒的博客-CSDN博客
6 路由组件的meta属性
如登录页面不需要底部的tab切换,因此可以给需要底部的tab切换的路由加上showFooter属性
//如登录页面不需要底部的tab切换,因此可以给需要底部的tab切换的路由加上showFooter属性
{
path:'/order',
component:Order,
meta:{
showFooter:true
}
}
在全局组件中给底部的tab组件加上判断条件,当跳转的路由需要底部tab再显示,如若不需要便不显示
<FooterGuide v-show="$route.meta.showFooter"/>
7 异步数据的请求
7.1 请求函数封装:使用Promise和axios实现封装,其中封装GET请求和POST请求两种请求方式,使用Promise实现异步任务,在Promise中发送请求;若发送请求则调用resolve方法,若发送失败,则调用reject方法
/*
* 封装ajax请求函数
* 返回值:promise对象
* */
import axios from 'axios'
export default function ajax (url, data = {}, type = 'GET') {
return new Promise(function (resolve, reject) {
let promise
// 执行异步ajax请求
if (type === 'GET') {
// 准备url query参数数据
let dataStr = ''
Object.keys(data).forEach(key => {
dataStr += key + '=' + data[key] + '&'
})
if (dataStr !== '') {
dataStr = dataStr.substring(0, dataStr.lastIndexOf('&'))
url = url + '?' + dataStr
}
// 发送get请求
promise = axios.get(url)
} else {
// 发送post请求
promise = axios.post(url, data)
}
promise.then(function (response) {
// 成功了调用resolve
resolve(response.data)
}).catch(function (err) {
// 失败了调用reject
reject(err)
})
})
}
7.2 接口的封装
根据后台的接口文档,一共有多少个接口便封装成多少个请求,该在Vue直接调用请求
/*
* 包含n个接口请求函数的模块
* 函数返回值:promise对象
* */
import ajax from './ajax'
const BASE_URL='api'
// 根据经纬度获取位置信息
export const reqAddress = (geohash)=> ajax(`${BASE_URL}/position/${geohash}`)
//获取食品分类列表
export const reqCategorys = ()=> ajax(`${BASE_URL}/index_category`)
//根据经纬度获取商铺列表
export const reqShops = (latitude,longitude)=> ajax(`${BASE_URL}/shops`,{latitude,longitude})
7.3 相关依赖
npm i axios --save //安装axios依赖
8 ajax跨域问题:配置代理
该项目为前后端分离的项目,前端向后台发送ajax请求,会发生跨域,解决跨域的方法:在前端设置代理,拦截请求,代理再将请求转发给服务器
proxyTable: {
'/api': { // 匹配所有以 '/api'开头的请求路径
target: 'http://localhost:4000', // 代理目标的基础路径
changeOrigin: true, // 支持跨域
pathRewrite: {// 重写路径: 去掉路径中开头的'/api'
'^/api': ''
}
}
}
9 异步数据的获取
使用vuex来实现对数据的管理。
首先创建相关的模块。index|state|mutations|actions|getters|mutation-type
actions用于响应组件中的动作,在该项目中,action中主要实现发送ajax请求,并将获取的数据commit给mutations
mutations用于操作数据,改变state中的数据
state中封装要接收的数据,state中的数据是直接与页面交互的一层
在组件中获取数据
1.向actions分发请求,异步获取数据,并放到state中
mounted(){
//获取数据
this.$store.dispatch('getCategorys')
this.$store.dispatch('getShops')
}
2. 获取state中数据
使用mapState使用数组语法获得数据,也可以使用计算属性去获取state中的数据。在组件中就可以直接使用该数据
import {mapState} from 'vuex'
computed:{
...mapState(['address','categorys'])
}
模板中数据的来源
data(自身的数据)、props(外部传入的数据)、computed(计算属性)根据data/props/state/getters获取数据
10 异步显示轮播图
使用vuex获取轮播图的数据
对数据进行整合,将一维数组转为二维数组
使用Swiper显示轮播,在界面更新之后创建Swiper对象
// 根据categorys一维数组生成一个二维数组
categorysArr(){
const {categorys}=this
const arr=[]
//准备一个小数组
let minArr=[]
//遍历categorys
categorys.forEach(item=>{
//如果当前小数组满了,创建一个新的
if(minArr.length===8){
minArr=[]
}
//如果当前小数组为空,将小数组保存到大数组
if(minArr.length===0){
arr.push(minArr)
}
//将食品分类的数据放入小数组
minArr.push(item)
})
return arr
}
使用Swiper显示轮播,在界面更新之后创建Swiper对象
使用waich+$nextTick()方法
this.$nextTick()将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新即可。
watch:{
categorys(value){
//界面更新就立即創建Swiper對象
this.$nextTick(()=>{
//一旦完成界面更新,立即調用Swiper(此語句寫在數據更新之後)
new Swiper('.swiper-container',{
loop: true,
//分页器
pagination:{
el: '.swiper-pagination'
}
})
})
}
},
11 登录/注册界面
1)切换登录的方式
给两个tab动态绑定class,在data中设置一个属性loginWay,代表登录的方式,值为布尔类型,当为true时为短信登录,反之为密码登录。使用对象的方法动态绑定class,当class中的on为true时,就会出动on中的样式
<a href="javascript:;" :class="{on:loginWay}" @click="loginWay=true">短信登录</a>
<a href="javascript:;" :class="{on:!loginWay}" @click="loginWay=false">密码登录</a>
如图当切换tab时,会显示不一样的form,同样给这两个表单动态绑定class,先将整个div设置为隐藏,当绑定的class属性值为true时,就将display设置为true
以下css语法使用stylus
.login_content
>form
>div
display none
&.on
display block
2) 手机号合法检查
使用正则表达式对数据进行验证,返回true则手机号码正确,可以发送验证码,false则不能发送验证码
rightPhone(){
return /^1\d{10}$/.test(this.phone)
}
3) 验证码发送倒计时实现
发送验证码按钮disable属性
当rightPhone为true,即手机号码正确时,按钮可以正常使用,即disable为false
当rightPhone为false,即手机号码错误时,按钮不能正常使用,即disable为true
计时和获取验证码按钮的切换
使用三木表达式,其中computeTime用于倒计时,当其>0时,显示已发送xxs,当其=0,显示获取验证码
<button :disabled="!rightPhone"
class="get_verification"
:class="{right_phone:rightPhone}"
@click.prevent="getCode">
{{computeTime ? `已发送(${computeTime}s)`: '获取验证码'}}
</button>
实现计时
当点击按钮时,触发getCode方法,该方法使用setInterval实现倒计时的功能
getCode(){
//当计时器没有工作时
if(!this.computeTime){
//启动倒计时
this.computeTime=30
const intervalId=setInterval(()=>{
this.computeTime--
if(this.computeTime<=0){
//停止计时
clearInterval(intervalId)
}
},1000)
//发送ajax请求,获取验证码
}
}
4) 切换显示和隐藏密码
<!--设置按钮的颜色,打开按钮绿色,关闭按钮灰色-->
<div class="switch_button"
:class="showPwd ? 'on':'off'"
@click="showPwd=!showPwd" >
<!--小圆圈-->
<div class="switch_circle" :class="{right:showPwd}"></div>
<!--文字-->
<span class="switch_text">{{showPwd ? 'abc':'...'}}</span>
</div>
该按钮由外圈,小圆圈,以及字体组成
给外圈动态绑定class,使用三目表达式,来动态绑定两种样式,白色隐藏密码,绿色显示密码
给小圆圈动态邦栋class,为true时,设置一个动画,向右滑动
文字同理
5) 前台验证码提示
前台验证登录主要验证是否非空,使用正则表达式验证手机号码是否正确