Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 

Repository files navigation

目录

117. rem单位border-radius:50%在安卓手机中画圆变形
116. 手机安装Charles的https证书
115. mac webstorm 配置 dart 插件
114. vsCode 安装 dart 插件
113. nginx 配置 http 强转 https
112. 记录一些 nginx 常用的全局变量
111. nginx 配置 https 报错问题
110. vsCode git 操作提示 Permission denied, please try again
109. 微信小程序设置超出行显示 ... 与展开更多按钮
108. 微信小程序设置超出隐藏,点击加载更多实现动画效果
107. vsCode 配置 easy sass 插件转换 css、wxss、acsss
106. vsCode 配置 easy less 插件转换 css、wxss、acss
105. 微信小程序中 input 的自定义删除按钮点不了
104. 微信公众号通知和服务通知
103. 微信小程序 1rpx border ios 真机显示不全
102. 微信小程序 webview 页面刷新
101. mac nginx 初次配置的默认路径
100. position 设置属性 absolute 之后,width 的值出现不固定
99. ios微信小程序中 input 输入框问题,输入的光标中的内容自动清空
98. window.__wxjs_environment 为 Undefined
97. audio 标签自动播放不起作用或者 play() 报错
96. a 标签 download 属性不起作用,或者下载的图片无法查看
95. 富文本解析 wxParse 解析数据造成页面假死
94. 微信小程序页面按钮分享好友缩略图截取顶部
93. git dist 目录排除不了
92. 微信小程序 canvas 问题
91. 微信小程序 wx.reLaunch 执行前几个页面的 onUnload 钩子
90. 微信小程序输入框属性 cursor-spacing 问题
89. 微信小程序输入框会字体显示不全或者换行
88. 微信小程序同一个页面压入历史栈两次,返回第二次页面没数据
87. padStart is not a function
86. 微信小程序Push场景本地调试方法
85. webpack vue 打包优化
84. 荣耀 10 字体显示错误,顶部部分遮掩
83. mpvue 中插槽 slot 没有渲染出来
82. 微信小程序同声传译 Face2FaceTranslator 开发
81. ios 手机端 input 框上方有内阴影
80. wx.showToast() 在真机中闪烁一下消失
79. webpack 热更新优化
78. 华为 mate8 拍照上传图片失败
77. vue 在 model 修改的数据没有响应式
76. node 获取本机 ip 地址
75. wepy mpvue 和原生开发小程序对比
74. mpvue 配置 tabBar 图片路径出错
73. input 聚焦掉起键盘,并且只能输入数字
72. webpack 构建 npm 包优化
71. parcel 报错问题
70. npm 发布更新包失败问题
69. ios 上浏览器返回上一页不会刷新页面问题,页面初始化的方法不执行
68. vsCode 开发微信小程序插件
67. vsCode 配置 html 文件警告
66. 移动端页面viewport缩放比不等于1时文本膨胀现象
65. IE6.0-8.0不支持使用 rgba 模式实现透明度
64. 在微博浏览器上背景问题
63. 埋点时,hash 改变没出发 hashChange 事件
62. input 上传第二次不能选择同一文件
61. im 聊天中视频播放
60. 移动端 click 事件
59. 上传图片预览图片方向错误
58. im 聊天输入框高度问题
57. 美团技术交流记录
56. FileReader 对象
55. ios9 中登录注册多出一条黑线
54. ios9 以下 flex 兼容问题
53. H5 中调相机、多选等问题
52. 推荐医生白色区块问题
51. 推荐医生头像问题
50. IM中输入框的问题
49. iscroll 和 better-scroll
48. better-scroll的实现原理
47. scroll 事件的触发
46. ios 上 IM 页面路由跳转白屏
45. Safari 中双指放大缩小问题
44. vue 中的通信
43. es6 新增方法处理
42. 页面唤起拨打电话
41. vue 双向绑定数据限制长度
40. vue中 v-if 遇到的问题
39. vue中 keep-alive 的使用
38. 数组的过滤器 filter 的问题
37. 在不翻墙的情况下下载vue调试插件(vue-DevTools)
36. vue中 v-if 和 v-show
35. 视频中的坑
34. 滚动穿透问题
33. app引导页的判断
32. 页面跳转的方式以及区别
31. 什么是 URL Schema?
30. app 与 js 之间的交互
29. window.name 的使用
28. 代码计时器
27. canvas图画保存成本地图片的方法
26. json 的注意事项
25. input 输入框输入中文
24. 输入框的事件的几种触发事件对比
23. jQuery 中 data() 引发的错误
22. js打开新页面的几种方式
21. 跨域的方式
20. select 默认选中问题
19. 兼容脚本
18. 移动端 border 宽度问题
17. flex布局中的注意事项
16. jQuery选取元素
15. 布局垂直对齐的方式
14. cookie 和 session 的区别
13. 自动登录的实现
12. 移动端的几种适配
11. jQuery中判断一个元素是否显示或者隐藏
10. ios中的一些兼容问题
9. require.js 做单页面应用
8. 分享qq空间出现失败
7. img 标签边框问题
6. filezilla连接服务器连接不上
5. 自执行函数的使用
4. 按钮置灰不能点击的方法
3. 给元素添加事件满足的条件
2. jQuery 中 trigger 的使用
1. stick footer 黏性底部

117. rem单位border-radius:50%在安卓手机中画圆变形

问题描述

使用border-radius:50%,或者border-radius的值与宽高相等,都可实现一个完美的圆形,但是在不同的安卓手机中,会有不同程度的变形(有的扁圆,有的大,有的小);当使用px做为宽高的单位,border-radius:50%画出来的圆是不会变形的;但使用rem时,rem在换算为px时,会是一个带小数点的值,安卓对小于1px的做了处理(不同浏览器对小于1px的处理方式不同,有的采用四舍五入,有的大于某个值展示1px否则就舍去),从而导致圆角不圆;在ios下就没有这个问题。

解决方案

  • 很多文章指出直接用px, 但是这样做无法达到适配的目的
  • 还有的说设置一个很大的值:border-radius:9999px,亲测不行(如:华为)
  • 使用svg, 既可以适配,即使再小的圆形也能在不同屏幕上完美展示,但又很麻烦

最终方案

  i{
       display: inline-block
       width: .16rem
       height: .16rem
       background-color: red
       border-radius: 50%
       transform: scale(.5)
   }

先把width,height的值放大一倍,然后用transform scale(.5)缩小一倍,接着用transform-origin调整下圆的位置就大功告成了!

116. 手机安装Charles的https证书

详情描述

一、iOS客户端安装证书

  1. 打开Charles,选择help→SSL Proxying→Install Charles Root Certificate on a Mobile Device or Remote Browser
  2. 手机连接电脑代理,打开safari,输入网址:chls.pro/ssl
  3. 手机弹出提示:此网站正尝试打开“设置”已向您显示一个配置描述文件。您要允许吗?忽略|允许,选择允许,安装描述文件,并信任
  4. iOS10.3以上的手机需要在:设置→ 通用 → 关于本机 → 证书信任设置→ 找到charles proxy CA证书,打开信任即可

二、android(安卓)客户端安装证书安卓手机类型众多,所以有些不太一样。

方法一:

  1. 打开Charles,选择help→SSL Proxying→Install Charles Root Certificate on a Mobile Device or Remote Browser
  2. 手机连接电脑代理,打开浏览器,输入网址:chls.pro/ssl
  3. 手机弹出提示:安装配置描述文件。您要允许吗?忽略|允许,选择允许,即可

方法二:

  1. 打开Charles,选择help→SSL Proxying→Save Charles Certificate,将证书导入到手机中
  2. 导入后直接点击安装证书即可

方法三:

  1. 打开Charles,选择help→SSL Proxying→Save Charles Certificate,将证书导入到手机中
  2. 导入后直接点击安装证书,提示无法打开
  3. 进入手机设置 → 更多设置 → 系统安全 → 从存储设备安装 → 选择charles.pem,点击高级,安装证书即可

115. mac webstorm 配置 dart 插件

详情描述

  1. 安装 dart ,移驾官网 dart 下载
  2. webstorm 中 在 plugins 中下载 Dart 插件,如下图: webstorm 下载 dart 插件
  3. 配置 sdk 路径:在设置中 => 语言&框架 => dart 配置 Dart SDK path:
    dart-sdk-path
    /usr/local/opt/dart/libexec 是我本地默认安装的 dart sdk 路径,查看自己本机的 dart 信息如下
$ brew info dart
dart-lang/dart/dart: stable 2.4.0, devel 2.5.0-dev.1.0
The Dart SDK
https://www.dartlang.org/
/usr/local/Cellar/dart/2.4.0 (387 files, 344.4MB) *
  Built from source on 2019-07-30 at 19:40:43
From: https://github.com/dart-lang/homebrew-dart/blob/master/dart.rb
==> Options
--devel
        Install development version 2.5.0-dev.1.0
==> Caveats
Please note the path to the Dart SDK:
  /usr/local/opt/dart/libexec

或者让 webstorm 自动配置:file => new => project... => dart; 这样,创建一个 dart 项目,然后创建的 dart 项目会自动配置 dart SDK path (前提是安装了 dart)

  1. 快速运行 dart 文件,查看输出信息(前提是配置了 dart sdk path): dart-run

114. vsCode 安装 dart 插件

详情描述

用 vsCode 开发 dart,安装两个插件会更方便,如下:

vsCode dart 插件

  • Dart 插件是用来语法提示!
  • Code Runner 是方便来运行 dart 文件(前提是必须安装 dart 环境,如何安装,请移驾官网),使用方法:在 vsCode 中右击文件,选择 Run code,输出里面就会显示文件输出信息

113. nginx 配置 http 强转 https

问题描述

如今 https 比 http 更加安全,可以用 nginx 配置一下 http 请求强转 https;

解决方案

方法一:采用nginx的497状态码
server {
	listen 8080 default_server;
	listen [::]:8080 default_server;

	# SSL configuration
	#
	listen 443 ssl default_server;
	listen [::]:443 ssl default_server;
	server_name yculcy.cn; #填写绑定证书的域名
	ssl on;
	ssl_certificate ./conf/1_yculcy.cn_bundle.crt;
	ssl_certificate_key ./conf/2_yculcy.cn.key;
	ssl_session_timeout 5m;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
	ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
	ssl_prefer_server_ciphers on;
	# 根据状态码 497 当网站只允许https访问时,当用http访问时nginx会报出497错误码
	error_page 497  https://$host$request_uri;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}
}
方法二:用 rewrite 重定向
server {
	listen 8080 default_server;
	listen [::]:8080 default_server;
	rewrite ^(.*)$  https://$host$1 permanent;        # 这是ngixn早前的写法,现在还可以使用。
}

112. 记录一些 nginx 常用的全局变量

详情描述

nginx 的全局变量容易忘记,以下记录一下备用:

$remote_addr		    // 获取客户端ip
$binary_remote_addr	    // 客户端ip(二进制)
$remote_port		    // 客户端port,如:50472
$remote_user		    // 已经经过Auth Basic Module验证的用户名
$host			        // 请求主机头字段,否则为服务器名称,如:blog.sakmon.com
$request		        // 用户请求信息,如:GET ?a=1&b=2 HTTP/1.1
$request_filename   	// 当前请求的文件的路径名,由root或alias和URI request组合而成,如:/2013/81.html
$status			        // 请求的响应状态码,如:200
$body_bytes_sent        // 响应时送出的body字节数数量。即使连接中断,这个数据也是精确的,如:40
$content_length	        // 等于请求行的“Content_Length”的值
$content_type	        // 等于请求行的“Content_Type”的值
$http_referer	        // 引用地址
$http_user_agent        // 客户端agent信息,如:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36
$args		            // 与$query_string相同 等于当中URL的参数(GET),如a=1&b=2
$document_uri	        // 与$uri相同  这个变量指当前的请求URI,不包括任何参数(见$args) 如:/2013/81.html
$document_root	        // 针对当前请求的根路径设置值
$hostname	            // 如:centos53.localdomain
$http_cookie	        // 客户端cookie信息
$cookie_COOKIE	        // cookie COOKIE变量的值
$is_args	            // 如果有$args参数,这个变量等于”?”,否则等于”",空值,如?
$limit_rate	            // 这个变量可以限制连接速率,0表示不限速
$query_string	        // 与$args相同 等于当中URL的参数(GET),如a=1&b=2
$request_body	        // 记录POST过来的数据信息
$request_body_file	    // 客户端请求主体信息的临时文件名
$request_method	        // 客户端请求的动作,通常为GET或POST,如:GET
$request_uri	        // 包含请求参数的原始URI,不包含主机名,如:/2013/81.html?a=1&b=2
$scheme		            // HTTP方法(如http,https),如:http
$uri			        // 这个变量指当前的请求URI,不包括任何参数(见$args) 如:/2013/81.html
$request_completion	    // 如果请求结束,设置为OK. 当请求未结束或如果该请求不是请求链串的最后一个时,为空(Empty),如:OK
$server_protocol	    // 请求使用的协议,通常是HTTP/1.0或HTTP/1.1,如:HTTP/1.1
$server_addr		    // 服务器IP地址,在完成一次系统调用后可以确定这个值
$server_name		    // 服务器名称,如:blog.sakmon.com
$server_port		    // 请求到达服务器的端口号,如:80

