项目开发笔记
一、 vue 路径的配置
配置方法有很多种,不同编译器大同小异,详细配置网上很多。
为了方便多次使用 ../../
路径,我们需要在vue.config.js 配置 @ 代表src目录:
let path = require("path");
module.exports = {
configureWebpack: (config) => {
config.resolve = {
extensions: ['. js', '. json', '. vue'],
alias: {
'@': path.resolve(__dirname, './src')
}
}
}
}
二、定义 Tabbar
(1)路由跳转:
switchTab(path) {
// 判断:如果是当前路由切换(二次点击当前路由),就不跳转,直接 return
if (this.$router.path == path) return
this.$router.replace(path)
}
(2)切换图标
<!-- 点击切换icon样式,router.path 如果包含 item.path 返回 true -->
<!-- 此时为选中状态,应该改变为选中状态的图标 -->
<img
:src="$route.path.includes(item.path) ? item.selected : item.default"
alt=""/>
(3)选中时更改字体颜色
-
原理同上,动态绑定 class样式
<span :class="$route.path.includes(item.path) ? 'active' : ''">{{ item.title }}</span>
效果:
三、目录分配
-
views
→ 用于存放页面 -
components
→ 用于存放组件 (页面中的一个个小模块) -
public
→ 这个需要注意,在data数据源里定义的静态资源路径
应该放在这。routerList: [ { /** * vue 导入图片的路径问题 : * 这里需要把 图片放在 public 文件夹下 (通过 './' 来获取图片) * 或者通过 require('@/assets/images/xxx.png')来导入 src目录下的图片 */ title: '首页', path: '/home', default: './tabbar/首页.png', //未选中默认图标 selected: './tabbar/home-selected.png' // 选中后修改图标 }, { title: '分类', path: '/list', default: './tabbar/分类.png', selected: './tabbar/list-selected-1.png' }, ]
三、Ly-tab切换展示插件
-
[安装方法] https://www.npmjs.com/package/ly-tab
-
引入:
// 移动端可滑动(惯性滑动&回弹)导航栏组件 import LyTab from 'ly-tab' Vue.use(LyTab)
-
使用:
<ly-tab v-model="selectedId" :items="items" :options="options"> </ly-tab>
数据源:
data() { return { selectedId: 0, items: [ { label: '推荐' }, { label: '金骏眉' }, { label: '大红袍' }, { label: '铁观音' }, { label: '绿茶' }, { label: '紫砂壶' }, { label: '漳平水仙' }, { label: '普洱' }, { label: '正山小种' }, { label: '茉莉花茶' }, { label: '建盏' }, { label: '大师壶' }, { label: '茶具' } ], options: { activeColor: '#407fdd' // 可在这里指定labelKey为你数据里文字对应的字段名 } } }
效果:
四、swiper 轮播图
安装和配置
高版本兼容性差,问题太多,使用低版本 3.1.3
npm install vue-awesome-swiper@3.1.3 -S
(1)导入 swiper 的css 样式时遇到的坑:
-
使用
cnpm
下载后,不知道是脚手架版本问题的缘故还是什么,使用官网提供的路径导入css样式报错(找不到 css)。-
先卸载 已经安装的 swiper
npm uninstall vue-awesome-swiper
-
使用 npm 重新下载
npm install vue-awesome-swiper@3.1.3 -S
-
(2)在组件内按需导入:
import 'swiper/css/swiper.min.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
或者在main.js
中全局引入:
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'
Vue.use(VueAwesomeSwiper)
组件中使用
<template>
<div class="swiper-main">
<swiper :options="swiperOption" ref="mySwiper">
<swiper-slide v-for="(item, index) in swiperList" :key="index"
><img :src="item.imgurl" alt=""
/></swiper-slide>
<!-- 如果需要分页器 -->
<div class="swiper-pagination" slot="pagination"></div>
<!-- 如果需要导航按钮 切换按钮(左右) -->
<div class="swiper-button-prev" slot="button-prev"></div>
<div class="swiper-button-next" slot="button-next"></div>
</swiper>
</div>
</template>
<script>
import navBar from "components/common/navBar/navBar";
import { swiper, swiperSlide } from "vue-awesome-swiper";
// 注意:这里导入的css位置 因版本而异
import 'swiper/css/swiper.min.css'
export default {
name: 'Swiper',
components: {
swiper,
swiperSlide
},
data() {
return {
// 轮播图片数据
swiperList: [
{
id: 1,
imgurl: './images/swiper/s-01.jpg'
},
{
id: 2,
imgurl: './images/swiper/s-3.jpeg'
},
{
id: 3,
imgurl: './images/swiper/s-02.jpeg'
},
{
id: 4,
imgurl: './images/swiper/s-4.jpeg'
}
],
//swiper 初始化
swiperOption: {
loop: true,
autoplay: {
delay: 3000, // 自动轮播切换时间
stopOnLastSlide: false,
disableOnInteraction: false
},
// 显示分页
pagination: {
el: '.swiper-pagination',
clickable: true //允许分页点击跳转
},
// 设置点击箭头
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
}
}
}
}
</script>
<style lang="less" scoped>
.swiper-main {
width: 100%;
height: 4.4rem;
margin-top: 1.706667rem;
img {
width: 100%;
height: 4.4rem;
}
}
</style>
效果:
五、修正移动端布局顶部和底部问题
滑动时候 使用 fixed 固定住的头部被遮盖
解决思路:
- 给页面加一个 100% 的 vh 高 vw宽。
- 头部和底部 使用 fixed 固定,设置宽高。
- 然后中间内容是 flex :1 , 高度为自适应。
效果:
六、better-scroll 滚动插件
vue中的 ref 获取 Dom
设置:<div ref='aaa'></div>
获取:this.$refs.aaa
(1) 下载和引入
npm install better-scroll -S # 安装带有所有插件的 BetterScroll
npm install @better-scroll/core # 核心滚动,大部分情况可能只需要一个简单的滚动
(2)使用方法
import BetterScroll from 'better-scroll'
// 第一种:在vue中 通过ref引用操作dom
mounted() {
new BetterScroll(this.$refs.wrapper, {
movable: true,
zoom: true
})
}
// 第二种:使用class类操作dom
mounted() {
new BetterScroll('.wrapper', {
movable: true,
zoom: true
})
}
滚动原理:
子盒子
必须比父元素高
才能实现滚动。- 在 vue 中实例化滚动插件必须在 mounted 生命周期内
- new 出来的对象里面的第一个参数
class 类样式应该指向父盒子
。
七、vue 中实现当 dom更新完再加载?
this.$nextTick(()=>{
})
解决下拉刷新空白bug
(1)切换ly-tab 页面后的遮盖问题
- 去掉父元素的高!
(2)下拉刷新空白
在使用 better-scroll 滚动的时候会计算子盒子的高度值, for循环渲染页面时候,无法计算子盒子高度,解决方法:等dom都有了再调用 better-scroll 。
怎么实现当DOM都元素加载完毕后再执行?
- 使用vue 提供的 this.$nextTick()方法。
// 当DOM都元素加载完毕后再执行
this.$nextTick(() => {
// 轮播图实例化
new BetterScroll(this.$refs.wrapper, {
movable: true,
zoom: true
})
})
问题解决。
八、二次封装 axios
在企业项目中,一定会对 axios 进行二次封装,提升代码复用和可维护性。
为什么二次封装?
- 解决下拉空白bug每次请求不同页面都需要实例化滚动插件。
- 解决每次刷新页面都要添加 lodding 加载和关闭效果问题。
在 src 新建一个 api
文件夹并新建一个 request.js
文件
// lodding效果
import { Indicator } from 'mint-ui'
import axios from 'axios'
export default {
common: {
method: 'GET',
data: {},
params: {}
},
$axios(options = {}) {
options.method = options.method || this.common.method;
options.data = options.data || this.common.data;
options.params = options.params || this.common.params;
//请求前==》显示加载中...
Indicator.open('加载中...');
return axios(options).then(v => {
let data = v.data.data;
return new Promise((res, rej) => {
if (!v) return rej();
//结束===》关闭加载中
setTimeout(() => {
Indicator.close();
}, 500)
res(data);
})
})
}
}
九、better-scroll 默认取消的事件
(1)、better-scroll 默认取消 click 事件
二次解决下拉插件问题:
在实现点击左侧商品分类跳转到对应商品列表除加入点击事件后无法触发。
解决:
//左侧滑动
new BetterScroll(this.$refs.left, {
// better-scroll 默认取消 click 事件
click: true
})
(2)、better-scroll 默认取消 scroll 事件
在实现滑动获取页面高度时候添加了 scroll 事件后无法触发。
解决:
-
probeType
: 默认为0 -
建议改成:
2 | 3
//右侧滑动
this.rightBScroll = new BetterScroll(this.$refs.right, {
click: true,
probeType: 3
})
十、路由传值
显式:
this.$router.push({
path:'/detail',
query:{
id
}
})
隐式:
this.$router.push({
name:'Detail',
params:{
id
}
})
区别
显示会在hash链接(也就是网址) 携带参数
,隐式则相反。
解决购物车页面点击返回报错:
十一、vue中的 keep-alive 组件:
keep-alive
: 是一个vue的内置组件。
作用:缓存组件
优势:提升性能
只要用到keep-alive会再多俩个生命周期 : activated
、deactivated
keep-alive 缓存问题
- 换账号登入后发现购物车页面还是上一个用户的购物车数据。
排查时发现:
- 购物车页面的
created 生命周期
不执行。 - 我在 App.vue组件加入了全局 keep-alive 缓存。
解决办法:
- 设置 keep-alive 缓存路由,也就是说,指定需要的路由去添加 keep-alive 。
在 App.vue中 设置:
<template>
<div id="app">
<!--要缓存的路由-->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!--不缓存的路由-->
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
在 router文件下的 index.js
购物车路由添加 meta
:
{
path: "/detail",
name: "Detail",
meta:{
keepAlive: false // 此组件不需要缓存
},
component: () =>
import("../views/Detail.vue"),
},
十二、接入短信验证码 SDK
API链接:https://github.com/qcloudsms/qcloudsms_js
下载
npm install qcloudsms_js
后端编写:
//发送短信验证码
router.post('/api/code', function (req, res, next) {
let tel = req.body.phone;
// 短信应用SDK AppID
var appid = 1400187558; // SDK AppID是1400开头
// 短信应用SDK AppKey
var appkey = "dc9dc3391896235ddc2325685047edc7";
// 需要发送短信的手机号码
var phoneNumbers = [tel];
// 短信模板ID,需要在短信应用中申请
var templateId = 285590; // NOTE: 这里的模板ID`7839`只是一个示例,真实的模板ID需要在短信控制台中申请
// 签名
var smsSign = "三人行慕课"; // NOTE: 这里的签名只是示例,请使用真实的已申请的签名, 签名参数使用的是`签名内容`,而不是`签名ID`
// 实例化QcloudSms
var qcloudsms = QcloudSms(appid, appkey);
// 设置请求回调处理, 这里只是演示,用户需要自定义相应处理回调
function callback(err, ress, resData) {
if (err) {
console.log("err: ", err);
} else {
// console.log("err: " + ress, "resData" + resData);
res.send({
code: 200,
data: {
success: true,
data: ress.req.body.params[0]
}
})
}
}
var ssender = qcloudsms.SmsSingleSender();
//这个变量:params 就是往手机上,发送的短信
var params = [Math.floor(Math.random() * (9999 - 1000)) + 1000];
ssender.sendWithParam(86, phoneNumbers[0], templateId,
params, smsSign, "", "", callback); // 签名参数不能为空串
})
十三、 token 令牌
token
是一个令牌,用来验证用户的。
- 作用(场景) :
验证用户
- token 是
后端生成
的 , 并且token是不能重复
的
下载插件 :
npm install jsonwebtoken
引入:
require('jsonwebtoken');
生成token语法:
jwt.sign( 用户信息 , 口令 , 过期时间)
解析 token:
jwt.decode(token);
Token使用流程:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据。
十四、 使用vuex绑定复选框联动的问题
-
在实现购物车界面复选框联动效果(点击全选选中所有商品,只要有一个未选中就取消全选按钮的选中状态)。
-
vuex属于单项数据绑定,若果使用 v-model,等于直接修改了state数据源里的值,在vuex中是不允许的,所以会报错。
-
这里需要使用
: value
解决。
实现思路:
-
请求到用户购物车数据后给每一项添加一个 cheeked = true状态
-
拿两个数组(购物车数据 和 选中的数据 )做对比,如果长度相等,就是全选,反之全不选。
开发 bug 日记
vant 组件收货地址传值问题
在收货地址页面,点击收货地址任一列表,进入编辑时,后端应该把数据传入编辑页面,但是传值的时候,地址显示不出来,必须传入areacode码。
购物车 页面bug
购物车页面从新刷新后 复选框失效:
- 完成功能的思路是对比两个数组长度来判断选是否非全选
- vuex中每次进去购物车页面都是用了forEarch去push选中的数据的id。
- 把循环删除,直接让selectList = CartArr
- 问题解决!
然后点击购物车商品的复选框,会莫名其妙在下面新增一条购物车商品。
⁃ Ctrl+z x10
商品页面添加相同商品到购物车不会累加数量而是在购物车页面新增了一条购物车商品列表。
⁃ 重写后端代码!
十四、 使用vuex绑定复选框联动的问题
[外链图片转存中…(img-XJohN3eR-1639888611450)]
-
在实现购物车界面复选框联动效果(点击全选选中所有商品,只要有一个未选中就取消全选按钮的选中状态)。
-
vuex属于单项数据绑定,若果使用 v-model,等于直接修改了state数据源里的值,在vuex中是不允许的,所以会报错。
-
这里需要使用
: value
解决。
实现思路:
-
请求到用户购物车数据后给每一项添加一个 cheeked = true状态
-
拿两个数组(购物车数据 和 选中的数据 )做对比,如果长度相等,就是全选,反之全不选。
开发 bug 日记
vant 组件收货地址传值问题
在收货地址页面,点击收货地址任一列表,进入编辑时,后端应该把数据传入编辑页面,但是传值的时候,地址显示不出来,必须传入areacode码。
购物车 页面bug
购物车页面从新刷新后 复选框失效:
- 完成功能的思路是对比两个数组长度来判断选是否非全选
- vuex中每次进去购物车页面都是用了forEarch去push选中的数据的id。
- 把循环删除,直接让selectList = CartArr
- 问题解决!
然后点击购物车商品的复选框,会莫名其妙在下面新增一条购物车商品。
⁃ Ctrl+z x10
商品页面添加相同商品到购物车不会累加数量而是在购物车页面新增了一条购物车商品列表。
⁃ 重写后端代码!