H5开发小记

离职中。离职前最后一个项目是前端项目,用到了一些之前不了解的工具,也遇到不少的问题。预计接下来几年都不会再接触前端开发工作,但记录一下以备忘、拓展知识广度总是好的。

具体分成三类话题。

  • 工具
  • 问题
  • 技巧

工具

首先谈谈开发工具。Chrome Devtools 真是个神器。这里有篇介绍 Devtools 的文章。只挑几个我觉得特别有用的功能说说。

-w451

一是选择机型,便于在不同分辨率下调试。二是选中元素开关(点击一下后变成蓝色),打开后选择 html 页面中的元素非常方便

-w444

第三个是 Replay XHR 功能。只会刷新页面来重新发送 XHR 请求,太 low 了。其实 Replay 一下就足够了!

另一个好用的开发工具是 Vue.js devtools。怎么好用呢?看图。直接在 Vue.js devtools 中修改数据,UI 也随之变化。调试界面非常方便!

vuejs-devtools

问题

再来说说遇到的问题(或者说是坑)。

DOM 与 Vue.js

首先要说的一个坑就是在 Vue.js 中使用 zepto 操作真实DOM节点引起的一个看似诡异其实很好理解的愚蠢问题。你肯定会质疑为什么 Vue.js 会使用 zepto。实际情况是前端输出的重构文件中用到的 zepto,一是我懒二是确实也不知如何准确地将 zepto 代码翻译成 Vue.js,所以就出现 Vue.js 与 zepto 混用的情况。

大部分场景下这种做并不会有问题,直接这个点击用户名后编辑的功能:

edit-name

伪代码类似这样,其关键在于 vm.inputTeamName = newtxt

1
2
3
<p class="name">
<span>{{inputTeamName}}</span>
</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 更改名称
$(".btn-change").click(function() {
var td = $(this).siblings('span');
var txt = td.text();
var input = $("<input type='text'value='" + txt + "'/>");
td.html(input);
input.click(function() {
return false;
});
input.trigger("focus");
input.blur(function() {
var newtxt = $(this).val();
if(newtxt != txt) {
// 更新 inputTeamName
vm.inputTeamName = newtxt
td.html(newtxt);
} else {
td.html(newtxt);
}
});
});

不过这段代码时灵时不灵。我疑惑了好久。但仔细一想又很简单:操作 span 这个真实DOM节点后,就不能指望 {{inputTeamName}} 是可靠的了 (毕竟它跟 Vue.js 的虚拟DOM节点相关)

类似的情况还有操作过真实DOM节点后,v-model指令失效。原因也类似。

重名组件

封装了一个 RegisterDialog 组件,组件中指定了 id。

1
2
3
4
5
6
7
8
9
10
<template>
<div>
<div class="pop-wrap pop-bg02 pop-box01" id="pop-box01" style="display: none">
<h4 class="p-title">绑定手机</h4>
<ul class="phone-input">
</ul>
</div>

</div>
</template>

RegisterDialog 组件被多处使用。如下图:

-w502

发现有时操作不能按预期方式操作 RegisterDialog。比如,头像和昵称无法正常显示。推测问题原因是 RegisterDialog 导致 html 页面内元素 ID 冲突。

一种解决方式是使用更合理的页面结构,保证只有一个 RegisterDialog。如下图:

-w503

另一种解决方式是避免 RegisterDialog 组件中 div 元素的 ID 写死为 pop-box01,而是使用动态ID。

1
2
3
4
5
6
7
8
9
10
<template>
<div>
<div class="pop-wrap pop-bg02 pop-box01" :id="myID" style="display: none">
<h4 class="p-title">绑定手机</h4>
<ul class="phone-input">
</ul>
</div>

</div>
</template>

分享图白边

我们的H5在某些机型上生成的分享图会出现一条白边。如下图:

-w383

白边问题的原因是rem和px转化存在小数点。提前将rem转换成px即可:

1
2
3
4
5
6
7
8
fixDimen(domId) {
const ele = document.getElementById(domId);
if (ele) {
// 解决rem和px转化存在小数点,导致的白边问题
ele.style.width = `${ele.offsetWidth}px`;
ele.style.height = `${ele.offsetHeight}px`;
}
},

图片跨域

dom2img 库用于将 DOM 节点转换成图片。使用 dom2img 时要注意图片跨域问题。一种简单的解决办法是将托管在图片服务器上的图片保存到本地,同时修改部分css代码。

修改前:

1
2
3
4
<head>
<meta charset="utf-8">
<link href="https://image-1251917893.cos.ap-guangzhou.myqcloud.com/gp-match/css/match.css" type="text/css" rel="stylesheet">
</head>

修改后:

1
2
3
4
5
<head>
<meta charset="utf-8">
<link href="https://image-1251917893.cos.ap-guangzhou.myqcloud.com/gp-match/css/match.css" type="text/css" rel="stylesheet">
<link href="match.css" type="text/css" rel="stylesheet">
</head>

修改后本地新增一个 match.css 文件。这个css会重写几个样式(主要是将背景图片指向本地图片,而非图片服务器)以覆盖前一个css中某些规则,以避免图片跨域问题。

1
2
3
.xspr1 { background-image: url(img/xspr1.png); background-repeat: no-repeat; background-size: 9.94rem 5.18rem; }
.xspr { background-image: url(img/xspr.png); background-repeat: no-repeat; background-size: 9.92rem 11.21rem; }
...

技巧

内联CSS

有时需要在 Vue.js 中内联 css 文件。

比如我遇到这样一个问题。一些图片和css文件在测试环境中可以正常访问,但发布到正式环境就不行。

看 Chrome 提示推测是正式服务器 content-type 配置有问题,它将css文件的作为html返回了,所以无法正常加载css。随之引起图片跨域问题(该css是专门用来解决跨域问题的)

-w936

无奈我没权限修改正式服务器配置。于是换另一种思路,将 css 内存到 Vue.js。

修改前:在 index.html 引入 match.css

1
2
3
<head>
<link href="match.css" type="text/css" rel="stylesheet">
</head>

修改后:在 App.vue 引入 match.css

1
2
3
<style scoped>
@import './../../../public/match.css';
</style>

修改后成功绕过正式服务器的 content-type 配置问题,可正常加载 match.css,避免了随之而来的图片跨域问题!

使用图片

vue 文件中也可以直接使用图片。方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// register-dialog.vue

<template>
<img class="info-txt-1" :src="imgs.share_text" alt />
</template>

<script>
import head_name from 'src/module/xxx/img/head-name.png'
import headbox from 'src/module/xxx/img/headbox.png'

export default {
data() {
return {
imgs: {
head_name: head_name,
headbox: headbox
},
}
},
}
</script>

保存分享图

一个需求是这样的:用户长按h5保存图片时,实际保存的图片上要求有一个二维码和提示。

微信中如何长按图片保存的是另一张图片_小朱的专栏-CSDN博客中介绍了一种解决方案。

其他

-w102

  • chrome devtools 中快速qq登录 (一直觉得H5中QQ登录很麻烦,实际上是没有掌握技巧。使用 Toggle device toolbar 将浏览器切换成PC模式而不是Mobile模式,可以拉起PC端的QQ登录页,然后手机QQ扫一扫登录,非常方便)
  • 部署不同的 url 的环境 (修改 publish.js 脚本)
  • beforeDestroy 响应back 键回退时,以关闭 layer
  • 同名组件问题 (同ref或同ID)
  • 无法获取角色信息问题确认
  • 卡在ssl.ptlogin2.qq.com的问题 (短时间同一测试QQ号在多个Android机器上登录时容易出现这个问题)
  • 分环境部署 (修改 publish.js 中的 desc 即可)
  • css 作用域问题 (dialog 样式)

参考