111. nginx 配置 https 报错问题

问题描述

用 nginx 配置 https 时,需要配置 443 端口、私钥路径、证书路径。会报错如下:

root@VM-173-231-ubuntu:~# nginx -t
nginx: [emerg] BIO_new_file("/usr/local/nginx/conf/1_yculcy.cn_bundle.crt") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/usr/local/nginx/conf/1_yculcy.cn_bundle.crt','r') error:2006D080:BIO routines:BIO_new_file:no such file)
nginx: configuration file /etc/nginx/nginx.conf test failed

如下图:
nginx 配置报错信息
报错提示配置文件有错误,找不多私钥和证书。

解决方案

最终发现,无论windows还是linux,只要写绝对路径,就会报错。

所以:
在 windows 下,将证书文件等放到 nginx/conf/ 目录下,配置文件中,不用加路径;
在 linux 下,可以将证书文件等放到 nginx.conf 同级目录下,不加路径即可,或者也可以放到 nginx/conf/ 目录下,可以加相对路径。

110. vsCode git 操作提示 Permission denied, please try again

问题描述

在 gitlab 仓库已经添加了 ssh key 之后,用 vsCode 或者 sourcetree 克隆或者操作仓库,还是会提示 Permission denied, please try again

解决方案

如果正确配置了 ssh key,则已经有了权限,但是每次提示 Permission denied, please try again 是因为需要 root 密码获取 ~/.ssh/id_rsa.pub 的 key;所以,在终端里执行以下命令:

ssh-add ~/.ssh/id_rsa

ssh-add 这个命令不是用来永久性的记住你所使用的私钥的。实际上,它的作用只是把你指定的私钥添加到 ssh-agent 所管理的一个 session 当中。而 ssh-agent 是一个用于存储私钥的临时性的 session 服务,所以每次重启都会失效,都需要再次执行命令。

以前有个方法 ssh-add -K privateKey 可以把私钥存到 keychain 中,重启后也不需要手动 ssh-add ,这个方法现在不行了,找了好久终于找到了解决方法

方法思路依然是利用上述原理,每次电脑开机自动执行 ssh-add 方法,参考文献如下:

mac下解决开机需要每次ssh-add的问题

注意:
上面链接方法中添加运行的命令 ssh-add ~/.ssh/id_rsa 依然会报没有权限,然后我修改为 ssh-add -A 则好了(具体原因不明)

109. 微信小程序设置超出行显示 ... 与展开更多按钮

问题描述

业务开发中会有一些场景,超出一行显示 ... 与展开更多按钮,展开更多按钮可以切换显示一行还是全部内容,少于一行正常显示;

解决方案

分析下问题: 一般这种需求不好实现的原因是,在移动端,每行显示的字数的有可能在不同机型会有差异,所以就使开发者无法知道这些内容是否超过一行,是否该显示展开更多按钮。

绕开上述原因,曲线救国,我们在每次页面渲染完成之后再去获取承载内容的元素宽度,和承载内容的元素的外层父级盒子的宽度相对比,如果宽度之差小于半个字体的大小(是为了防止一点误差),则显示 ... 的样式,显示展开更多按钮,相反,则隐藏更多按钮。

最终效果如下:

image

主要代码如下

<view class="coupon-remark-wrapper">
    <!--id = toggle-warpper 为包裹内容的父级元素-->
    <view class="coupon-remark-content" id="toggle-wrapper">
        <!--id = toggle-content 为内容的容器,控制显示全部内容还是显示超出一行... -->
        <view id="toggle-content" class="{{toggleParams.toggleFlag === 1?'ellipsis':''}}" hidden="{{toggleParams.toggleFlag === 0}}">
            {{couponData.limitRemark}}
        </view>
        <!--class = toggle-icon 为展开更多按钮-->
        <image class="toggle-icon {{toggleParams.toggleFlag === 1?'hide':'show'}}" wx:if="{{toggleParams.toggleShow}}" bindtap="toggleHandler" src="https://img.dmallcdn.com//dshop/201904/b1c5af14-f29a-494c-9e3b-899f1a2cf218"></image>
    </view>
</view>
.coupon-remark-wrapper {
  padding: 20rpx;
  padding-top: 33rpx;
  padding-right: 60rpx;
  margin-top: -20rpx;
  line-height: 1;
  box-sizing: border-box;
  color: #666666;
  background-color: #fff;
  position: relative;
  z-index: 1;
}
.coupon-remark-content {
  width: 100%;
  view {
    font-size: 22rpx;
    line-height: 1.5;
    word-break: break-all;
    display: inline-block;
    max-width: 100%;
  }
  .ellipsis{
    text-overflow:ellipsis;
    white-space: nowrap;
    overflow: hidden;
  }
  .toggle-icon {
    width: 30rpx;
    height: 30rpx;
    position: absolute;
    right: 20rpx;
    top: 35rpx;
    transition: all 0.2s linear;
    &.show {
      transform: rotate(180deg);
    }
  }
}
const couponItemBehavior = Behavior({
	data: {
		// 控制说明文案收起/展开
		toggleParams: {
			toggleFlag: 1, //0收起1展开
			toggleShow: false, //默认不显示toggleIcon
		},
	},
	ready() {
		this._checkRemarkToggle();
	},
	methods: {
		// 获取指定元素实际宽度
		_getElementWidth(id = "") {
			let _query = this.createSelectorQuery();
			return new Promise(resolve => {
				_query.select(id).fields({
					size: true,
				}, (res) => {
					resolve(res.width)
					_query = null;
				}).exec();
			});
		},

		// 说明文字收起/隐藏事件
		toggleHandler() {
			const {toggleFlag} = this.data.toggleParams;

			this.setData({
				toggleParams: {
					toggleFlag: toggleFlag === 0 ? 1 : 0,
					toggleShow: true
				}
			})
		},
		/*
		* 检测说明文字是否需要隐藏/收起操作
		* 对比文字外层固定宽度容器元素宽度wrapperWidth与当前文字元素宽度contentWidth
		* 若相差小于10则说明超出一行
		* */
		_checkRemarkToggle() {
			Promise.all([
				this._getElementWidth('#toggle-wrapper'),
				this._getElementWidth('#toggle-content')]
			).then(res => {
				const wrapperWidth = res[0];
				const contentWidth = res[1];

				const {limitRemark, startDate, endDate, statusCode} = this.properties.couponData;

				if (wrapperWidth - contentWidth < 10) {
					this.setData({
						toggleParams: {
							toggleFlag: 1,
							toggleShow: true
						},
						timeArea: `${startDate}-${endDate}`,
						unableImageSrc: UNABLE_IMAGE[statusCode]
					})
				}
			})
		}
	}
});

总结:
在这里只是个抛砖引玉提供一个思路,小程序中可以这样实现,在 H5 中也可以这样实现,如果有更好的方案,欢迎讨论提供!

108. 微信小程序设置超出隐藏,点击加载更多实现动画效果

问题描述

业务开发中经常会有一些场景,以商品订单场景为例,少于两个商品,不显示更多按钮,超过两个显示更多,点击展开,商品全部展示,并且有渐变动画效果

解决方案

Tips:先说下自己当时的误区的纠正:
动画的发生需要满足以下条件:

  1. 实现动画的元素 css 属性写上了 transition 属性,并且值设置正确(具体值代表什么,自行百度)
  2. 元素需要实现动画的属性需要有具体的值的变化,如果不是具体的值则,不会实现动画(比如:max-height 的值由 100px => 200px 会有动画,但是由 100px => none/inherit 则不会有动画)

实现效果如下图:

image

根据 Tips 的两点条件,遇到的瓶颈如下:

  1. 产生动画的元素必须要有 css 属性值的具体变化;
  2. 商品的数量是不一定的,难以设置属性值的具体变化

解决上述两点,其实就是实现的思路:

  1. css 属性值得具体变化,可以使用 max-height 属性来控制;
  2. 动态获取商品列表容器的高度,然后设置给 max-height 属性,这样,max-height 属性会由两个商品的高度和多个商品的高度来切换;

主要代码如下:

<!--视图层:
    ware-list 为最外层,由 max-height 控制动画,并且设置 overflow:hidden;
    list-box 为包裹商品的盒子,max-height 的最大值为此盒子的高度,
    list 为每一商品项
    此处 278rpx 是商品为两个时的商品列表盒子的大概高度
-->
<view class="wares-lists" style="max-height:{{showAllWares?listBoxHeight:'278rpx'}};">
    <view id="list-box">
        <view class="list" wx:for="{{moduleData.wares}}" wx:key="index">
            
        </view>
    </view>
</view>
<!-- 设置需要动画元素的样式 -->
.wares-lists {
	overflow: hidden;
	transition: all 0.2s linear;
}

部分 js 代码如下:

const app = getApp();
Component({
	/**
	 * 组件的属性列表
	 */
	properties: {
		moduleData: {
			type: Object
		},
	},

	/**
	 * 组件的初始数据
	 */
	data: {
		showAllWares: false,
		listBoxHeight: '278rpx',
	},
	ready: function () {
		this.setListHeight();
	},
	/**
	 * 组件的方法列表
	 */
	methods: {
		toggleShow: function (e) {
			this.setData({
				showAllWares: !this.data.showAllWares
			});
		},

		// 设置商品列表高度
		setListHeight () {
			this._getElementHeight('#list-box').then( height => {
				this.setData({
					listBoxHeight:`${height}px`,
				});
			});
		},

		// 获取指定元素实际宽度
		_getElementHeight(id = "") {
			const _query = this.createSelectorQuery();
			return new Promise(resolve => {
				_query.select(id).fields({
					size: true,
				}, (res) => {
					resolve(res.height);
				}).exec();
			});
		},
	}
});

总结:
在这里只是个抛砖引玉提供一个思路,小程序中可以这样实现,在 H5 中也可以这样实现。

107. vsCode 配置 easy sass 插件转换 css、wxss、acss

问题描述

小程序开发有时会使用 easy sass 插件,在 vsCode 中配置自动转换,以下为配置方式:

解决方案

先附上下图,再来一步步配置;

image

  1. vsCode 中安装 easy sass 插件;
  2. 建一个文件夹.vscode .vscode 文件夹下建一个叫 settings.json 的文件(针对于当前项目的配置,全局的配置在全局的 settings.json 里添加) settings.json 中配置内容如下:
"easysass.formats": [
    {
        "format": "expanded",  // 没有缩进的、扩展的css代码
        "extension": ".wxss"  //转化的后缀名
    },
]
  1. easysass.formats 是设置编译输出的 css 风格的,可以同时编译输出多个不同风格的 CSS 文件;

easysass.formats.format 支持四个选项用以编译生成对应风格的 CSS:

  • nested:嵌套缩进的 css 代码。
  • expanded:没有缩进的、扩展的css代码。
  • compact:简洁格式的 css 代码。
  • compressed:压缩后的 css 代码。

easysass.formats.extension 顾名思义就是设置编译输出的文件名了

106. vsCode 配置 easy less插件转换 css、wxss、acss

问题描述

小程序开发有时会使用 easy less 插件,在 vsCode 中配置自动转换,以下为配置方式:

解决方案

先附上下图,再来一步步配置;

image

  1. vsCode 中安装 easy less 插件;
  2. 建一个文件夹.vscode .vscode 文件夹下建一个叫 settings.json 的文件 settings.json 中配置内容如下:
"less.compile": {
  "outExt": ".wxss"
}
  1. outExt 参数为导出文件名,默认为 .css,可以配置 .wxss、.acss 等,其他配置项请查询官方;

105. 微信小程序中 input 的自定义删除按钮点不了

问题描述

业务场景:手机号输入框有个删除按钮可以删除输入的手机号。但是真机上经常输入框聚焦之后删除按钮点击不了。

问题原因

在开发者工具上调试发现:input 框在安卓和ios上都有默认不同的宽度,并且 微信小程序 input 是原生的组件,当聚焦之后,层级最高,会覆盖掉删除按钮,失焦之后就可以点击。

比较直观的图如下:

原因图

解决方案

因为 input 层级最高,并且宽度不固定。层级最高肯定控制不了,可以设置固定的宽度,让其和删除按钮分开,就可以点击到删除按钮了;

104. 微信公众号通知和服务通知

详细描述

以下简单对公众号通知和服务做一些总结:

公众号通知:
微信在公众号推送的通知,比较有针对性,无法禁止推送,出发取消关注;
==推送权限:== 用户必须有交互,包括并不仅限于:扫码、关注、点击菜单,发送消息(大概会获取推送二十条的权限)等,权限会是三天有效期

服务通知:
微信小程序通知的集合内容,所有小程序的服务通知会在一起推送;
==推送权限:== 必须有formId,一个formId对应一个推送权限,支付会两个,一个表单提交会攒一个,有效期七天!

103. 微信小程序 1rpx border ios 真机显示不全

问题描述

在微信小程序的原生页面,ios 真机上 1rpx border 会出现个别边显示不全的情况;

解决方案

这里先放上问题直通车:微信小程序1rpx border ios真机显示不全问题分析及解决方案

经过分析:当标签的父容器宽度(单位rpx)÷2的值为偶数或偶数.5的时候会出现该bug,那么我们可以推到出用200.5*2=401,302*2=604等等都会重现这个bug;

所以解决方案为: 那么解决方案就来了:

1)第一种方式是设置标签父容器的宽度到无bug值,即(奇数或奇.5)*2,例如281*2rpx,281.5*2rpx可以解决;

2)第二种方式是补充像素单位:

步骤1中wxml增加space的view后如下:

<view class='label-con'>
    <view class='space'></view>
    <view class='label'>中国移动</view>
    <view class='label'>苏宁</view>
    <view class='label'>阿里巴巴</view>
    <view class='label'>华为</view>
</view>

步骤1中wxss中增加space类为:

.space{
    width: 1rpx;
    height: 100%;
    float: left;
}

以上两种方式即可解决该问题。 具体原因和解决方案请点击上面直通车

102. 微信小程序 webview 页面刷新

问题描述

在微信小程序原生页面做了操作,数据发生改变,回到 webview 页面时需要更新 webview 里面的数据。由于小程序没有提供与 webview 的实时通信能力,因此刷新页面是个可考虑的做法。

解决方案

首先,解决回到 webview 刷新的问题,webview 自带缓存,直接物理键返回,或者 back api 返回,都不会更新实时数据,这个问题可以利用 onShow 生命周期,在 onShow 生命周期中改变 webview 的 src 属性;

注意:
在 onShow 中改变 src 链接时,需要改变 src 的原链接,如果直接赋值原链接,不会起作用,所以需要在 query 参数再加上时间戳,才能让当前 webview 刷新页面;

引发的问题:
这种处理方式页面是会更新了。但是会增加webview的浏览history,导致用户在后退的时候,会在webview内退到前一个页面,而不是退到小程序的前一个页面。

处理方式:
首先,让webview做条件渲染;需要刷新时,先把webviewUrl设为空,销毁当前webview。然后再把webviewUrl设为当前值。最终综合解决方式如下:

<template>
  <div>
    <!--此处是重点-->
    <web-view v-if="webViewUrl.length" :src="webViewUrl"></web-view>
  </div>
</template>

<script>
  import api from "common/js/util/util";

  export default {
    data() {
      return {
        webViewUrl:''
      }
    },
    onShow(){
      //此处是重点
      if(wx.getStorageSync('isJournalBack')){
        let urlTemp = this.webViewUrl;
        this.webViewUrl = '';
        wx.removeStorageSync('isJournalBack');
        setTimeout( () => {
          this.webViewUrl=urlTemp.split('?')[0]+'?flag='+Date.parse(new Date())+'&' + urlTemp.split('?')[1];
        }, 100)
      }
    },
    onLoad(option) {
      if(wx.getStorageSync('isJournalBack')){
        wx.removeStorageSync('isJournalBack');
      }
      let str='/dist/journalList.html';
      if(JSON.stringify(option) !== '{}'){
        str+='?';
        for (var i in option){
          str+=i+'='+option[i]+'&'
        }
        str=str.slice(0,str.length-1);
      }
      this.webViewUrl = `${api.httpEnv()}${decodeURIComponent(str)}`
      console.log(this.webViewUrl)
    },
  }
</script>

这样便可以在不影响导航栏历史的情况下刷新页面,也可以是跳转url。 这里重新赋值 url 之后,页面内容的更新应该是异步执行的,因此我们后一次修改 url 需要延时一小段时间,否则会出现 error 。 猜测重新赋值 url 后页面实际更新应该是在下一次的 requestAnimationFrame ,因此如果页面完全不卡顿可能16ms就可以了,保险起见,我设了100ms。

101. mac nginx 初次配置的默认路径

问题描述

mac 上初次配置 nginx,会出现找不见默认路径的情况,以下是总结的默认路径

解决方案

nginx 默认安装的地方(默认的配置文件路径)

/usr/local/etc/nginx

nginx 默认配置文件配置的是 8080 端口,会返回一个默认的 index.html 页面,这个 index.html 页面路径为下

// [version] 为 nginx 的版本

/usr/local/Cellar/nginx/[version]/html

如果是用 brew 安装,则: brew info nginx,则可以得到所有信息

brew info nginx
nginx: stable 1.15.8 (bottled), HEAD
HTTP(S) server and reverse proxy, and IMAP/POP3 proxy server
https://nginx.org/
/usr/local/Cellar/nginx/1.15.8 (23 files, 1.4MB) *
  Poured from bottle on 2019-01-05 at 20:05:47
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/nginx.rb
==> Dependencies
Required: openssl ✔, pcre ✔
Optional: passenger ✘
==> Options
--with-passenger
	Compile with support for Phusion Passenger module
--HEAD
	Install HEAD version
==> Caveats
Docroot is: /usr/local/var/www

The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.

nginx will load all files in /usr/local/etc/nginx/servers/.

或者是用命令 nginx -V 查看,如下:

nginx -V
nginx version: nginx/1.15.8
built by clang 10.0.0 (clang-1000.11.45.5)
built with OpenSSL 1.0.2q  20 Nov 2018
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/nginx/1.15.8
--sbin-path=/usr/local/Cellar/nginx/1.15.8/bin/nginx
--with-cc-opt='-I/usr/local/opt/pcre/include -I/usr/local/opt/openssl/include'
--with-ld-opt='-L/usr/local/opt/pcre/lib -L/usr/local/opt/openssl/lib'
--conf-path=/usr/local/etc/nginx/nginx.conf
--pid-path=/usr/local/var/run/nginx.pid
--lock-path=/usr/local/var/run/nginx.lock
--http-client-body-temp-path=/usr/local/var/run/nginx/client_body_temp
--http-proxy-temp-path=/usr/local/var/run/nginx/proxy_temp
--http-fastcgi-temp-path=/usr/local/var/run/nginx/fastcgi_temp
--http-uwsgi-temp-path=/usr/local/var/run/nginx/uwsgi_temp
--http-scgi-temp-path=/usr/local/var/run/nginx/scgi_temp
--http-log-path=/usr/local/var/log/nginx/access.log
--error-log-path=/usr/local/var/log/nginx/error.log
--with-debug --with-http_addition_module
--with-http_auth_request_module --with-http_dav_module
--with-http_degradation_module --with-http_flv_module
--with-http_gunzip_module --with-http_gzip_static_module
--with-http_mp4_module --with-http_random_index_module
--with-http_realip_module --with-http_secure_link_module
--with-http_slice_module --with-http_ssl_module
--with-http_stub_status_module --with-http_sub_module
--with-http_v2_module --with-ipv6 --with-mail
--with-mail_ssl_module --with-pcre --with-pcre-jit
--with-stream --with-stream_realip_module
--with-stream_ssl_module --with-stream_ssl_preread_module

100.position 设置属性 absolute 之后,width 的值出现不固定

问题描述

页面布局中有一些场景需要设置盒子的 css 样式 position:absolute, 但是之后不设置 width 的具体值,会出现意想不到的宽度,出现折行啊等样式错乱

解决方案

原因是当设置了 position:absolute 之后,该元素的witdh、height会根据父元素(需设置position:relative,没有则按浏览器作为父元素)的width、height和该元素left、bottom、top、right而改变。
计算公式为:
该元素的witdh = 父元素的width-top-bottom;
该元素的height= 父元素的height-left-right; 所以根据具体的页面布局,设置宽高,防止出现意想不到的样式错乱

99.ios微信小程序中 input 输入框问题,输入的光标中的内容自动清空

问题描述

1.我在页面上有个倒计时的功能,每一秒都在更新时间,更新时间显示的值(view一直变)
2.我调用input输入框,准备输入内容,每次倒计时秒数变得时候,光标的内容自动全部清空

具体场景描述请见下图:

image

解决方案

这个问题是 mpvue 处理定时器和 input 输入框在ios上的兼容问题;问题连接附上:

github issuse 直达车

github 上有道友出了几个方案,但是都没有解决我的项目场景;最后捋了捋思路:既然 input 绑定数据会和定时器冲突,那就可以不绑定;代码如下(简写思路):

<template>
    <figure class="main-input-box-textarea-inner" v-if="textareaShow">
        <section class="area-content">
              <input class="main-input-box-textarea"
                     v-if="textareaShow"
                     type="text"
                     @input="inputFunc"
                     maxlength="500"
                     @focus="scrollToBottom()" cursor-spacing="5"/>
              <div class="main-input-box-textarea" v-if="!textareaShow"></div>
        </section>
        <button class="main-input-box-send" :class="{'on':sendTextContent.length}" @click="sendMessage"
                type="submit" formType="submit">发送
        </button>
    </figure>
</template>
<script type="text/ecmascript-6">
export default {
    methods: {
        inputFunc (e) {
            console.log(e.target.value)
            this.sendTextContent = e.target.value
        },
        sendMessage() {
            if (this.sendTextContent.trim().length === 0) {
              return false;
            } else {
              this.textareaShow = false;//这里是重点
              if (!this.clickFlag) return false;
              this.clickFlag = false;
              console.log(this.sendTextContent.trim().substring(0,20));
              dataLog.createTrack({
                actionId: 14202,
                keyword: this.sendTextContent.trim()
              });
              imBaseMethods.sendMessage({
                target: this.targetData.account,
                sendContent: this.sendTextContent.trim(),
                custom: JSON.stringify({
                  cType: "1",
                  cId: this.doctorCustomerId,
                  mType: "0",
                  conId: this.orderSourceId
                }),
                needPushNick: false,
                pushContent: `患者${this.patientName ? this.patientName : ""}:${this.sendTextContent.trim().substring(0,20)}`,
                pushPayload: JSON.stringify({
                  account: "0_" + this.caseId,
                  type: "1"
                }),
              }).then(obj => {
                this.textareaShow = true; //这里是重点
                this.setFocus = true;
                this.sendMessageSuccess(obj);
              }).catch((err, obj) => {
                this.sendFail(err, obj)
              });
            }
          },
    }
}
</script>

98. window.__wxjs_environment 为 Undefined

问题描述

微信小程序的 webview 中在网页内可通过window.__wxjs_environment变量判断是否在小程序环境,但是在真实项目中发现有时 window.__wxjs_environment 为 undefined;

解决方案

这个全局变量建议在WeixinJSBridgeReady回调中使用,也可以使用JSSDK 1.3.2提供的getEnv接口,代码如下:

