技巧(不再更新,新内容移动到骚操作中)
# 解决遮罩层滚动穿透
@touchmove.prevent
# 1.屏幕旋转的事件和样式
事件:window.orientation,取值:正负 90 表示横屏模式、0 和 180 表现为竖屏模式
window.onorientationchange = function() {
switch (window.orientation) {
case -90:
case 90:
alert("横屏:" + window.orientation)
case 0:
case 180:
alert("竖屏:" + window.orientation)
break
}
}
2
3
4
5
6
7
8
9
10
11
样式
//竖屏时使用的样式
@media all and (orientation: portrait) {
.css {
}
}
//横屏时使用的样式
@media all and (orientation: landscape) {
.css {
}
}
2
3
4
5
6
7
8
9
10
11
# 2.audio 元素和 video 元素在 ios 和 andriod 中无法自动播放
应对方案:触屏即播
$("html").one("touchstart", function() {
audio.play()
})
2
3
# 3.移动端禁止选中内容
如果你不想用户可以选中页面中的内容,那么你可以在 css 中禁掉:
.user-select-none {
-webkit-user-select: none; /* Chrome all / Safari all */
-moz-user-select: none; /* Firefox all (移动端不需要) */
-ms-user-select: none; /* IE 10+ */
}
2
3
4
5
# 4.快速回弹滚动
在 iOS 上如果你想让一个元素拥有像 Native 的滚动效果,你可以这样做:
.xxx {
overflow: auto; /* auto | scroll */
-webkit-overflow-scrolling: touch;
}
2
3
4
PS:iScroll 用过之后感觉不是很好,有一些诡异的 bug,这里推荐另外一个 iDangero Swiper,这个插件集成了滑屏滚动的强大功能(支持 3D),而且还有回弹滚动的内置滚动条,官方地址:http://www.idangero.us/sliders/swiper/index.php
# 5.移动端如何清除输入框内阴影
在 iOS 上,输入框默认有内部阴影,但无法使用 box-shadow 来清除,如果不需要阴影,可以这样关闭:
input,
textarea {
border: 0; /* 方法1 */
-webkit-appearance: none; /* 方法2 */
}
2
3
4
5
# 6.什么是 Retina 显示屏,带来了什么问题
retina:一种具备超高像素密度的液晶屏,同样大小的屏幕上显示的像素点由 1 个变为多个,如在同样带下的屏幕上,苹果设备的 retina 显示屏中,像素点 1 个变为 4 个
在高清显示屏中的位图被放大,图片会变得模糊,因此移动端的视觉稿通常会设计为传统 PC 的 2 倍
那么,前端的应对方案是:
设计稿切出来的图片长宽保证为偶数,并使用 backgroud-size 把图片缩小为原来的 1/2
//例如图片宽高为:200px*200px,那么写法如下
.css {
width: 100px;
height: 100px;
background-size: 100px 100px;
}
2
3
4
5
其它元素的取值为原来的 1/2,例如视觉稿 40px 的字体,使用样式的写法为 20px
.css {
font-size: 20px;
}
2
3
# 7.移动端 click 屏幕产生 200-300 ms 的延迟响应
fastclick
可以解决在手机上点击事件的 300ms 延迟
zepto 的 touch 模块,tap 事件也是为了解决在 click 的延迟问题
触摸事件的响应顺序
1、ontouchstart 2、ontouchmove 3、ontouchend 4、onclick
解决 300ms 延迟的问题,也可以通过绑定 ontouchstart 事件,加快对事件的响应
# 8.移动端字体单位 font-size 选择 px 还是 rem
对于只需要适配手机设备,使用 px 即可 对于需要适配各种移动设备,使用 rem,例如只需要适配 iPhone 和 iPad 等分辨率差别比较挺大的设备 rem 配置参考:
html {
font-size: 10px;
}
@media screen and (min-width: 480px) and (max-width: 639px) {
html {
font-size: 15px;
}
}
@media screen and (min-width: 640px) and (max-width: 719px) {
html {
font-size: 20px;
}
}
@media screen and (min-width: 720px) and (max-width: 749px) {
html {
font-size: 22.5px;
}
}
@media screen and (min-width: 750px) and (max-width: 799px) {
html {
font-size: 23.5px;
}
}
@media screen and (min-width: 800px) and (max-width: 959px) {
html {
font-size: 25px;
}
}
@media screen and (min-width: 960px) and (max-width: 1079px) {
html {
font-size: 30px;
}
}
@media screen and (min-width: 1080px) {
html {
font-size: 32px;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 9.移动端如何定义字体 font-family
# 三大手机系统的字体:
ios 系统
默认中文字体是 Heiti SC 默认英文字体是 Helvetica 默认数字字体是 HelveticaNeue 无微软雅黑字体 android 系统
默认中文字体是 Droidsansfallback 默认英文和数字字体是 Droid Sans 无微软雅黑字体 winphone 系统
默认中文字体是 Dengxian(方正等线体) 默认英文和数字字体是 Segoe 无微软雅黑字体 各个手机系统有自己的默认字体,且都不支持微软雅黑 如无特殊需求,手机端无需定义中文字体,使用系统默认 英文字体和数字字体可使用 Helvetica ,三种系统都支持
移动端定义字体的代码
body {
font-family: Helvetica;
}
2
3
# 10.添加到主屏后的标题(IOS)
<meta name="apple-mobile-web-app-title" content="标题">
# 11. 启用 WebApp 全屏模式(IOS)
当网站添加到主屏幕后再点击进行启动时,可隐藏地址栏(从浏览器跳转或输入链接进入并没有此效果)
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-touch-fullscreen" content="yes" />
2
# 12.设置状态栏的背景颜色(IOS)
设置状态栏的背景颜色,只有在"apple-mobile-web-app-capable" content="yes"时生效
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
content参数:
default :状态栏背景是白色。
black :状态栏背景是黑色。
black-translucent :状态栏背景是半透明。 如果设置为 default 或 black ,网页内容从状态栏底部开始。 如果设置为 black-translucent ,网页内容充满整个屏幕,顶部会被状态栏遮挡。
2
3
4
5
6
# 13.IOS Web app 启动动画
由于 iPad 的启动画面是不包括状态栏区域的。所以启动图片需要减去状态栏区域所对应的方向上的 20px 大小,相应地在 retina 设备上要减去 40px 的大小
<!-- iPhone -->
<link href="apple-touch-startup-image-320x460.png" media="(device-width: 320px)" rel="apple-touch-startup-image">
<!-- iPhone (Retina) -->
<link href="apple-touch-startup-image-640x960.png" media="(device-width: 320px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPad (portrait) -->
<link href="apple-touch-startup-image-768x1004.png" media="(device-width: 768px) and (orientation: portrait)" rel="apple-touch-startup-image">
<!-- iPad (landscape) -->
<link href="apple-touch-startup-image-748x1024.png" media="(device-width: 768px) and (orientation: landscape)" rel="apple-touch-startup-image">
<!-- iPad (Retina, portrait) -->
<link href="apple-touch-startup-image-1536x2008.png" media="(device-width: 1536px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
<!-- iPad (Retina, landscape) -->
<link href="apple-touch-startup-image-2048x1496.png" media="(device-width: 1536px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
2
3
4
5
6
7
8
9
10
11
12
# 14.添加到主屏后的 APP 图标
指定 web app 添加到主屏后的图标路径,有两种略微不同的方式:
<!-- 设计原图 -->
<link href="short_cut_114x114.png" rel="apple-touch-icon-precomposed">
<!-- 添加高光效果 -->
<link href="short_cut_114x114.png" rel="apple-touch-icon">
2
3
4
图标尺寸:
可通过指定 size 属性来为不同的设备提供不同的图标(但通常来说,我们只需提供一个 114 x 114 pixels 大小的图标即可 )
官方说明如下:
Create different sizes of your app icon for different devices. If you’re creating a universal app, you need to supply app icons in all four sizes. For iPhone and iPod touch both of these sizes are required:
57 x 57 pixels
114 x 114 pixels (high resolution)
For iPad, both of these sizes are required:
72 x 72 pixels
144 x 144 (high resolution)
# 15.在手机端去掉以下标签的各种自带样式
a,
select,
span,
i,
input {
-webkit-tap-highlight-color: transparent; //无色
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); //这个地方的设置最好是用rgba
-webkit-appearance: none;
outline: none;
border: 0;
line-height: normal;
background: none;
}
2
3
4
5
6
7
8
9
10
11
12
13
# 16.解决手机 web 字号不一
body {
-webkit-text-size-adjust: none;
}
2
3
# 17.上传文件
基于 vue,省略非关键代码
<label for="resource" class="ui-upload">
上传
<!-- <i class="el-icon-upload el-icon--right" /> element-ui可使用 -->
</label>
<input id="resource" type="file" style="display: none;" @change="change($event)" />
<div>
<i v-if="ruleForm.resource.name" class="el-icon-document" />
{{ ruleForm.resource.name }}
</div>
2
3
4
5
6
7
8
9
data(){
return{
zip: new JSZip()
}
}
change(event) {
this.ruleForm.resource = event.target.files[0]
console.log('resource', this.ruleForm.resource)
}
/**
* 1、创建form对象
* 2、通过append向form对象添加数据
* 3、添加form表单中其他数据
* 4、FormData私有类对象,访问不到,可以通过get判断值是否传进去
*/
const formData = new FormData()
formData.append(
'audioFile',
this.ruleForm.resource,
this.ruleForm.resource.name
)
console.log(formData.get('audioFile'))
var html = new File(
[this.ruleForm.explainContentComputed],
`h5.html`,
{
type: 'charset=utf-8'
}
)
saveAs(html, `h5.html`)//下载到本地
this.zip
.generateAsync({
// 压缩类型选择nodebuffer,不压缩,在回调函数中会返回zip压缩包的Buffer的值,再利用fs保存至本地
type: 'blob',
compression: 'STORE'
})
.then(content => {
saveAs(content, `${unitNo}.zip`)
})
formData.append('file', html, html.name)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 18.时间格式化
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}"
let date
if (typeof time === "object") {
date = time
} else {
if (typeof time === "string" && /^[0-9]+$/.test(time)) {
time = parseInt(time)
}
if (typeof time === "number" && time.toString().length === 10) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay(),
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === "a") {
return ["日", "一", "二", "三", "四", "五", "六"][value]
}
if (result.length > 0 && value < 10) {
value = "0" + value
}
return value || 0
})
return time_str
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (("" + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return "刚刚"
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + "分钟前"
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + "小时前"
} else if (diff < 3600 * 24 * 2) {
return "1天前"
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() + 1 + "月" + d.getDate() + "日" + d.getHours() + "时" + d.getMinutes() + "分"
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80