智慧商城
知识点目录
实现
按照结构创建vue-cli脚手架,创建项目
初始化设置一下文件
(有部分修改和增加)
- 增加两个文件夹------api 和 utils
- 删除之前关于vue页面样式的一些文件
- 修改路由配置
js
const router = new VueRouter({
// 默认路由是一个空数组
routes: []
})
- 修改app.vue,把之前的样式删掉,只留一个路由出口即可
认识第三方Vuet组件库vant-ui
组件库:
第三方封装好了很多很多的组件,整合到一起就是一个组件库
Vant 2 - 轻量、可靠的移动端组件库 (gitee.io)
vant全部导入和按需导入
全部:
按需:
按需导入这里需要在根目录再创建一个js文件:babel.config.js
js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
}
- 但是之后我们用到的组件增多时,全部写在main.js里就不太合适了
- 所以我们现在在utils文件夹里写一个新的vant-ui.js文件用来存放这些组件
项目中的vw适配
目标:基于postcss插件实现项目vw适配
在根目录(不是src)创建一个新的js文件:postcss.config.js
js
module.exports = {
plugins: {
'postcss-px-to-viewport': {
// vw适配的标准屏的宽度(iPhoneX)
// 设计图 750 ,调成1倍 =》适配375标准屏幕
// 设计图 640 ,调成1倍 =》适配320标准屏幕
viewportWidth: 375
}
}
}
路由设计配置
- 先搞清楚一级路由和二级路由,并完成文件的准备
比如:
- 配路由规则(数组里面包对象)
js
//router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/login'
import Layout from '@/views/layout'
import Search from '@/views/search'
import SearchList from '@/views/search/list'
import ProDetail from '@/views/prodetail'
import Pay from '@/views/pay'
import MyOrder from '@/views/myorder'
Vue.use(VueRouter)
const router = new VueRouter({
// 默认路由是一个空数组
routes: [
{ path: '/login', component: Login },
{ path: '/', component: Layout },
{ path: '/search', component: Search },
{ path: '/searchlist', component: SearchList },
{ path: '/prodetail/:id', component: ProDetail },
{ path: '/pay', component: Pay },
{ path: '/myorder', component: MyOrder }
]
})
export default router
- 路由设计配置
- 目标1:阅读vant组件库文档,实现底部导航tabbar
- 目标2:基于底部导航,完成二级路由配置
- 配相关的二级组件
- 配置二级路由:在相关的一级路由里嵌套,用children
js
import Home from '@/views/layout/home'
import Category from '@/views/layout/category'
import Cart from '@/views/layout/cart'
import User from '@/views/layout/user'
{
path: '/',
component: Layout,
redirect: '/home',//重定向:一进页面,默认首页路由
children: [
{ path: '/home', component: Home },
{ path: '/category', component: Category },
{ path: '/cart', component: Cart },
{ path: '/user', component: User }
]
},
- 配置导航链接
配合route和to路径可以实现导航栏点击高亮转换
js
<van-tabbar route active-color="#ee0a24" inactive-color="#000">
<van-tabbar-item to="/home" icon="wap-home-o">首页</van-tabbar-item>
<van-tabbar-item to="/category" icon="apps-o">分类页</van-tabbar-item>
<van-tabbar-item to="/cart" icon="shopping-cart-o">购物车</van-tabbar-item>
<van-tabbar-item to="/user" icon="user-o">我的</van-tabbar-item>
</van-tabbar>
- 配置路由出口,在app.vue
js
<router-view></router-view>
登录静态布局
1. 准备工作
- 以后所有的 公共通用样式 都可以写在styles文件夹里
js
//common.less
// 重置默认样式
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
// 文字溢出省略号
.text-ellipsis-2 {
overflow: hidden;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
}
// 添加导航的通用样式
.van-nav-bar {
.van-nav-bar__arrow {
color: #333;
}
}
- 在main.js里导入common.less
js
import '@/styles/common.less'
- 图片素材拷贝到assets目录中
2. 登录页静态布局编写
- 头部组件 NavBar
- 引入
- 页面
- 左箭头通用样式
- 静态未渲染的页面结构编写
utils/vant-ui.js
js
import Vue from 'vue'
import { NavBar } from 'vant'
Vue.use(NavBar)
views/login/index.js
js
<!-- 头部,用到了vant插件NavBar -->
<!-- 返回上一页 @click-left="$router.go(-1)" -->
<van-nav-bar
title="会员登录"
left-arrow
@click-left="$router.go(-1)"
/>
在这里给头部导航的返回箭头加了一个通用样式
css
//添加导航的通用样式
//不把这个样式在行内写,而写在通用样式里,是因为不仅这一个导航栏需要
//写两层是为了增加它的权重
.van-nav-bar{
.van-nav-bar__arrow{
color: #333;
}
}
request模块-axios封装-发请求
目标:将axios请求方法,封装到request模块
- 获取图像验证码
- 获取短信验证码
- 登录
使用axios来请求后端接口 ,一般都会对axios进行一些配置(比如:配置基础地址、请求响应拦截器)
所以项目开发中,都会对axios进行基本的二次封装 ,单独封装到一个request模块中,便于维护使用
创建request模块
-
安装axios:
yarn add axios
-
新建request模块
- 基于原本的axios,创建了一个新的用于请求的实例
- 之后所有内容都是往新建的这个实例中去添加的,它并不会污染最原始的axios
- 接口文档地址:wiki - 智慧商城-实战项目 (apifox.com)
- 基地址:cba.itlike.com/public/inde...
- axios官网:起步 | Axios中文文档 | Axios中文网 (axios-http.cn)
utils/request.js
其中有部分修改,看注释
js
import axios from 'axios'
// 创建axios实例,将来对创建出来的实例进行自定义配置
const instance = axios.create({
// 基地址记得修改成你自己的
baseURL: 'http://cba.itlike.com/public/index.php?s=/api/',
timeout: 5000
// headers: { 'X-Custom-Header': 'foobar' }
})
// !!!!这里需要注意的是:
// 你直接从官网上拦截器处cv过来的是配置在最原始的axios上的
// 你需要把下面的axios换成比如你在这里创建的新的instance
// 自定义配置 - 请求/响应 拦截器
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
// return response
// (默认axios会多包装一层data,所以我们这里打点一下data)
return response.data
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error)
})
// 导出配置好的实例
export default instance
- 创建实例&配置,导出实例
views/login/index.vue
js
import request from '@/utils/request'
export default {
name: 'LoginPage',
async created () {
//在智慧商城接口文档处找------获取图形验证码
const res = await request.get('/captcha/image')
console.log(res)
}
}
图形验证码功能完成
目标:基于请求回来的base64图片,实现图形验证码功能
js
export default {
name: 'LoginPage',
data () {
return {
picCode: '', // 请求用户输入的图形验证码
picKey: '', // 将来请求传递的图形验证码的唯一标识
picUrl: '' // 存储请求渲染的图片地址
}
},
async created () {
// 整个这个发请求的部分也可以封装成一个方法methods
this.getPicCode()
// const res = await request.get('/captcha/image')
// console.log(res)
},
methods: {
// 获取图形验证码
async getPicCode () {
// 基于返回的结果进行解析
const { data: { base64, key } } = await request.get('/captcha/image')
this.picUrl = base64 // 存储地址,设置给img src
this.picKey = key // 存储唯一标识,将来验证需要携带
}
}
}
</script>
然后在页面:src="picUrl"
渲染一下
js
//这里还加了一个v-if表示有图片的时候才会渲染,避免了刷新出现显示图片损坏
//把标签自带的alt=""删掉,不然点击事件不生效
<img v-if="picUrl" :src="picUrl" @click="getPicCode">
这样就可以得到图形验证码了,并且每次刷新都会更换,每次点击也会更换
api接口模块-封装图片验证码接口
目标:将请求封装成方法,统一存放到api模块,与页面分离
以前的模式:
采用封装api模块的模式:
就举我们刚刚写的的这个请求图片验证码的请求,把红色框部分封装到api里的login.js里(这里面可以存放所有有关login界面的请求),然后这一部分就可以替换成调用了
api/login.js
js
// 此处用于存放所有登录相关的接口请求
import request from '@/utils/request'
// 需要export导出(这里是按需导出,所以页面中也需要按需导入)
// 1. 获取图形验证码请求
export const getPicCode = () => {
// 必须加return,如果不加的话,将来在login的vue里就接收不到你返回来的promise结果了
return request.get('/captcha/image')
}
views/login/index.vue
js
const { data: { base64, key } } = await getPicCode()
---------------------------------------------------效果跟刚才一样^^成功
Toast轻提示
- 组件库导入
js
import Vue from 'vue'
import { Toast } from 'vant'
Vue.use(Toast)
- 调用
js
import { Toast } from 'vant';
Toast('获取图形验证码成功')// 组件内/非组件都可以,必须写导入
this.$toast('获取图形验证码成功')//只能必须在组件内,但是可以不写上面导入那条
短信验证倒计时
- 点击按钮,实现倒计时效果
从变量出发,在data里写
js
totalSecond: 60, // 总秒数
second: 60// 当前描述,开定时器,对second--
timer:null //定时器id
js
<button @click="getCode">
{{ second === totalSecond ? '获取验证码' : second + '秒后重新发送'}}
</button>
js
// 在methods中写
getCode () {
// 当前目前没有定时器开着,且totalSecond和second一致(也就是秒数归位)才可以倒计时
if (!this.timer && this.second === this.totalSecond) {
// 开启倒计时
this.timer = setInterval(() => {
console.log('正在倒计时...')
this.second--
// 避免减到负数
if (this.second <= 1) {
clearInterval(this.timer)
this.timer = null// 重置定时器
this.second = this.totalSecond// 归位
}
}, 1000)
}
},
// 这个是为了当你离开这个页面后把定时器停掉,不然你离开页面如果它没执行完就还会倒计时继续执行
destroyed () {
clearInterval(this.timer)
}
- 倒计时之前的校验处理(手机号、验证码)
由于校验这个功能比较通用,所以我们可以把它封装成一个方法
- 首先需要校验,那就需要先拿到这两个数据
- 所以我们需要在data中准备变量
- 准备了变量就记得在页面相应处v-model
- 还可以优化比如用个toast轻提示
js
mobile: '', // 手机号
picCode: '' // 请求用户输入的图形验证码
js
//methods中
// 校验 手机号 和 图形验证码 是否合法
validFn () {
// 以1开头,第二位3-9,再后面\d{9},即再有9个数字
if (!/^1[3-9]\d{9}$/.test(this.mobile)) {
this.$toast('请输入正确的手机号')
return false
}
if (!/^\w{4}$/.test(this.picCode)) {
this.$toast('请输入正确的图形验证码')
return false
}
// 只有上面两个都通过了校验,才return ture
return true
},
- 写完上面这两个校验,就可以跟下面的短信验证码联动了
- 如果上面没通过,就不用执行短信验证码了
js
// 获取短信验证码
getCode () {
if (!this.validFn()) {
// 如果没通过校验,就不需要往下获取验短信证码了
return
}
}
- 封装短信验证请求接口,发送请求添加提示
通过智慧商城的接口文档(登录-获取短信验证码),我们在自己的 api的login.js 里写上这个接口,之后页面调用一下就可以
js
// 2. 获取短信验证码
export const getMsgCode = (captchaCode, captchaKey, mobile) => {
return request.post('/captcha/sendSmsCaptcha', {
form: {
captchaCode,
captchaKey,
mobile
}
})
}
调用这个接口(在定时器倒计时方法处):
js
// 发送请求
const res = await getMsgCode(this.picCode, this.picKey, this.mobile)
onsole.log(res)
------------------------成功 \^o^/
看到 status: 200 就说明成功了!
在控制台看到成功后,就可以稍微修改一下代码,把log换成toast轻提示
js
await getMsgCode(this.picCode, this.picKey, this.mobile)
this.$toast('短信验证成功!')
登录功能
目标:封装api登录接口,实现登录功能
- 通过智慧商城接口文档,封装登录接口
js
// 3. 登录接口
export const codeLogin = (mobile, smsCode) => {
return request.post('/passport/login', {
form: {
isParty: false,
partyData: {},
mobile,
smsCode
}
})
}
- 登录前的校验
- 调用方法,发送请求,成功添加提示并跳转👇
js
//data提供变量
msgCode:''// 短信验证码
// 输入框绑定
<input v-model="msgCode" class="inp" placeholder="请输入短信验证码" type="text">
// 先注册触发校验方法的点击事件
<div @click="login" class="login-btn">登录</div>
js
import { codeLogin, getMsgCode, getPicCode } from '@/api/login'
// 登录
async login () {
if (!this.validFn()) {
return
}
if (!/^\d{6}$/.test(this.msgCode)) {
this.$toast('请输入正确的短信验证码')
return
}
// 如果这里的codeLogin显示没定义,就看上面import那里有没有从api那里导入这部分
// 但其实你在拼写的时候,系统提示你然后你回车不全后,它上面会自动帮你加上
const res = await codeLogin(this.mobile, this.msgCode)
console.log(res)
// 提示登录成功,并且跳转首页
this.$toast('登录成功')
this.$router.push('/')
}
},
默认密码:246810,成功\^o^/