// web-view下的页面内
function ready() {
  console.log(window.__wxjs_environment === 'miniprogram') // true
}
if (!window.WeixinJSBridge || !WeixinJSBridge.invoke) {
  document.addEventListener('WeixinJSBridgeReady', ready, false)
} else {
  ready()
}

// 或者
wx.miniProgram.getEnv(function (res) {
  console.log(res.miniprogram) // true
})

97. audio 标签自动播放不起作用或者 play() 报错

问题描述

页面的 audio 标签设置了自动播放属性,进入页面自动播放不起作用,或者用 js 控制 play(),方法无效,报错!

解决方案

经过各种百度,谷歌,追踪到原因如下: 页面必须进行交互才能进行对 audio 播放;

声音无法自动播放这个在IOS/Android上面一直是个惯例,桌面版的Safari在2017年的11版本也宣布禁掉带有声音的多媒体自动播放功能,紧接着在2018年4月份发布的Chrome 66也正式关掉了声音自动播放,也就是说自动播放在在桌面版浏览器也将失效;

如Android Chrome文档提到。因此浏览器厂商放开了对多媒体自动播放的限制,只要具备以下条件就能自动播放:

(1)没音频轨道,或者设置了muted属性

(2)在视图里面是可见的,要插入到DOM里面并且不是display: none或者visibility: hidden的,没有滑出可视区域。

换句话说,只要你不开声音扰民,且对用户可见,就让你自动播放,不需要你去使用GIF的方法进行hack.桌面版的浏览器在近期也使用了这个策略;

所以上面提到很多人是监听整个页面的点击事件进行播放,不管点的哪里,只要点了就行,包括触摸下滑。这种方法只适用于一个声音资源,

96. a 标签 download 属性不起作用,或者下载的图片无法查看

问题描述

download 是 a 标签 html5 的新属性,可以点击下载文件,初次使用,经常会出现无法点击的情况,可能有以下原因,排除下:

解决方案

  1. 必须设置 href 属性,download 才起作用;
  2. download 属性是文件名,href 属性,指向的是要下载的文件;
  3. href 的指向需要同源,跨域下载不下来,当然可以通过其他方案,比如把图片传到自己后台,再返回同源的路径;

95.富文本解析 wxParse 解析数据造成页面假死

问题描述

小程序中总有富文本解析的场景,比如:头条的终端页。我们的终端页使用了 wxParse, 但是由于 wxParse有些小问题,并且项目使用 mpvue,所以把 wxParse 拉到本地做了一些魔改,但是依然遇到性能瓶颈,数据过多造成页面假死,相对于小程序原生的 rich-text 富文本解析组件;wxparse 的功能性更丰富,支持 video;

解决方案

由于数据过多而造成页面假死,那就从数据层的角度考虑,把数据分段加载,关键部分代码如下:

<template>
  <!--基础元素-->
  <div class="wxParse" :class="className" v-if="!loading">
    <block v-for="(node,index) of nodes" :key="index">
      <wxParseTemplate :node="node"/>
    </block>
  </div>
</template>

<script>
let query = null;
let scrollTime = null;
let nodesData = [];
export default {
    data() {
      return {
        nodes:[], // 计算属性中的 nodes 放到 data 里
      };
    },
    onPageScroll(e){
      if (!nodesData.length) return;
      if (scrollTime) clearTimeout(scrollTime);
      scrollTime = setTimeout( ()=> {
        query.exec((res) => {
          clearTimeout(scrollTime);
          console.log('res');
          console.log(res);
          console.log(e);
          if (e.scrollTop > (res[0].height/2)) {
            console.log('我要加载');
            this.nodes.push(...nodesData.splice(0,15));
          }
        })
      },100);
    },
    onLoad() {
      nodesData = [];
      console.log('wxParse start');
      query = wx.createSelectorQuery();
      query.select('.wxParse').boundingClientRect();
      nodesData = this.getNodes();
      this.nodes.push(...nodesData.splice(0,25));
    },
    onUnload () {
      nodesData = [];
      if (scrollTime) clearTimeout(scrollTime);
    },
    methods: {
      getNodes () {
        const {
          content,
          noData,
          imageProp,
          startHandler,
          endHandler,
          charsHandler,
        } = this;
        const parseData = content || noData;
        const customHandler = {
          start: startHandler,
          end: endHandler,
          chars: charsHandler,
        };
        const results = HtmlToJson(parseData, customHandler, imageProp, this);
        this.imageUrls = results.imageUrls;
        return results.nodes;
      },
    },
}
</script>

上面方法的思路是在页面滑动的时候对数据进行分段加载,但是通过实践,发现如果终端页要跳转其他页面,返回之后还是会把剩余数据加载完,依旧造成页面卡死,还有问题就是刚进入页面解析数据,比如有贴底按钮无法点击(此时在解析数据)。最终还是重新自写了个 parse,如果对于需求比较简单的,推荐小程序原生的 rich-text,如果数据较少, wxParse 还行,如果数据量过大,慎用!!!

94. 微信小程序页面按钮分享好友缩略图截取顶部

问题描述

微信小程序转发会默认截取当前页面的当前作为转发好友的缩略图,但是 PM 想实现转发的时候用当前页面的顶部UI作为转发缩略图。

解决方案

其实方案就是将页面滑动到顶部,但是注意一定要加延时才起效果,以下是代码

wx.pageScrollTo({
  scrollTop:  0,
  duration: 100
});

93. git dist 目录排除不了

问题描述

在有的项目中,需要排除 dist 目录不被 git 管理,一般都是在 .gitignore 文件 添加 'dist/';但是有的时候发现没用。

解决方案

原因是首次提交可能就将 dist 增加到了 git 仓库,所以检查下 git 仓库如果有 dist 目录,然后将 git仓库的 dist 目录删除,再 pull 本地合并,最后 dist 目录就排除了管理

92. 微信小程序 canvas 问题

问题描述

场景:当前页面用 canvas 画了个图片,获取到临时路径;之后再用这个临时路径去画图,手机上会出现画不出来或者画不全的情况;开发者工具没问题。

解决方案

原因不明,小程序的问题,尽量避免这种场景,没有找到解决方案。实际开发中,当时第一次处理了用户微信头像,然后再用临时路径画,ios 和安卓都没出来;阿里返回坐标点的图片,ios没问题,安卓只出来一半多图。

91. 微信小程序 wx.reLaunch 执行前几个页面的 onUnload 钩子

解决方案

有种场景:页面 A => B => C => D, 当在 C 页面调用 wx.reLaunch({url:'/pages/D'}) 时,页面 A 、B、C 的 onUnload 事件都会执行,这是小程序的触发规律,根据自己业务场景看需要怎么处理一些事情。

90. 微信小程序输入框属性 cursor-spacing 问题

问题描述

微信小程序给输入框提供了属性 cursor-spacing,用处是聚焦时光标离软键盘的距离,但是在安卓机子上会出现不太好使,比如,没有达到预期的设置值,还有滑动到底部,设置的值不起作用。

解决方案

因为 cursor-spacing 属性是微信小程序提供的,经过对比、测试发现,当出现这种情况的时候,是因为微信版本过低导致的,在微信版本6.6.7会出现上述问题,微信更新为 6.7.2 ,则修复了上述问题,所以这种问题没必须和测试人员耗时间,就是微信版本的兼容性问题。

89. 微信小程序输入框会字体显示不全或者换行

问题描述

有的时候不同的设备上会出现微信小程序输入框表现不一致,比如:换行,字体显示不全

解决方案

用开发者工具调试发现,input,textarea 有默认的 weight or height,并且是 rem 为单位,所以会在不同设备出现不同的表现的形式。 原因找到了,解决方法就是覆盖掉默认样式就ok;

88. 微信小程序同一个页面压入历史栈两次,返回第二次页面没数据

问题描述

最近项目中遇到一个场景,页面A(A1) => B => A(A2), 然后返回时,先从页面返回时,从A2 => B => A1, A2 回退时,会触发 A2 的 onUnload(onUnload 事件中执行了一些数据重置为空的函数)事件,然后回退到 A1时,发现 A 页面的数据为空,A1 此时不会触发 onLoad(我们的页面数据赋值在 onLoad) 事件,会触发 onShow 事件。此时,会出现 A1 页面空白,数据为空。

解决方案

通过问题描述的分析,得到这种情况的原因是:
当历史栈里有两个 A(A1,A2)时,先从 A2 返回,会清空 A 页面的数据,而返回到 A1 时,没有触发 onLoad 事件重新赋值,所以造成 A1 页面数据空白。
以下是我们的解决方案: 我们的项目使用的是 mpvue,用 vuex 管理,在第一次进入 A1 时,onLoad 钩子里把值存到 vuex 中,这样即使再次进入会重新赋值,然后返回也不会影响数据为空。

87. padStart is not a function

问题描述

微信小程序开发时,控制台padStart is not a function;

解决方案

不用这个方法了呗,或者自己重新在 String.prototype.padStart 中自己实现,毕竟是 es6 之后的方法,经测试,微信6.6.6版本不支持,6.6.10 版本支持,和版本也有一定的关系,期望以后的支持性越来越好了;

86. 微信小程序Push场景本地调试方法

问题描述

开发微信小程序时,会出现正常进入没问题,但是通过 push 进入出现 bug 的场景,这时就尴尬,总不能每次为了测试 push 场景而去审核通过,以下是在本地调试 push 场景的方法;

解决方案

开发者工具添加编译模式,入口页面为需要调试的页面,启动参数都带上 扫码进入,然后关闭,第二次进入即为Push入口的场景。
从公众号 Push 进入时生命周期和切后台会有所不同,这种场景下会执行 Unload 和 Hide,切后台只会执行 Hide ,即是说该页面会全部重新装载

85. webpack vue 打包优化

问题描述

在项目优化中,有一种方案,不经常更新的第三方包可以不打在 vendor.js 中,可以在 .html 模板中引入,然后在 webpack 中配置排除这些包,但是会遇到一个问题,就是开发环境中,如果排除掉 vue.js 不打入 vendor.js 中,则无法使用 vue devtools 进行调试,如果不排除 vue.js ,则又会和模板中引入的 vue.js 冲突报错,以下是我的解决方案;

解决方案

思路:

  1. 在 webpack 配置中,根据环境变量来判断是否排除 vue;
  2. 在 HtmlWebpackPlugin 插件中传参需要插入的 vue.js 的 script 引入的字符串;
  3. 在 html 模板中写入模板语法,动态注入 vue.js;
  4. 通过 ejs-loader 编译 html 中的模板语法;

关键代码如下

webpack.base.conf.js

// webpack.base.conf.js

let externals = {
  'vuex': 'Vuex',
  'vue-router': 'VueRouter',
  'jquery': 'jQuery',
  'mint-ui': 'mintUi',
  'vueg': 'vueg',
}

if (process.env.NODE_ENV === 'production') {
  Object.assign(externals, {
    'vue': 'Vue',
  })
}

module.exports = {
  externals,
  module: {
    rules: [
      {
        test:/\.html$/,
        loader:'ejs-loader',
      },
    ]
  }      
}  

webpack.prod.conf.js

// webpack.prod.conf.js

webpackConfig.plugins.push(new HtmlWebpackPlugin({
  script:'<script src="https://cdn.bootcss.com/vue/2.5.15/vue.min.js"></script>',
}));

.html 模板中

// .html

<%=htmlWebpackPlugin.options.script%>

84. 荣耀 10 字体显示错误,顶部部分遮掩

问题描述

华为荣耀 10 机型上出现字体被显示不全,顶部被遮掩,其他大部分手机正常。

解决方案

给相关字体的容器设置了 padding-top:1px(1px只是意思一下);然后就恢复正常,原因不明。

83. mpvue 中插槽 slot 没有渲染出来

问题描述

组件开发中,经常会使用到插槽 slot, 小程序原生是支持插槽的,mpvue 也支持了插槽,但是发现插槽并没有被渲染出来,原因如下:

解决方案

mpvue 虽然公布支持了插槽,但是有版本限制的,开发者注意看看版本,slot 没出来总结为以下几点(截止为1.0.15版本):

  1. mpvue 的版本问题,1.0.13 之后才支持具名 slot;
  2. slot 里面不能有变量,有变量渲染不出来,官方推荐 用 props 传值;
  3. 不支持一个组件多个插槽;

82. 微信小程序同声传译 Face2FaceTranslator 开发

详情描述

移驾我的博客查看

