样式适配问题
同一页面,同一元素,展示出左右2中形态(华为mate30pro设备分辨率1176*2400,宽度单位使用的rem)。
大家思考下,为什么会有这个问题?
引申一下
像素分类:设备像素和CSS像素
- 设备像素(device independent pixels): 设备屏幕的物理像素,任何设备的物理像素的数量都是固定的
- CSS像素(CSS pixels): 又称为逻辑像素,是为web开发者创造的,在CSS和javascript中使用的一个抽象的层
- 每一个CSS声明和几乎所有的javascript属性都使用CSS像素,因此实际上从来用不上设备像素 。
在桌面端,css的1个像素往往都是对应着电脑屏幕的1个物理像素。
手机端,由于屏幕尺寸的限制,缩放是经常性的操作。
缩小操作时,一个设备像素覆盖了多个CSS像素
放大操作时,一个CSS像素覆盖了多个设备像素
不论缩小或放大,元素设置的CSS像素(如width:300px)是始终不变的,而一个CSS像素对应多少个设备像素是根据当前的缩放比例来决定的。
在HTML中不得不提到viewport,经常会设置viewport的width=device-width,那这个device-width的值是多少呢?
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
在iphone5下device-width=320,iphone6下是375,iphone6+下是414。
DPR:
设备像素比DPR(devicePixelRatio)是默认缩放为100%的情况下,设备像素和CSS像素的比值
dpr,也被成为device pixel ratio,即物理像素与逻辑像素的比,那也就不难理解:iphone6下dpr=2,iphone6+下dpr=3(考虑的是栅格化时的像素,并非真实的物理像素;
问题原因:
由于华为浏览器版本问题,低版本华为浏览器支持最小像素为12px,高版本则无限制。
如何规避类似问题:
采用postcss-pxtorem 和 flexible
postcss-pxtorem作用:将px转换为rem
flexible 作用:计算根font-size (flexible.js )
postcss-pxtorem使用方法:
main.js中
// 引入 flexible 用于设置 rem 基准值
import 'lib-flexible/flexible.js';
.postcssrc.js配置
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {},
'postcss-pxtorem': {
rootValue({ file }) {
return file.indexOf('vant') !== -1 ? 37.5 : 117.6;(width/10)
},
"propList": ['*'],
"selectorBlackList": ['.norem'] // 过滤掉 .norem 开头的 class,不进行转换
}
}
}
1px 边框(vant)
<!-- 上边框 -->
<div class="van-hairline--top"></div>
移动端1px实现方案( https://zhuanlan.zhihu.com/p/100752129 )
性能优化
路由懒加载
一、定义
懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。
二、写法
常用的懒加载方式有两种:即使用vue异步组件 和 ES中的import
未懒加载写法:import index from '@/pages/index/index.vue';
懒加载写法1:const index = () => import('@/pages/index/index.vue');
routes: [
{
path: '/',
name: 'index',
component:index
}]
懒加载写法2
routes: [
{
path: '/',
name: 'index',
component: resolve=>(require(["@/pages/index/index.vue"],resolve))
}]
三、打包后区别
未做懒加载dist包中js文件夹
修改为懒加载dist包中js文件夹
图片压缩(https://tinypng.com/)
开启gzip
一、配置
config/index.js/productionGzip: true (打包效果如上图)
二、效果
当 HTML 文档解析完成就会触发 DOMContentLoaded,而所有资源加载完成之后,load事件才会被触发。 jQuery 中经常使用的 $(document).ready(function() { // …代码… }); 其实监听的就是 DOMContentLoaded 事件,而 $(document).load(function() { // …代码… }); 监听的是 load 事件。
三、使用安卓壳cdr缓存
组件按需加载
一、vant按需加载
二、echarts按需加载
main.js中
使用cdn缓存(网络限制未使用)
一、资源引入
在index.html中,添加CDN资源,例如bootstrap上的资源:
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
</body>
二、添加配置
在bulid/webpack.base.conf.js文件中,增加externals,将引用的外部模块导入,如下:
module.exports = {
entry: {app: './src/main.js'},
externals:{'vue': 'Vue','vue-router': 'VueRouter'}
}
三、去掉原有的引用
去掉import、去掉Vue.use(XXX)等如:
// import Vue from 'vue'
// import Router from 'vue-router'
// Vue.use(Router)
交互优化
一、增加超时时间
ajax.js中,
ajax.defaults.timeout = 10000;
二、增加超时提示
ajax.js后置拦截器error中,增加
if (error && error.stack.indexOf('timeout') > -1) {
Toast.fail({message: '连接超时,请检查你的网络'});}
else if (error && error.stack.indexOf('Network Error') > -1) {
Toast.fail({ message: '当前网络不可用,请检查你的网络'});
}
weixin-js-sdk用法
npm i -S weixin-js-sdk
使用
//引入
import wx from 'weixin-js-sdk';
//请求接口获取jsapi_ticket
const params = {
//当前页面url
url:location.href.split('#')[0],
//随机字符串
noncestr:Math.random().toString(36)
.substr(2, 15),
//时间戳
timestamp:parseInt(new Date().getTime() / 1000)
};
//接口返回票据后注册
wx.config({
debug: false,
appId: 'wld341060039',
timestamp:params.timestamp,
nonceStr: params.noncestr,
signature: res.ticket,
//注册事件 选择照片/拍照 获取本地照片数据
jsApiList: ['chooseImage', 'getLocalImgData']
});
// 通过ready接口处理成功验证
wx.ready(function () {
console.log(666);
});
// 通过error接口处理失败验证
wx.error(function (res) {
console.log('error', res);
});
// 判断当前客户端版本是否支持指定JS接口
wx.checkJsApi({
// 需要检测的JS接口列表,所有JS接口列表见附录2,
jsApiList: ['chooseImage', 'getLocalImgData'],
success: function (res) {
console.log(res);
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
拍照或从手机相册中选图接口
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
quality: 0.8, //压缩质量,范围0~1,数值越小,质量越低,压缩率越高(仅对jpg有效)
success: function (res) {
// 返回选定照片的本地ID列表(绝对路径),localId可以作为img标签的src属性显示图片
var localIds = res.localIds;
}
});
获取本地图片接口
wx.getLocalImgData({
localId: '', // 图片的localID
success: function (res) {
//localData是图片的base64数据,可以用img标签显示
let localData = res.localData;
//ios与安卓兼容问题
if (localData.indexOf('data:image') != 0) {
// 判断是否有这样的头部
localData = `data:image/jpeg;base64,${localData}`;
}
localData = localData.replace(/\r|\n/g, '').replace('data:image/jgp', 'data:image/jpeg');
}
});
ios压缩图片问题
图片压缩方法
cutImageBase64(base64, w, callback) {
const newImage = new Image();
let quality = 0.6; // 压缩系数0-1之间
newImage.src = base64;
newImage.setAttribute('crossOrigin', 'Anonymous'); // url为外域时需要
let imgWidth, imgHeight;
newImage.onload = function () {
imgWidth = this.width;
imgHeight = this.height;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (Math.max(imgWidth, imgHeight) > w) {
if (imgWidth > imgHeight) {
canvas.width = w;
canvas.height = w * imgHeight / imgWidth;
} else {
canvas.height = w;
canvas.width = w * imgWidth / imgHeight;
}
} else {
canvas.width = imgWidth;
canvas.height = imgHeight;
quality = 0.6;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
let base64 = canvas.toDataURL('image/jpeg', quality); // 压缩语句
// 如想确保图片压缩到自己想要的尺寸,如要求在50-150kb之间,请加以下语句,quality初始值根据情况自定
while (base64.length / 1024 > 150) {
quality -= 0.01;
base64 = canvas.toDataURL('image/jpeg', quality);
}
// 防止最后一次压缩低于最低尺寸,只要quality递减合理,无需考虑
while (base64.length / 1024 < 50) {
quality += 0.001;
base64 = canvas.toDataURL('image/jpeg', quality);
}
// 必须通过回调函数返回,否则无法及时拿到该值
callback(base64);
};
}
使用压缩图片
this.cutImageBase64(base64, 700, this.uploadImgbas);
压缩后的数据
uploadImgbas(base64) { console.log(base64)}
ios注意事项
在IOS中,canvas绘制图片是有两个限制的:
首先是图片的大小,如果图片的大小超过两百万像素,图片也是无法绘制到canvas上的,调用drawImage的时候不会报错,但是你用toDataURL获取图片数据的时候获取到的是空的图片数据。
再者就是canvas的大小有限制,如果canvas的大小大于大概五百万像素(即宽高乘积)的时候,不仅图片画不出来,其他什么东西也都是画不出来的。
应对上面两种限制,我把图片宽度、高度压缩控制在1000px以内,这样图片最大就不超过两百万像素了。在前端开发中,1000px*1000px基本可以满足绝大部分的需求了。当然了还有更完美的瓦片式绘制的方法,我们这里就说瓦片式绘制方法了。
如此一来就解决了IOS上的两种限制了。
除了上面所述的限制,还有两个坑,一个就是canvas的toDataURL是只能压缩jpg的,当用户上传的图片是png的话,就需要转成jpg,也就是统一用canvas.toDataURL(‘image/jpeg’, 0.5) , 类型统一设成jpeg,而压缩比就自己控制了。
另一个就是如果是png转jpg,绘制到canvas上的时候,canvas存在透明区域的话,当转成jpg的时候透明区域会变成黑色,因为canvas的透明像素默认为rgba(0,0,0,0),所以转成jpg就变成rgba(0,0,0,1)了,也就是透明背景会变成了黑色。解决办法就是绘制之前在canvas上铺一层白色的底色。