title: Hi运动商城 date: 2017-12-28 tags:
文档整理参与者请写下你的大名
文档整理(2019/12) 整理人 杜文华
环境 | 域名 |
---|---|
正式环境 | http://wx-shop.hiyd.com |
测试环境 | http://test-wx-shop.hiyd.com |
预发环境 | http://new-wx-shop.hiyd.com |
嵌入微信公众号中
原因有:
TypeScript + Vue-Cli3.x + Vue2.6x(配合 Composition-api 支持部分 3.0 的新特性) + Vuex + Vue-Router + scss + fetch(原生 fetch) + Mint-UI + Jest
...
- dist
- node_modules
- public
- src
- api --- 业务逻辑
- assets
- components --- 公共组件(也可以称为纯UI组件)
- router
- routes --- 路由表
- store --- 公共数据流
- styles
- views
- tests --- 这里的tests不是jest,是在页面上测试的
- activity --- activity写具体的活动名字 是以活动为单位 (exam:redPacket )
- ...
- components ---- 针对该View的组件(业务组件)
- ...
- tests ---- jest单元测试(可针对某些特殊的进行测试)
- ... ---- 其他配置文件
...
(2020/3/18 注:后续新增活动可以以活动为单位,进行项目架构。例如:红包活动直接一个文件夹,在分出来页面和组件等,单独一个整体存在。假如后续不需要也可以不需要侵入性的修改,包括其他在其他页面侵入式修改的组件都应该在活动里面编写,保持模块中的共同做法)
(tips:当时接触的时候,没有去详细了解写法。可以尝试的是,将 Script 部分的逻辑抽离到一个 ts 文件中,ts 文件里写一个 composition 函数,返回你需要的逻辑,2020/2/10 注)
(tips:在 composition 的函数中,返回的 reative 的 state 要用 toRefs 包裹,这样可以防止丢失响应式。在解构或者是扩展运算符的操作情况下就会出现这样的问题,2020/3/9 注)
shop shop主页
order 订单页
category 分类
marketDetail 中间部分推广的详细页
productDetail 所有产品的详细页
orderDetails 订单详细
express 查看快递的详细页
paySuccess 支付成功页
search 搜索页
shopcar 购物车
confirmOrder 确认支付
address 地址管理
login H5的专属登录
index (本来以为tab栏也是H5做的,但是后来是安卓做的,所以就不用了)
// redPacket 新加的路由
newUser 新人用户专享路由
ticket 可使用券
shareActivity 分享活动
// 测试的路由
test 付款的测试
test2 登录的测试
公众号的测试可能有点复杂,需要每次更改都需要打包到测试环境才能测试。因为微信公众号只能识别线上的地址,本地开发配置 host 的地址,微信不能识别
尝试一:postcss-pxtorem + 仅仅计算转换后的数值
结果: 跟设计稿相差甚远,最好不要仅仅转换数值
尝试二:postcss-pxtorem + 修改后的公式(px2rem = px / 750 /640 /1.5 / rem)
结果: 看上去可能好一点,实际上不太行还是得重新弄
最终尝试:postcss-pxtorem + flexable
原理: 因为 pxtorem 转换后的是根据 rem 进行修改的。配合 flexable 进行修改 rem 的数值到达屏幕适配的目的
// 这里特殊说明一下,都是通过cookie进行保存信息的,但是后端一开始是写不进去的,最后是前端进行写入cookie的操作。后面看的时候需要小心这里
// 登录逻辑分三步 login - blank - shop/other
1. login 逻辑是 调用weixin/login接口,然后获取到对应的信息之后,跳转到blank
2. blank是一个中间页面。只是用来写入cookie的操作。
3. 最后写完cookie之后就看 是跳详情页 还是 shop页了
2 假如出现 totalFree 问题,这个是后端计算的问题,跟我们没什么关系
首页的 tab 是用插件(vue-awesome-swiper)做的,这个插件是基于 Swiper 的,想要找的 Api 就去 Swiper 上找。这里有一个问题就是,当 tab 已经是 fixed 固定在视图的最上方的时候,假如进去了详情页再返回时,会因为缓存的原因停留在选中的 tab 上。但是也会因为这个 fixed,点击其他 tab 的时候,激活 swpier 插件使得 swpier 返回到最初的地方。(可能是 fixed 跟 transform 无法兼容的问题)
这里做的尝试有(1)进去详情页之前先记录当前的 transform 的距离,然后返回的时候动态加上。但是又会因为激活的原因返回到第一个 tab。(2)假如是点击的时候每次进行改变,这样也会跟原来的 transform 冲突,返回的位置也会不一样。
最终找到了官网上的一个方法,可以应对这个场景。但是会有一个问题就是会出现一个过渡的 300ms 的过渡动画。
这里有全面屏和非全面屏的问题。因为要适配这两种屏幕,所以我动态计算了高度。然后通过计算当前的高度和文档的高度,进行取舍。但是又因为有头部的原因,需要把头部剪去。但是这里会出现因为适配之前已经计算好了 rem 的原因。剪去的高度不一。在不同的屏幕上也会出现问题。这里主要是适配了全面屏。非全面屏这里,会出现高度溢出的状况(暂时能想到这种解决方法)
(3.9 新增)通过 flex 布局 + min-height:100vh 实现。min-height 的意思是最小值是 100vh。1vh = 屏幕的 1%。
两种方法解决:(1)用 div 模拟成 input 框的样子,自然就不会有键盘的唤醒了(好像有点违背原来的想法)(2)将输入框设置成 readonly 属性就可以不唤醒键盘
在 focus 的时候记录当前的 scrollElement 的高度,在 blur 还原
// IOS 上 键盘弹回的操作
handleSaveScrollTop() {
if (document.scrollingElement) {
// data 记录当前的scrollTop 感觉得hack 因为可能有些没有这个对象
data.scrollTop = document.scrollingElement.scrollTop;
}
},
handleChangeScrollTop() {
if (document.scrollingElement) {
// data 记录当前的scrollTop 感觉得hack 因为可能有些没有这个对象
document.scrollingElement.scrollTo(0, data.scrollTop);
}
},
当时后端无法写入 Cookie,不知道是什么问题。然后前端写 cookie 也有一个问题,信息可能会被盗取的可能,毕竟没有写入 httpOnly
export function setCookie(name: string, value: string) {
const expiresDays = 10; // 过期时间是10天
let date = new Date();
date.setTime(date.getTime() + expiresDays * 24 * 3600 * 1000);
// 这里的document.cookie 直接等于不用加号
document.cookie =
name +
'=' +
escape(value) +
// 记得这里的分号 ,少一个分号就写不进去
';expires=' +
// 这里的时间要转换一下
date.toUTCString() +
// 域名也得写正确
';domain=hiyd.com;path=/';
}
路由 hash 的问题,微信可能会屏蔽 hash 后面的值,导致后面的 url 可能会对签名有问题。可以做的方法是跳到另外一个页面在做。 (1)请求完接口后,让后端去签名然后支付完再回来前端 (2)hash 问题直接换 hash 就行了,用 history(需要后端代理一下 )
WeixinJSBridge.invoke:
(1)刚开始发现的是参数不对,那个 timestamp 转成字符串后某些机型就可以了
(2)这种方法在安卓上行不通,某些机型偶尔可以支付一下,但是大部分都不行。可能是因为 WeixinJSBridge 的问题。一直无法监听 onWeiXinBridgeReady 方法
WXSDK:
这种方法就是后端返回一堆东西,前端直接调用微信的 sdk(这种方法不知道会不会有风险,但是只有这种办法暂时能兼容安卓和 IOS)
// 巨坑之 timestamp 大小写问题
wx.config({
appId: res.data.config.appId,
timestamp: res.data.config.timestamp,
nonceStr: res.data.config.nonceStr,
signature: res.data.config.signature,
jsApiList: ['chooseWXPay'],
});
wx.ready(() => {
wx.chooseWXPay({
nonceStr: res.data.platform_data.nonceStr,
package: res.data.platform_data.package,
paySign: res.data.platform_data.paySign,
signType: res.data.platform_data.signType,
timestamp: `${res.data.platform_data.timestamp}`,
success: ret => {
state.success = true;
},
});
因为刚开始使用的是别的地方的 appid,突然换一个公众号的时候,session_id 仍然存在,保留了之前的登录信息,所以 appid 也就不匹配了 解决方法是清除缓存就可以了。
(1)在谷歌浏览器中调试刚好的高度,然后通过这个高度进行判断(存在的问题是,全面屏跟普通屏不能适配)
(2)后来通过document.documentElment.scrollTop
来动态计算高度,也是不太准
(3)最后是通过 offsetTop 和 getBoundingClientRect 来适配机型。
// 最终方案
window.addEventListener('scroll', function() {
if (nav.getBoundingClientRect()) {
data.positionFixed = nav.getBoundingClientRect().top < 0;
} else {
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
let offsetTop = getOffset(nav, 'top');
data.positionFixed = scrollTop > offsetTop;
}
});
(2020/3/10注:此类做法要用一个新的空的div来包裹,防止抖动的现象)
(定位1)首先定位是否是IOS的问题 当时 嘉智家里人安卓测试了没问题,
我通过各位同学的测试后,发现确实安卓基本都通过,由此可以暂时确定IOS有问题
(定位2)后来让慧慧家里的人测试,还有IOS的朋友,发现IOS也没问题,锁定是否是6s plus的问题
(定位3)最后第二天找了其他三台6s plus测试,最终结果如下
微信版本都是 最新的
6s plus 13.1 有问题
6s plus 13.2 没问题
6s plus 12 没问题
6s plus 10 没问题
最终锁定就是慧慧手机的问题
最终解决方法是(不管是安卓还是IOS空白的解决方法)
3. 用户双金home键,关闭微信重新打开微信
4. 在空白页面点击右上角的”刷新“
5. 注销微信账号,然后关闭微信,重新登录微信
6. 等待一段时间,重新点击公众号登录
据某位IOS初级开发说:就是把账号也退出了,再等到微信自己把东西都清干净
这里有一个问题:(1)是否微信内部打开网页都不能打开,(2)是否仅仅是自己的应用无法打开(3)是否外面的问题
这里假如出现空白搜到的几种问题
(1) JS 内部报错,导致无法继续下去(出现一次路由栈爆了)
(2) 微信浏览器或者是自身浏览器缓存机制的问题(IOS 的)
(3) 可能是浏览器兼容性问题,某些属性无法使用导致 空白屏
(2020/3/13) 当晚确定的问题是 安卓手机跟 IOS 手机 判断没有 cookie 的返回值不一样,导致路由无法进入 然后页面空白
function getCookieParam(name: string, str: string = `${document.cookie};`) {
// 这里IOS的问题 是 result === null 而不是undefined 而且 某些苹果里面会存在一个 device-token的 这种手机 就会报错
...
return result === undefined || result === null
? ''
: unescape((result as any)[1]);
...
}
当判断是否是登录的情况,是判断 cookie 是否存在,但是我的方法里面是默认 document.cookie 是存在的,当浏览器清除了以后,document.cookie 就不存在了,所以方法报错,导致路由栈爆了。
还有第二个爆栈的原因,就是应该将'/login'的路由剔除,不然会重复也会爆栈
问题1. 是复制的时候 相当于分享的操作的时候。头部的返回都得返回到首页
之前有做vuex的全局管理,进入的时候就记录一下,上面全局头部进行判断的时候就可以返回了
问题2. 当不是login进去的时候,都得检查是否是有登陆 不然就会跳转 到 登录进行 登录一系列操作
这里的问题是,假如是详情页进去的话,还得将首次进入的url保存。然后登录完之后拿出来跳到该url中
这里我使用了sessionStorge,保证的是用户只有打开的时候生效,离开就不生效的做法
问题3 最后需要关注的是公众号内部的问题。马上关注的链接打开之后,是缺少关注按钮的。所以最后用了二维码代替
问题4 假如想要直接从外部浏览器跳微信浏览器,这里有一个最直接的侵入式操作,就是使用微信的协议。但是这个协议需要花钱 慎重考虑
问题 1. 需要点击两次才能有反应(仅存在于请求后端的时候,返回才做操作)
方案一: 这里有一个 hack 的方法,就是 root.\$nextick 在去复制操作。但是好像没有效果
方案二: 有一个 mouseteer 的方法,并且仅执行一次,来 hack
问题 2. 点击次数越多,复制次数递增
方案一: 每次生成之后就销毁再生成
问题 3. 原生复制在浏览器上面是无法使用的,被迫无奈使用了这个库,谁知道还是有问题的。后面有更好的想法可以替换
问题: 首先是从分享进去就无法点击了,然后在看到那个商品无法点击的时候,就推断报错了。但是没有反应,后面发现报了 product_id 为空
是因为那件商品已经下架了。但是没有下架的提醒,所以报错了导致无法点击
描述:分享存在两种不同的状态,是否存在登录态。登录态通过 cookie 判断(这里保证 cookie 是存在的),分享的时候还得记录当前的 url,在没有登录的时候需要登录流程 过完之后,再回来记录的 url。但是这个 url 不能用 sessionStorage 来存储,某系机型因为这个原生 Api 不能存储导致报错。最后还是选择了 localStorage
描述一下因为换了个后端 所以有一些数据返回的类型还有值 都要发生变化。可能得要重新封装一层数据才能使用,所以要认真看一下 redPacket
头部有一个公共头部 就是添加返回的那个,还有一些零零散散自己的头部这些都要针对性的调整。调整的时候因为是点击之后就没了 tips,而且又因为不同的 state 控制的,所以就得放到全局里边去了。(header.vue/ tipsHeader)
这里还没有完成,还需要增加对应的接口返回知道是否已经关注了公众号如果没有关注的才需要显示,已经关注了就不需要在显示了
cliboard.js 这个东西需要两次点击才可以,原因是在点击的时候 DOM 还没有更新。或者说 DOM 节点还不存在。所以第二次点击的时候 DOM 才会存在。这个时候很简单 nextTick 在处理就可以。那为什么 SetTimout 之后不行呢?其实我在怀疑是不是 nextTick 又降为用 SetTimout 了。(也有 hack 的手法但是不能作为一种解决方案)
这个把使用券弹窗跟页面分离,通信成本增加。这里主要是父组件请求(查看减少价格的接口)还是子组件查看。按钮是在子组件的
尝试 1:子组件进行请求。这里需要的参数有 goodsId 跟 takesId,goodsId 直接从父组件拿到,takeId 是动态更新的,子组件选中后就更新一次,但是这里有一个问题子组件只知道当前的 takeId,但是他不知道外面还有多少选中的 takeId,所以还得让父组件通过 props 传进来后,watch。这里就有一个问题了。到底是 watch 先还是赋值先的问题了。经过实践是 watch 先赋值后(这里的赋值是自定义事件,可能排在 watch 的后面吧)。所以效果就是每次点击都是拿的上一次的值....尝试失败
尝试 2:父组件请求。父组件将请求封装成方法传递给子组件,然后子组件直接点击触发。搞定。逻辑上也说得通。因为请求的结果是父组件样式的修改,所以返回的数据可以直接作用于父组件,而不用继续透传 props 修改子组件的样式了。
这里的使用券还有一个问题就是要封装数据(请仔细看 confirmMessage.vue)
解决方法:ngnix 没有代理的话就代理一下。接口没有请求到就得看是否 baseUrl 的问题
nice_price 不会存入数据库的,这是一个内存字段。注意:只有红包的逻辑,逻辑包括什么(红包商品,该商品的下单,使用红包的时候等等),相关的价格全部使用这个字段,其他时间都可以用原本的 privilege_price,在使用之前一定要判断sell_price_rule参数这个参数就是是否使用ruleId的
花了几天重构了一下商品详情页,整体感觉比较舒服,也很明了,一些函数调用方面看参数都应该知道是什么情况。但是因为拆分了组件的原因。所以可能通信成本增加,本来重构过后的通信就难以理解,这部分可能还得继续考虑该如何进行下一步的优化(productDetail)
字体大小影响了布局的问题。因为有些老年人需要放大字体,然后设置了微信的字体大小后,打开微信的浏览器样式就会崩,我们可以使用weixin提供的bridge来实现重新调整fontsize的大小(@/utils/ajustFont.js)
公众号头部没有完成只是隐藏了。后续如果加上的话把样式隐藏的加起来就好
解决了首页商品缓存的问题,在首页实现一个路由钩子,在返回的时候将一个标志update置为true,进去首页的时候置为false,通过update透传props进nav组件,通知nav进行数据更新。(涉及几个问题 v-for问题,钩子触发的问题)