81. ios 手机端 input 框上方有内阴影

解决方案

  1. 方法一:
<!--如果 ui 样式里有边框,可以用外层盒子设置边框-->
input{
    border:none;
}
  1. 方法二:
//在IOS下,input 和textarea表单默认会有个内阴影,一定程度上影响视觉一致,可通过设置下面代码去掉:

input{
    -webkit-appearance: none;
}

80. wx.showToast() 在真机中闪烁一下消失

问题描述

在真实的业务场景下,请求接口需要调用 wx.showLoading(),接口请求结束调用 wx.hideLoading()。如果需要给用户提示错误信息,调用 wx.showToast(),在模拟器上没事,但是在真机上会出现提示信息闪烁一下,然后消失。

解决方案

这个问题出现的原因就是因为小程序的内部处理 wx.showLoading() 和 wx.showToast() 调用的是同一个框,都受 wx.hideToast() 或者 wx.hideLoading() 的影响。
比如在真机上你的代码顺序为 wx.showLoading() =>wx.hideLoading() => wx.showToast() ;但是实际你看到的现象是 wx.showLoading() => wx.showToast() =>wx.hideLoading(),受到最后的 wx.hideLoading() 影响,toast 框闪烁一下就消失;
解决方法如下:

wx.showLoading();
wx.hideLoading();
setTimeout( () => {
  wx.showToast({
    title: '提示的错误术语',
    icon: "none",
  });
  setTimeout( () =>{
    wx.hideToast();  
  },2000)
},0);

// 看到代码就明白了,其实就是把 wx.showToast() 放到事件队列的队尾去执行。

79. webpack 热更新优化

问题描述

在多页面项目开发中,开发环境的热更新下,会发现随着页面的增多,热更新的编译时间会越来越长,本人项目在十几页的情况下,编译达到30s,这无疑浪费了时间。以下是一种解决方案;

解决方案

这种方案的思路为,开发环境中,每人负责的都是一部分模块或者组件,所以热更新可以只编译自己当前需要的页面,而没必要把所有的页面全部编译。创建一个 selfConfig.js 设置需要保存的页面,然后在 webpack 配置中,配置,只属于需要的页面去编译热更新。加快开发环境中的编译速度。

// selfConfig.js
module.exports = [
    'imScence',
    'mLogin'
];
// webpack.base.conf.js  
// 部分关键代码
const selfConfig = require("./selfConfig");

for (let moduleName of modules) {
  if (selfConfig.length === 0) {
    devEntries[moduleName] = path.join(resolve('src'), 'modules', moduleName, 'main.js');
  } else {
    if (selfConfig.includes(moduleName)) {
      devEntries[moduleName] = path.join(resolve('src'), 'modules', moduleName, 'main.js');
    }
  }
  buildEntries[moduleName] = path.join(resolve('src'), 'modules', moduleName, 'main.js');
}

以上事例设置完成后,只会热更新两个页面,但是这种方案的弊端是,其他页面本地环境将是白屏打不开(因为压根没编译),所以这种方案还是根据适合自己的场景使用。

注意: 每次修改 selfConfig.js 需要重起 webpack 服务。

78. 华为 mate8 拍照上传图片失败

问题描述

在上传图片时,华为 mate8 掉起相册可以正常上传,但是掉起相机拍照片时,上传失败(仅限于原生浏览器)。场景:咨询流程上传图片,上传检查检验

解决方案

通过 debugger ,发现,mate8 在原生浏览器拍照上传时,有一个小坑,拍完照获取的照片名字有两个 '.' ,所以截取到的名字后台识别不了,错误名字实例为:xxxxx.xxxxx.jpg;前端解决方案如下:

// file 为文件对象
let _fileName = "",
  _rex = /\./g,
  _rex2 = /\&/g;
let _fileLocalName = "";
if (files.name.match(_rex).length == 1) {
_fileName = files.name.split(".")[1];
_fileLocalName = files.name;
} else {
_fileName = files.name.split(".")[2];
_fileLocalName =
  files.name.split(".")[0] +
  files.name.split(".")[1] +
  "." +
  files.name.split(".")[2];
}
if (_fileLocalName.indexOf("&") > 0) {
_fileLocalName = _fileLocalName.replace(_rex2, "");
}
//上传请求
api.ajax({
url: XHRList.imgCreate,
method: "POST",
data: {
  fileContent: base64
    .split(",")[1]
    .replace(/\+/g, "%2B")
    .replace(/\n/g, ""),
  fileName: _fileLocalName,
  extName: _fileName,
},
timeout: 300000,
done(res) {
 
},
fail(res) {
  
}
});

77. vue 在 model 修改的数据没有响应式

问题描述

在 vue 的实际项目开发时,有时会遇到在 model 中修改的数据没有同步改变到 view 层,而慢一步,找了找原因,如下:

解决方案

Vue 不允许在已经创建的实例上动态添加新的根基响应式属性(root-level reactive proiperty)。然后它可以使用 Vue.set(object,key, value)方法将响应属性添加到嵌套的对象上:

Vue.set(vm.someObject,'b',2);

您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

this.$set(this.someObject,'b',2);
// 上面情况实践中出错的地方:im 聊天中上传图片给其设置 loading 的时候。

有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让他包含原对象的属性和新的属性;

// 代替 `Object.assign(this.someObject,{a:1,b:2})`
this.someObject = Object.assign({},this.someObject,{a:1,b:2})
// 出错的地方;im中用 vuex 管理医生数据,使用了注销的那种方案没有得到同步更新;

76. node 获取本机 ip 地址

问题描述

开发 H5 时,经常会使用真机进行调试本地环境、webpack 配置服务器好多脚手架写的都是固定的,而在团队开发中需要每人配置自己的本机 ip 进行开发,每次开启开发环境的都需要修改,并且还不能提到 git ,麻烦,所以找了方法,动态获取本机 ip 进行,本地环境真机调试;

解决方案

const interfaces = require('os').networkInterfaces(); // 在开发环境中获取局域网中的本机iP地址
let IPAdress = '';
for(var devName in interfaces){  
  var iface = interfaces[devName];  
  for(var i=0;i<iface.length;i++){  
        var alias = iface[i];  
        if(alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal){  
              IPAdress = alias.address;  
        }  
  }  
} 
console.log(IPAddress);

75. wepy mpvue 和原生开发小程序对比

详情描述

移驾我的博客查看

74. mpvue 配置 tabBar 图片路径出错

问题描述

使用 mpvue 开发小程序,配置 tabBar 时,提示配置的路径找不到,但是已经把image 文件夹放到了src 目录下;

解决方案

1.方法一:
如果把 image 文件夹手动放到dist 目录下,是正常可以找到的。 是不是 mpvue 没有把需要的图片打到 dist 下,需要自己手动添加(自己猜测!)。等待 mpvue 修复这个问题;期望能到达到自己设一个 image ,自己控制;

2.方法二:
官方给的解释是这样操作:把图片文件放到 static 文件夹下去引入;

image

73. input 聚焦掉起键盘,并且只能输入数字

问题描述

在实际项目开发中,会有需求为 input 聚焦掉起键盘,并且只能数字,开发者第一反应为 type 修改 number,但是 number 是允许输入 + - . e 四个字符的,以下是项目中的解决思路;

解决方案

1.方法一:

<template>
    <input
        type="number"
        placeholder="请输入手机号"
        name="phone"
        @keypress="onKeyPress()"
        v-model="phoneMessage"
        :class="{'hasContent':phoneMessage.length>0}"
    >
</template>
<script>
    onKeyPress () {
        event.returnValue = /[\d]/.test(String.fromCharCode(event.keyCode));
    }
</script>

以上方法在 pc 端可以,但是移动端 keypress 不会触发(移动端会触发 keyon 和 keydown),并且移动端输入小数点之后, phoneMessage 会变为空,所以不太完善。

2.方法二

<template>
    <input
        type="tel"
        placeholder="请输入手机号"
        name="tel"
        @input="onInput()"
        v-model="phoneMessage"
        :class="{'hasContent':phoneMessage.length>0}"
    >
</template>
<script>
    onInput () {
        let content = this.phoneMessage.split("").filter( (item,index) => {
            return /^[0-9]*$/.test(item) && index < 11;
        }).join("");
        this.phoneMessage = content;
    }
</script>

这种方案思路是将 input type 变为 tel,这样,在移动端只能掉起数字键盘,并且输入其他字符时,也能正常触发 input 事件,然后通过 js 来截取所需要的内容(京东的登录也是这种方案);

72. webpack 构建 npm 包优化

详情描述

webpack可用来构建发布到npm上去的给别人调用的js库,以下方案可以减少 npm 包的体积;

const nodeExternals = require('webpack-node-externals');
module.exports = {
  entry: {
    index: './src/index.js',
  },
  externals: [nodeExternals()],
  target: 'node',
  output: {
    path: path.resolve(__dirname, '.npm'),
    filename: '[name].js',
    libraryTarget: 'commonjs2',
  },
};

这里有几个区别于web应用不同的地方:

  • externals: [nodeExternals()]用于排除node_modules目录下的代码被打包进去,因为放在node_modules目录下的代码应该通过npm安装。
  • libraryTarget: 'commonjs2'指出entry是一个可供别人调用的库而不是可执行的,输出的js文件按照commonjs规范。

71. parcel 报错问题

问题描述

学习 parcel(号称0配置的打包工具)的时候报错: Unhandled promise rejection (rejection id: 1): SyntaxError: 'super' keyword unexpected here

解决方案

parcel 说明上是支持 node 6+,但是还是报错。node 6+ 不支持 async 函数,所以还是将 node 升级为 8+;

70. npm 发布更新包失败问题

问题描述

好久不更新的包今天想起来更新一下,但是 npm publish 的时候显示失败,然后开始找原因

解决方案

  1. 如果是已经发布过的包,则要修改 package.json 的verson 版本;
  2. 在实际开发项目中 npm 源下载包比较慢,所以一般使用的是淘宝源或者私有源,但是上传包更新包的时候只能使用 npm 源;

69. ios 上浏览器返回上一页不会刷新页面问题,页面初始化的方法不执行

问题描述

在 ios 上浏览器返回上一页不会刷新页面问题,页面初始化的方法不执行,造成了很多意外情况,这个问题不能忍;

解决方案

  1. 方法一:hack方法,加入iframe强制刷新后,去除
function(title){
   var u = navigator.userAgent;
   var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
   document.title= title;//添加标题
   if(isIOS){
       // hack在IOS微信等webview中无法修改document.title的情况
       var $iframe = $('<iframe src="/favicon.ico"></iframe>').on('load', function() {
           setTimeout(function() {
               $iframe.off('load').remove()
           }, 0)
       }).appendTo($('body'))
   }
};
  1. 方法二:利用 onpageshow 事件触发:
window.onpageshow=function(e){
    if(e.persisted) {
        window.location.reload() 
    }
};

68. vsCode 开发微信小程序插件

问题描述

用微信开发者工具开发微信小程序不适应;没事,我们还有强大的 vsCode;

解决方案

用 vsCode 开发微信小程序可以配置以下插件,让开发更美好:

  1. vscode weapp api
  2. vscode wxml
  3. vscode-wechat
  4. Easy WXLESS
  5. 有个和 vsCode 差不多,还可以预览的 IDE:Egret Wing;

67. vsCode 配置 html 文件警告

问题描述

IDE vsCode 会默认根据自己的规则来检测 html 文件书写格式;但是在实际项目中模板的格式可能会有与规则有些不同,比如:第一行必须为声明、属性不能为空等;本人有点偏强迫症,要找办法解决这种问题

解决方案

在当前项目的根目录下添加 .htmlhintrc 文件,vs 检查规则会通过这个文件;但是规则如何填写呢? 可以去 http://htmlhint.com/ 配置自己的忽略格式选项,配置完成下载下来粘贴到 .htmlhintrc 就ok了。

66. 移动端页面viewport缩放比不等于1时文本膨胀现象

问题描述

<meta name="viewport" content="width=device-width, initial-scale=1">

或是:

<meta name ="viewport" content ="initial-scale=1, maximum-scale=1, minimum-scale=1">

当initial-scale取值不等于1时,移动端页面可能出现:文本字号与CSS设置的font-size不一致,比font-size大许多的情况。
该现象称为Font Boosting,是webkit对于移动端页面优化的一种行为。
早期前端开发没有对移动端设备实行有效的适配时,PC端页面在移动端看来会显得极小,影响用户体验。
Webkit工作组为使用户不必滑动屏幕或双击放大屏幕也能看清页面内容,提出了Font Boosting特性。但它目前往往造成不必要的结果。
它的计算公式较为复杂,但实测可能在28px以上触发。

解决方案

避免其生效的方法有两种:

  1. 指定viewport width=320,其余属性取默认值(即不作设置);
  2. 将发生Font Boosting的元素显式设置宽高度;

显然以上两种方法均不适用,但对于方法2而言,max-height同样生效。
因此解决方法为:设置元素max-height:100%即可。

65. IE6.0-8.0不支持使用 rgba 模式实现透明度

问题描述

IE6.0-8.0不支持使用 rgba 模式实现透明度

解决方案

可使用 IE 滤镜处理 需要使用

filter: progid:DXImageTransform.Microsoft.Gradient(startColorstr=#88000000, endColorstr=#88000000);

64. 在微博浏览器上背景问题

问题描述

在微博浏览器上,页面底部为浅灰色

解决方案

在微博浏览器上;页面底层不设置背景色,在其父级或者body上设置 background-color 为需要的对应的颜色;

63. 埋点时,hash 改变没出发 hashChange 事件

问题描述

个人中心埋点时,跳转路由没有触发 hashChange 事件

解决方案

vue 2.8.0 以上;vue 触发的 hash 改变,不会触发 hashchage 事件;主张在 路由钩子去完成想要进行的操作;
将 vue 回退到了2.6版本;

62. input 上传第二次不能选择同一文件

问题描述

在上传图片过程中,同一个 input 选择同一张图片 不会触发 onchange事件,在选择不同图片时,会多次触发onchange事件;刚开始在选择完成后,删除重新初始化一个input ,这个方法有点山炮!!!

解决方案

不要采用删除当前input[type=file]这个节点,然后再重新创建dom这种方案,这样是不合理的。
解释如下:
input[type=file]使用的是onchange去做,onchange监听的为input的value值,只有再内容发生改变的时候去触发,而value在上传文件的时候保存的是文件的内容,你只需要在上传成功的回调里面,将当前input的value值置空即可。event.target.value='';

61. im 聊天中视频播放

问题描述

在 im 聊天聊天消息为视频时,可以点击播放;ios 会有统一的样式,但是在 android 上,微信平台会自动接管全屏播放,但是在 M 站上样式一踏糊涂;

解决方案

解决思路:
在 video 播放时,将video 播放设置全屏

//部分安卓机型(vivo x9;小米 note3)im聊天中播放发送的视频;先横屏,再点击播放,才正常;解决方案:先调用全屏的方法;然后再进行播放;
if (this.$refs.videoHtml.requestFullscreen) {
  this.$refs.videoHtml.requestFullscreen();
} else if (this.$refs.videoHtml.mozRequestFullScreen) {
  this.$refs.videoHtml.mozRequestFullScreen();
} else if (this.$refs.videoHtml.webkitRequestFullScreen) {
  this.$refs.videoHtml.webkitRequestFullScreen();
}
this.$refs.videoHtml.play();
//当用户退出播放视频时,还会有声音;
//解决方案:监听video,退出全屏,video 暂停;
$(document).on(
'fullscreenchange webkitfullscreenchange mozfullscreenchange', // 			webkitfullscreenchange/mozfullscreenchange
  function (evt) {
    let flag=document.fullscreen || document.webkitIsFullScreen || document.mozFullScreen;
    if (!flag){
      that.$refs.videoHtml.pause()
    }
  });

60. 移动端 click 事件

详情描述

移动端的 click 有300 ms的延时原因:在移动端触发时间会按照 touchstart,touchmove,touchend,click 顺序触发;触发 touchend,click 之间会有200-400不等的时间延时(因为移动端需要判断用户是不是想要进行双击);
fastclick 和 zepto 的tap 事件 都可以解决 300 ms延时;
fastclick 原理:
是在检测到touchend事件的时候,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后的click事件阻止掉。
tap 原理:
在touchstart 时会记录一个值x1,y1,在touchend时会记录x2,y2,通过对比着几个值,判断用户是否是点击事件,而不是滑动事件,然后直接触发事件;
注意:
fastclick 在ios 上会影响元素自动触发,比如 直接click();会拦截第一次,需要执行两次click();才会触发;安卓上不需要;

59. 上传图片预览图片方向错误

问题描述

ios手机上传竖拍照片会逆时针旋转90度,横拍照片无此问题;Android手机没这个问题。

解决方案

获取到照片拍摄的方向角,对非横拍的ios照片进行角度旋转修正。 利用exif.js读取照片的拍摄信息; 唯医骨科项目中用 canvas 把上传图片转为同等大小的图片显示并进行base64压缩上传;

58. im 聊天输入框高度问题

问题描述

输入框的高度随着字数增多而增高,但是超过一定高度后,不会增高,场景像微信的输入框一样;刚开始使用 autosize.js 控制 textarea ,但是在 ios11 有兼容问题,不断触发聚焦事件;

解决方案

舍弃 autosize.js ,用纯css + html 实现:
与textarea放一个平级的 pre 标签与 textarea 双向绑定;textarea 高度设置百分之百;textarea 父级的父级设置一个最大高度;父级不限制,然后textarea字数增加;pre标签也跟着增高,把父级撑开;textarea高度也就跟着父级变化;

57. 美团技术交流记录

详情描述

  1. dlpserver 目前仅在美团内部使用,测试阶段。充分利用 localstorage 缓存js;
    思路:
    页面引入一个dlp.js,在 a.html 中直接 require('a.js'), dlp.js 会带着 a.js(以及版本号) 去 dlpserver 中去请求,dlpserver 会判断 a.js 依赖哪些模块,哪些js,然后返回相应的 js 以及版本的 md5 加密,dlp.js 收到之后将返回的 js(字符串)eval(), 下次访问 b.html 时 require('.js'),dpl.js 去请求dlpserver 并且会带着上一次请求过 a.js 以及版本号, 返回 a.js 哪些缓存可以使用,还缺哪些,返回缺的 js 然后到本地 eval(),继续保存到 localstorage 中,localstorage 的限制是 5M,当超过 5M 存储的时候,会删除一半或者 2M。dlpserver 中会有一个版本号记录,想切换哪个版本的的时候直接在 dlpserver 中切换使用哪个版本、则线上就会切换,这样的话,上线只是将 js 版本 push 到 dlpserver 中,既实现了方便的增量上线,也能很快的回滚线上版本;
    解决的痛点:
    • webpack 把所有js 打到一个里面,不能够很好的利用缓存,有改动的话就得全部更新;
    • 把 js 都分开打包,但是 js 请求会更多;
    • webpack 把 js 分开打三个包(page包、vender包、common包),有的页面不需要一些公共方法也会被打包进去(目前业内的一种通用方案);
  2. hygrid 优化方案: 在不影响客户端启动的情况下,在一个合适的时机,启动一个隐藏的 webview;加载一个静态的html页面,从服务端请求一个压缩的 zip(zip文化可以有效的防止被爬) 压缩文件,里面有 vue.js、common.js 等公共js,隐藏的 webview 加载静态的 html 页面直接冲本地调用 vue.js、common.js 并且运行,缓存到内存中。
    优点:
    减少了启动 webview 的30ms 的时间,减少了公共js 的运行时间;也基本上可以秒开、无白屏;舍弃 react 的原因,react 在低端机上运行加载需要200ms 左右的时间,没有vue 性能好;
    缺点:
    webview 会一直占用手机运行内存、30M左右;
  3. api文档:
    呈现出来的是类似于我们使用的 apizza 一样,但是效果更好;不一样的地方是 apizza 需要后台去维护,美团的 api 文档是自动更新、自动抓取,不需要后台维护;
    思路:
    有使用 java 的技术解析后台写的 java接口文件,分析后台接口需要的参数、以及返回的数据;分析后台写的备注;每个备注匹配到相对应的字段后面(需要后台写好清晰明了的备注),在后台构建的时候会自动解析新加的接口和修改的接口;
    解决的痛点:
    前后台开发文档不同步;后台在写自己代码的备注的同时,还需要再维护开发文档(节省开发效率);
  4. 活动推广页的制作:
    直接在页面拖拽配置:有选项卡、雷达图、按钮、弹窗、可以配置各种动画、交互、答题;配置完成直接确定就可以线上访问;
    解决的痛点:
    这一套系统运营可以直接根据自己想法随时制作;不要开发人员每次开发;但是开发人员前期需要做大量的工作;

56. FileReader 对象

详情描述

HTML5文件操作的api,FileReader接口提供了读取文件的方法和包含读取结果的事件模型。
FileReader对象的方法:

  1. readAsText:该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。
  2. readAsBinaryString:该方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。
  3. readAsDataURL:这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符串的实质就是 Data URL,Data URL是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。

处理事件:

  • onabort 当读取操作被中止时调用.
  • onerror 当读取操作发生错误时调用.
  • onload 当读取操作成功完成时调用.
  • onloadend 当读取操作完成时调用,该处理程序在onload或者onerror之后调用.
  • onloadstart 当读取操作将要开始之前调用.
  • onprogress 在读取数据过程中周期性调用

55. ios9 中登录注册多出一条黑线

问题描述

ios9中,登录注册页面 input 框左右多一条黑线,border显示不正常

解决方案

ios9中,登录注册页面 p>input,input 应该脱离文档流,不然会出现左右多一条黑线,border显示不正常;原因不明;

54. ios9 以下 flex 兼容问题

详情描述

ios9 以下,display:flex 元素的第一级子元素必须是block,否则 flex 布局是不会生效的

53. H5 中调相机、多选等问题

详情描述

<input type="file" accept="image/*" capture="camera">
<input type="file" accept="video/*" capture="camcorder">
<input type="file" accept="audio/*" capture="microphone">

capture表示,可以捕获到系统默认的设备,比如:camera--照相机;camcorder--摄像机; microphone--录音。
accept表示,直接打开系统文件目录。

其实html5的input:file标签还支持一个multiple属性,表示可以支持多选,如:

但是安卓不支持多图上传,(会诊项目) 加上这个multiple后,capture就没啥用了,因为multiple是专门用来支持多选的。

注意:
input file 标签在安卓上想要掉起相机,需要添加capture="camera",但是此属性会影响 ios 的掉起相机,在ios上需要取消掉;

52. 推荐医生白色区块问题

问题描述

在 ios 上,推荐医生数据超过十条时,渲染不出来,为白色

解决方案

替换ul、li标签为section标签; 具体原因不明

51. 推荐医生头像问题

问题描述

在ios9.3.2上滑动,图片会变成方形,其他手机没问题,。

解决方案

推荐医生医生头像,div 里面套了个 img 标签,只给 div 设置 border-radius: 50%;在 ios9.3.2 上滑动,图片会变成方形,其他手机没问题,给img也添加border-radius: 50%;

50. IM中输入框的问题

详情描述

  1. ios(特别是UC浏览器)对底部fiexd布局,兼容不好,再聚焦的时候fiexd会漂,所以不能用fiexd布局;
  2. ios底部输入框用的是relative,absolute会再部分ios机子上全屏感觉有个遮罩层,使全屏不可点,点的时候有个黑色透明的遮罩层闪烁;
  3. android 底部输入框用的是absolute,relative 布局在安卓上输入框会覆盖在虚拟键盘下面;
  4. ios11.1.2 对面几种布局支持性都不好,当虚拟键盘出来后,输入框不会被挤到上面(因为body高度不变);解决方式比较暴力,判断是ios11.1.2,数据框聚焦把body变为50%,失焦恢复;

49. iscroll 和 better-scroll

详情描述

iscroll 和 better-scroll 的对比 iscroll的兼容性比较强,用requestAnimationFrame(表意为“请求动画帧”)实现,可以兼容到 ie6,requestAnimationFrame是根据浏览器的最小渲染值来触发;达到流畅效果;但是已经停止维护 better-scroll 是滴滴负责人黄轶写的,使用css3和requestAnimationFrame;默认优先使用css3,参数可以配置;

48. better-scroll的实现原理

详情描述

父容器固定高度,并设置属性 overflow:hidden,使得子元素高度超出容器后能被隐藏。better-scroll作用在父容器上。通过touch事件给子容器设置transform:translate()translateZ();
注意:
Vue中数据更新是异步的,在数据还没有加载完之前,BScroll是无法获取目标内容容器的高度的,就会出现无法滚动的现象。

47. scroll 事件的触发

详情描述

window.addEventListener('scroll',function () {

})
//ios上只会在滚动稳定后出发;安卓会有间隔的持续触发;

46. ios 上 IM 页面路由跳转白屏

问题描述

vue 手机端项目在进入主页后在进入子页面,直接按返回出现空白情况,然后轻触一下,空白区域就消失了
安卓手机上不会,ios 会出现这种情况。

解决方案

这是safari的ios render blank.

//拿到数据之后
this.$nextTick(() => {
	window.scrollTo(0, 1)
	window.scrollTo(0, 0)
})

45. Safari 中双指放大缩小问题

问题描述

为了提高Safari中网站的辅助功能,即使网站在视口中设置了user-scalable = no,用户也可以手动缩放。

解决方案

监听事件来阻止

window.onload=function () {  
 	document.addEventListener('touchstart',function (event) {  
        if(event.touches.length>1){  
            event.preventDefault();  
        }  
    })  
    var lastTouchEnd=0;  
    document.addEventListener('touchend',function (event) {  
        var now=(new Date()).getTime();  
        if(now-lastTouchEnd<=300){  
            event.preventDefault();  
        }  
        lastTouchEnd=now;  
    },false)  
}  

淘宝的解决方案也是如此 ;但是并不能很好的解决;

44. vue 中的通信

详情描述

父子组件通信:
  1. 子组件触发父组件函数:
子组件:
<template>
    <button @click="submit">提交</button>
</template>
<script>
export default {
  props: {
    onsubmit: {
      type: Function,
      default: null
    }
  },
  methods: {
    submit: function () {
      if (this.onsubmit) {
        this.onsubmit(‘cc12345’)
      }
    }
  }
}
</script>
父组件:
<template>
    <editor id="editor" class="editor" :onsubmit="cc"></editor>
</template>
<script>
export default {
  methods: {
    cc: function (str) {
      alert(str)
    }
  }
}
</script>
  1. 子组件修改父组件传过来的值:this.$emit('update:foo', newValue);父组件通过v-bind绑定并且写上.aync;
  2. 由于javascript的特性,父组件像子组件传一个对象,子组件修改也会出发父组件变化;
非父子组件通信
  1. 用一个新的 vue 实列管理
var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
 		 // ...
})
  1. 用vuex状态管理

43. es6 新增方法处理

详情描述

es6中Array.includes和Object.assign方法在部分浏览器中支持性不太好,需要用babel-polyfill处理。

42. 页面唤起拨打电话

详情描述

  1. window.location.href = "tel:010-59007006";支持性比较好,ios、安卓都支持
  2. 用 a 标签:
<a href="tel:010-59007006" class="make-call" ref="makeCall"></a>;
//直接点击ios、安卓都支持、但是使用自动触发安卓支持、ios支持不太好;

41. vue 双向绑定数据限制长度

问题描述

vue中输入框v-modle 双向绑定的数据;在需要的业务场景下需要对其进行字数长度限制;

解决方案

可以使用以下方法:

  1. 方法一:
//方法一:输入框添加keypress方法;然后函数为:
maxLength(attr,length){
	let keyCode = event.keyCode;
	console.log("keyCode");
    	let len=0;
	console.log(this[attr].length);
	for (let codePoint of this[attr]) {
 		if (this[attr].charCodeAt(codePoint) > 128) {
    			len += 2;
  		} else {
   	 		len++;
  		}
    	}
	if (len < length) {
  		event.returnValue = true;
	} else {
  		event.returnValue = false;
	}
},
//注意:事件必须为keypress;
//keydown 可以做限制,但是达到长度不可以删除;keyup不行;
  1. 方法二:
//方法二:输入框添加input方法;然后函数为:
inputMaxLength(attr,length){
  		this[attr] = api.getStrByteLen(this[attr], length);
},

方法对比:
方法一优点,循环少,性能高;缺点,中文输入法空格输入字符的时候不会触发;
方法二优点,兼容性好,适合各种场景;缺点,循环多,性能比较差;

40. vue中 v-if 遇到的问题

问题描述

在添加患者中;botton 按钮用 v-if 隐藏掉之后,出现了不可见,但是可以点击的情况

解决方案

在 botton 外层添加了一层 session 标签;可能是 v-if 对行内块原理有兼容性;

39. vue中 keep-alive 的使用

问题描述

在业务开发中,会有路由跳转但是返回需要保留数据的场景;vue 中提供了 keep-alive 来处理

解决方案

返回dom不让其重新刷新,在vue-view外面包一层, 当引入keep-alive的时候,页面第一次进入,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。当再次进入(前进或者后退)时,只触发activated。
事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中; 可以将 是否包裹 keep-alive 通过参数配置;

<keep-alive>
  	<router-view v-if="$route.meta.keepAlive" style="min-height:100%"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" style="min-height:100%"></router-view>
//不需要刷新的路由配置里面配置 meta: {keepAlive: true}, 这个路由则显示在上面标签;
//需要刷新的路由配置里面配置 meta: {keepAlive: false}, 这个路由则显示在下面标签;

38. 数组的过滤器 filter 的问题

详情描述

对象或者数组的过滤器filter,不能使用第三方变量过滤; 比如:var num = value ; return num>0; 必须写成:return value>0;

37. 在不翻墙的情况下下载vue调试插件(vue-DevTools)

详情描述

  1. Chrome地址栏输入"crx.2333.me"
  2. 然后把你要下载的扩展ID填到输入框中,点击"Get"(vue的id:nhdogjmejiglipccpnnnanhbledajbpd)
  3. 点击"成功Get,点我下载"
  4. 或者在github 上搜vue-Devtools

36. vue中 v-if 和 v-show

详情描述

  1. v-if是惰性的,每次false之后会删除元素,这样,每次显示的时候都会重新走选择城市的接口。
  2. v-show,只是简单的显示隐藏

35. 视频中的坑

详情描述

参考自此链接 以及乔的ppt;

  1. 自动播放问题: 通过autoplay属性 视频的自动播放需要在video标签上添加autoplay属性, 如:<video autoplay><video/>
    但是在很多浏览器里,如 iOS 下并不支持这个属性,在 iOS下必须给webview设置 self.wView.allowsInlineMediaPlayback = YES;self.wView.mediaPlaybackRequiresUserAction = NO; 才能让这个属性生效从而让用户一进入页面就开始视频的自动播放 在微信下因为不允许视频直接播放,则必须通过用户的真实操作来触发调用video.play(),这就是各种微信的h5活动页面需要引导用户进行一下点击操作才开始的原因。
  2. 页面内联播放问题:在iOS Safari 和一些安卓的一些浏览器下播放视频的时候,不能在h5页面中播放视频,系统会自动接管视频 如果需要在h5页面内播放视频,需要在视频标签上加上 webkit-playsinline,在iOS10以后,需要加上playsinline,建议同时加上这两个属性,同时需要app支持这种模式,手Q和微信都支持这种模式
    <video id="player" webkit-playsinline playsinline > (在html) webview.allowsInlineMediaPlayback = YES(在app内设置webview属性);
  3. 视频的高度问题:在安卓下,一些浏览器如 QQ 浏览器和 UC 浏览器,系统会把视频的层级调到最高,所以如果想在页面上显示 dom 元素,都会被视频盖住,单纯的设置该dom的z-index是无效的
    解决方案:
    1. 在弹出会显示在视频上方dom的时候暂停视频播放
    2. 将视频所在的dom的父元素的高度设为1
    3. 处理完弹出的事件后将视频所在的父元素高度还原
    4. 视频的默认播放图标
  4. 在 iOS 下会有一个默认的播放图标,在 iOS 都会默认显示,不能通过 js 控制,但是可以通过css样式将其隐藏
	video::-webkit-media-controls-start-playback-button { display: none;}

34. 滚动穿透问题

详情描述

解决方法:

  1. 在弹层出现时给body设置position:fixed,top:-滚动条高度;弹层消失的时候获取body的top,$(window).scrollTop(-body的高度)。解决大部分场景,在ios微信浏览器无法禁止微信浏览器原生的弹性黑层;
  2. 用iscroll.js+禁止touch事件(唯医答题用的方法)解决

33. app引导页的判断

详情描述

  1. 判断是否是第一次打开,本地存储一个标识符,第一次打开后设置为true,以后进入判断该标志符,为false则可以进入引导页;
  2. 判断是否是同一版本号,进入时判断本地保存的版本号和打开的版本号是否是同一版本号,如果不是,则进入引导页,并且把版本号设置为当前版本号;

32. 页面跳转的方式以及区别

详情描述

跳转方式有:

  • window.location.href,
  • window.location.replace(),
  • window.location.reload()

三者的区别:

  1. window.location.href=“url”:改变url地址;
  2. window.location.replace(“url”):将地址替换成新url,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,你不能通过“前进”和“后 退”来访问已经被替换的URL,这个特点对于做一些过渡页面非常有用!
  3. window.location.reload():强制刷新页面,从服务器重新请求! 解决的问题,在app中嵌套的网页中,收到传的参数时,用replace替换当前url。且不加入历史栈

31. 什么是 URL Schema?

详情描述

Android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;通过scheme协议,服务器可以定制化告诉App跳转那个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。
详细链接点此进入

30. app 与 js 之间的交互

详情描述

采用的框架是 WebViewJavascriptBridge,采用这套框架可以方便的使 native 与 JS 交互
详细链接点此进入

29. window.name 的使用

详情描述

window.name 给当前窗口起名字,iframe也可这样使用。
name 在全局下是关键字;
window.open('','MyName','width=200,height=100');

  • 参数一:url,打开的链接;
  • 参数二:打开窗口的名字;
  • 参数三:打开窗口的大小px; 应用场景:
  1. 用来判断此窗口是刷新,还是重新打开的窗口,来执行不同的操作;
  2. 跨域(待补充);

28. 代码计时器

详情描述

console.time("main");
console.timeEnd("main")。

27. canvas图画保存成本地图片的方法

详情描述

var oCanvas = document.getElementById("thecanvas");
Canvas2Image.saveAsPNG(oCanvas);  // 这将会提示用户保存PNG图片
Canvas2Image.saveAsJPEG(oCanvas); // 这将会提示用户保存JPG图片
Canvas2Image.saveAsBMP(oCanvas);  // 这将会提示用户保存BMP图片
// 返回一个包含PNG图片的<img>元素
var oImgPNG = Canvas2Image.saveAsPNG(oCanvas, true); 
// 返回一个包含JPG图片的<img>元素
var oImgJPEG = Canvas2Image.saveAsJPEG(oCanvas, true); 
// 返回一个包含BMP图片的<img>元素
var oImgBMP = Canvas2Image.saveAsBMP(oCanvas, true);

26. json 的注意事项

详情描述

自己写的json字符串中必须用双引号。使用单引号无法转换成json对象;

25. input 输入框输入中文

问题描述

在input输入框输入中文时,需要即时查询出匹配输入内容的结果,一般我们会使用input事件监听用户输入事件,但是在输入汉语拼音时,也会触发input事件,前端就会不断发送请求,用户体验非常差劲。

解决方案

针对这种情况,给大家介绍一个简单易懂的好方法。代码如下:

function in2 () {
	var cpLock = false;
    $('#in2').on('compositionstart', function () {
        cpLock = true;
        console.log("中文输入:开始");
		$("span").text("kaishi");
		$(this).off("input");
    });
    $('#in2').on('compositionend', function () {
        cpLock = false;
        console.log("中文输入:结束")
		$("span").text("jieshu");
		console.log($(this).val().length);
		$(this).on('input', function () {
            if (!cpLock) {
                console.log($(this).val().length);
            }
        });

	});
}

原理:
当浏览器有非直接的文字输入时, compositionstart 事件会以同步模式触发.
当浏览器是直接的文字输入时, compositionend 会以同步模式触发.
当元素监听到 compositionstart 事件,给 input 中事件加锁,禁止 input中事件执行,
当元素监听到 compositionend 事件,给input中事件解锁,正常执行。

24. 输入框的事件的几种触发事件对比

详情描述

  1. change事件 触发事件必须满足两个条件:
    • 当前对象属性改变,并且是由键盘或鼠标事件激发的(脚本触发无效)
    • 当前对象失去焦点(onblur)
  2. keypress 恩,还好。。。。。就是能监听键盘事件,鼠标复制黏贴操作他就无能为力
  3. propertychange(ie)和input事件

input是标准的浏览器事件,一般应用于input元素,当input的value发生变化就会发生,无论是键盘输入还是鼠标黏贴的改变都能及时监听到变化
propertychange,只要当前对象属性发生改变。

23. jQuery 中 data() 引发的错误

详情描述

jQuery 中 data()解释为可以获取、设置元素自定义的属性,但是尽量不用data()方法去获取元素的自定义属性;因为会引发一些隐形错误;

  1. 只能获取到第一次赋值的属性,之后通过修改的值获取不到;
  2. 如果值是string类型的数字,比如“123”,获取的时候会强转为number,123;
  3. 所以建议还是使用 $("div").attr() 的方法去获取

22. js打开新页面的几种方式

详情描述

  1. window.location.href=goUrl;
  2. window.open(goUrl,"_self");
  3. location.replace(goUrl);
  4. location.assign(goUrl);

21. 跨域的方式

详情描述

具体详情见微信朋友圈

  1. jsonp,动态创建script标签,scr设置为需要跨域的域名,加callback回掉函数参数。但是支持get请求,且必须后台支持jsonp跨域;
  2. document.domain 设置相同的doncument.domain,动态创建一个隐藏的iframe来跨域;
  3. window.name 这个全局属性主要是用来获取和这只窗口名称,但是通过结合ifame也可以跨域获取数据。
  4. window.postMessage 是HTML5新增在window对象上的方法,目的是为了解决在父子页面上通信的问题。该技术有个专有名词;跨文档消息(cross-document messaging)。利用postMessage的特性可以实现较为安全可信的跨域通信。
  5. 使用代理服务器跨域;
  6. CORS 跨域

20. select 默认选中问题

问题描述

select 标签会默认选中第一个 option ;但是一般使用的时候不想要默认选中第一个,而是一个空白的选择框

解决方案

  1. 给select元素pretend一个 <option stype="display:none">;
  2. 给select元素pretend一个 <option disabled = "disabled">;

19. 兼容脚本

详情描述

  1. rem.js 使IE8能够识别rem单位(但是不能控制伪元素);
  2. html5shiv.js 使IE8识别HTML5标签;
  3. pie.htc 识别部分css3样式属性(border-radius等);
  4. response.js 使用js模仿媒体查询;

18. 移动端 border 宽度问题

详情描述

在移动端布局中,经常使用 rem 单位,但是 border 使用热门单位时会有兼容性, 比如魅族手机浏览器,ios 部分系统;border 不显示;可以使用 px 布局;

17. flex布局中的注意事项

详情描述

父级设置:display: flex;flex-wrap: wrap(超出部分换行,no-wrap 不换行wrap : 第一行在上面;wrap-reverse: 换行,第一行在下面);子集纵轴排列会默认每个项目两侧的间隔相等,项目之间的间隔比项目之间的边框的间隔大一倍;如果需要清除默认样式的影响,则设置justify-content: flex-start(flex-start :左对齐;flex-end: 右对齐;center:居中;space-between:两端对齐,项目之间的间隔都相等;space-around:每个项目两侧的间隔相等,项目之间的间隔比项目之间的边框的间隔大一倍)(实列见复诊建议项目框);

16. jQuery选取元素

详情描述

jQuery([selector,[context]])
selector:用来查找的字符串
context:作为待查找的 DOM 元素集、文档或 jQuery 对象。
$("p,div") 找到元素p和div
$("p","div") 找到div里面的p

15. 布局垂直对齐的方式

详情描述

  1. 左右容器分别设置display:table-cell;vertical-align:middle;
  2. 左右容器分别设置display:inline-block;vertical-align:middle;(会出先兼容问题,比如努比亚z11line-height不起效果;可以利用padding居中,把空白撑开)

注意: display:table-cell属性指让标签元素以表格单元格的形式呈现,可以实现元素的垂直居中对齐(vertical-align:middle;),关联伸缩等,与其他一些display属性类似,table-cell同样会被其他一些CSS属性破坏,例如float, position:absolute

14. cookie 和 session 的区别

详情描述

  1. cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
  2. cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗考虑到安全应当使用 session 。
  3. session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻 服务器性能方面,应当使用 COOKIE 。
  4. 单个 cookie 保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个 cookie 。
  5. 所以个人建议:
    • 将登陆信息等重要信息存放为SESSION
    • 其他信息如果需要保留,可以放在COOKIE中

13. 自动登录的实现

详情描述

  1. 第一次登录之后,后台会在返回的cookie里保存的一些东西,然后每个页面都会掉一次getLapList接口,后台会判断cookie里是否有之前返回过的东西,根据返回的数据,成功则获取到用户的基本信息,失败则进入登录页面;
  2. 用户点击退出登录之后,退出登录的接口成功后,后台会清除cookie,下次用户从新登录;

注意: 后台可以设置cookie是否可读可写,自动登录的机制(安全角度讲)下后台会禁止前端拿到后台设置的cookie进行读写;

12. 移动端的几种适配

详情描述

  1. 淘宝:使用viewport缩放,通过给html添加 data-dpr=xx, 设置html字体大小,来适配移动端,唯医模仿淘宝;单位使用rem;
  2. 天猫:禁止viewport缩放,定高不定宽,使用弹性盒子布局;单位使用px;
  3. 京东:禁止viewport缩放,宽高都使用百分比,设置最大宽度和最小宽度;通过@media媒体查询,设置不同的宽高;单位使用px;
  4. 小米:禁止viewport缩放,单位使用rem;当屏幕宽度改变时,html标签的行内样式font-size跟着改变(自己感觉可以根据window.resize()可以实现);

11. jQuery中判断一个元素是否显示或者隐藏

详情描述

  1. 第一种方式:

alert($('.div1').is(':hidden'));//false,没隐藏
alert($('.div2').is(':hidden'));//true,隐藏了
$('#dvData').is(":visible")
  1. 第二种方式:
if ($('#dvData').css('display') == 'none') {
    // Item is hidden. Write your code.
}
if($('#dvData').is(":visible")){
     // Item is hidden. Write your code.
}
if ($('#dvData').css("visibility") == "hidden"){
   // Item is hidden. Write your code.
}

10. ios中的一些兼容问题

详情描述

  1. ios8.4.1版本中对jQuery中closeset()、find()、存在兼容性,只能直接使用jQuery对象去使用这些方法。通过赋值的方法去调用不起作用;
  2. ios上微信端a标签href必须填写(JavaScript:0;);否则无法点击
  3. ios上微信端不给元素设置 cursor:pointer 样式,可能会出现在手机上无法点击的情况;

9. require.js 做单页面应用

详情描述

require.js配合插件text.js实现最简单的单页应用程序;text和image插件,则是允许require.js加载文本和图片文件。详细代码见项目;require.js的好处:

  1. 实现js文件的异步加载,避免网页失去响应;
  2. 管理模块之间的依赖性,便于代码的编写和维护。

8. 分享qq空间出现失败

详情描述

做 qq 分享时,如果给 qq 的链接参数中有中文;会分享失败;

7. img 标签边框问题

详情描述

<img>标签默认有固定宽度,并且不设置src属性或者src属性=“”时,会有默认边框,想让边框消失的一个解决办法:
利用属性选择器[src=""]让的 img 的 src 属性为空的透明度设为0;如下:

img[src=""],img:not([src]){
  opacity:0;
}

6. filezilla连接服务器连接不上

详情描述

ftp协议默认使用的是21端口,80端口默认是使用的http协议,也就是网站默认是使用的80端口您这边需要先配置FTP服务,然后才能使用ftp软件登录您的服务器。之前登录服务器是使用的sftp,也就是通过22端口来登录的。对于FTP的配置,linux 推荐 vsftpd

5. 自执行函数的使用

详情描述

  1. 在模板中循环添加数据并返回;
  2. 减少全局变量,最后用window.xxx=xxx;把方法暴露出去就可以(是模块化开发演变中的一个历程);
  3. 自执行函数可以直接绑定在 onClick 上;比如:
<button onClick="(function(){alert('1')})()">执行</button>

4. 按钮置灰不能点击的方法

详情描述

  1. 给button添加disabled的属性。注意,控制disabled为ture或者false才能起作用;
  2. 给添加单独的类名显示不同的颜色,然后点击的时候判断return false;
  3. 控制两个button,一个绑定事件,一个不绑定;通过控制验证字段是否通过来控制按钮的显示隐藏;

3. 给元素添加事件满足的条件

详情描述

  1. 确保元素已经加载出来再添加;
  2. 利用事件委托的方式去添加事件(比较常用的一种方案);利用事件流的冒泡机制,可以给父元素委托事件;这样动态添加的子元素也会有事件;

2. jQuery 中 trigger 的使用

详情描述

  1. trigger不可以直接触发input(file)、select的原生事件;可以触发给元素添加的事件;但是如果trigger外面包了一层on(“click”),则可以触发input(file)、select的原生事件
  2. trigger触发某个元素的某个事件,首先得让那个元素把那个事件添加的函数提前执行;比如可以使用 trigger 做进入页面自动定位的功能,但是在触发 trigger 之前,必须确保触发元素的事件已经绑定上;
  3. fastclick.js会影响trigger的使用,出现点击第一次没有出现响应,第二次才起效果(具体原因请看移动端 300ms 延时问题)

1. stickfooter黏性底部

问题描述

问诊咨询流程页,布局需要将下一步(提交)按钮在内容较少时,固定在底部;内容超出页面高度时,跟随内容高度下面

解决方案

这种布局就是 stick footer 黏性底部布局;这里提供两种方案实现以及实现的思路;
思路为有一个 min-height:100% 的元素,围绕这个元素做文章;注意 html 需要设置 height:100%;

方案一:footer绝对定位-并加一层父元素

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin:0;
            padding:0;
            box-sizing: border-box;
        }
        html,body{
            height: 100%;
            /*min-height: 100%;*/
            min-width: 1200px;
        }
        body{
            font: 14px/1.5 "Microsoft YaHei", sans-serif;
            color: #666666;
            background: #e8e8e8;
        }
        .body{
            position: relative;
            min-height: 100%;
            height:auto !important;
            height:100%;//IE6不识别min-height
        }
        .header{
            width: 100%;
            background-color: #f1a899;
            height: 64px;
            box-shadow: 0 0 0 transparent, 0 0 0 transparent, 0 4px 8px #DFDFDF, 0 0 0 transparent;
        }
        .section{
            width: 1200px;
            margin: 0 auto;
            padding: 30px 0 145px;
        }
        .container{
            background: #ffffff;
            height:500px;
        }
        .footer{
            position: absolute;
            bottom: 0;
            height: 95px;
            width: 100%;
            background: #858B9A;
        }
    </style>
</head>
<body>
<div class="body">
    <div class="header">
        header页面头部
    </div>
    <div class="section">
        <div class="container">
            页面主体内容
        </div>
    </div>
    <div class="footer">
        footer页面底部
    </div>
</div>
</body>
</html>

方案二:footer加负值上边距

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html, body {
            height: 100%;
            min-height: 100%;
            min-width: 1200px;
        }

        body {
            font: 14px/1.5 "Microsoft YaHei", sans-serif;
            color: #666666;
            background: #e8e8e8;
        }

        .header {
            width: 100%;
            background-color: #f1a899;
            height: 64px;
            box-shadow: 0 0 0 transparent, 0 0 0 transparent, 0 4px 8px #DFDFDF, 0 0 0 transparent;
        }

        .section {
            min-height: 100%;
            padding: 0 0 95px;
        }

        .container {
            width: 1200px;
            height: 500px;
            margin: 30px auto;
            background: #ffffff;
        }

        .footer {
            height: 95px;
            margin-top: -95px;
            width: 100%;
            background: #858B9A;
        }
    </style>
</head>
<body>

<div class="section">
    <div class="header">
        header页面头部
    </div>
    <div class="container">
        页面主体内容
    </div>
</div>

<div class="footer">
    footer页面底部
</div>
</body>
</html>

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors