2020/03/30 周一
#JSON数据转Blob后,怎么还原
在axios请求下载文件接口时,一般设置responseType: ‘blob’,文件返回正常就没问题,但后台如果处理文件或鉴权有问题,接口返回了包含错误信息的json格式数据,那样json数据也会转为Blob对象,而前端有必要将错误信息展示的,那怎么将Blob数据转JSON呢?下面来看看
let fileType = res.headers['content-type']
if (fileType.startsWith('application/json')) {
let reader = new FileReader();
reader.addEventListener("loadend", function() {
let data = JSON.parse(reader.result)
console.log(data);
});
reader.readAsText(res.data, "UTF-8") // 加UTF-8防止中文乱码
return
}
#2020/03/28 周六
#网页dark mode(深色模式)适配
微信最近推出了深色模式,我试了下,手机切换时页面效果样式是实时刷新的。于是就想着web怎么能够监听深色模式,并设置样式。查了资料后,在Stack Overflow上找到了答案
通过css里的媒体查询就能适配深色模式,先来看看怎么用js获取当前是否是深色模式
// 获取当前是否是深色模式
// window.matchMedia('(prefers-color-scheme: dark)').matches
window.matchMedia && console.log('Is dark mode: ', window.matchMedia('(prefers-color-scheme: dark)').matches)
// 用js监听深色模式的切换事件
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (event) => {
console.log('dark mode change,已' + (event.matches ? '进入': '退出') + 'dark mode')
})
window.matchMedia到底是用来做什么的?我查了下mdn,发现了这样一个示例
let mql = window.matchMedia('(max-width: 600px)');
document.querySelector(".mq-value").innerText = mql.matches;
从这个例子看,大概就知道怎么用css来支持dark模式了吧,就是加一个类似小屏适配的一个媒体查询样式,来看个例子
/* dark mode support */
@media (prefers-color-scheme: dark) {
body {
background-color: black;
color: #aaa;
}
body .content article, header, aside > div, footer {
border-color: #333;
color: #aaa;
background-color: black;
box-shadow: 0 0 10px #333;
}
}
深色模式下,一般将背景调暗,字体设置为偏白色即可。zuo11.com 已用上面的方法适配了深色模式,可以体验下。网站是开源的,zuo11.com深色模式支持代码 - github(opens new window)
参考:
- How do I detect dark mode using JavaScript? - Stack Overflow(opens new window)
- window.matchMedia | MDN(opens new window)
- Supporting Dark Mode in Your Interface | Apple Developer Documentation(opens new window)
#2020/03/27 周五
#canvas绘制模糊的问题
今天发现同样的代码在两台电脑上绘制的一个清晰,一个模糊,后来查资料发现确实有这个问题
因为canvas不是矢量图,高dpi屏幕每平方英寸有更多的像素,也就是两倍屏,浏览器会以两个像素点的宽度来渲染一个像素,所以在Retina屏上会导致图片、文字都会模糊,怎么解决呢?
获取设备像素比:window.devicePixelRatio || 1
如果绘制的实际区域大小为 750 * 40,假设设备像素比为2,那么,canvas的width、height需要设置为 1500 * 80,然后用内联样式设置width为750,height为40,相当于canvas绘制2倍的大小,然后再缩放,这样就清晰了。
综上,在canvas绘制时,各种长度一定要考虑乘以devicePixelRatio,不然可能显示的不清晰
参考:解决 canvas 在高清屏中绘制模糊的问题(opens new window)
#2020/03/26 周四
#canvas不支持文本换行怎么处理
今天在stackoveflow里面搜索ctx.fill的问题时,查到了很多关于canvas ctx.fillText()绘制文本时不支持换行的问题,找到了一个比较好的答案
I’m afraid it is a limitation of Canvas’ fillText. There is no multi-line support. Whats worse, there’s no built-in way to measure line height, only width, making doing it yourself even harder!
一般解决思路是,根据 ctx.measureText(‘Hello’).width 来看需要显示的文字是否需要换行,写一个for循环来处理
参考:
- canvas绘制文本内容自动换行(opens new window)
- javascript - HTML5 canvas ctx.fillText won’t do line breaks? - Stack Overflow(opens new window)
#canvas绘制不规则形状填充渐变色
在JS高程3中,有一章专门将使用canvas绘图,今天终于用上了,效果还不错,来看效果,原生js,70行不到
<canvas id="drawing1" width="720" height="45" >A draw of something.</canvas>
<script>
drawStatus('drawing1', 2)
function drawStatus(domId, position) {
let str = ['① 状态一', '② 状态二', '③ 状态三', '④ 状态四', '⑤ 状态五', '⑥ 状态六']
let config = {
width: 100,
height: 40,
extendLength: 20,
radius: 4
}
let config2 = { ...config, width: 110 }
let cur = str.length - position
str.reverse().forEach((item, index) => {
let pos = str.length - index - 1
let x = 0 + (str.length - 1) * config.radius
if (pos !== 0) {
x = (pos * 100) + (pos -1) * 10 + (str.length - 1 - pos) * config.radius
}
console.log(pos,x)
let curConfig = pos === 0 ? config : config2
if (pos < (str.length - cur)) {
curConfig.isFocus = true
}
drawUnnormalShape(domId, x , 0, str[index], curConfig)
})
}
function drawUnnormalShape(domId, x, y, text, config) {
let drawing = document.getElementById(domId);
let ctx = drawing.getContext('2d');
let { width, height, extendLength, radius, isFocus } = config
ctx.beginPath(); // 如果都需要重新beginPath 不然,后面的fill会覆盖前面的fill
// 不规则矩形
ctx.moveTo(x + radius, y) // 从左上角 (x + radius, y) 位置开始
ctx.arcTo(x, y, x, y + radius, radius) // 左上圆角
ctx.lineTo(x, y + height - 2 * radius) // 画左边
ctx.arcTo(x, y + height, x + radius, y + height, radius) // 左下圆角
ctx.lineTo(x + width - radius, y + height) // 下边
// ctx.arcTo(x + width - radius, y + height, x + width - radius, y + height - 1, 1) // 圆角
let extendEndX = x + width + extendLength
let middleHeight = y + height / 2
ctx.arcTo(extendEndX, middleHeight, extendEndX - radius, middleHeight - radius, radius) // 线 + 圆角
ctx.lineTo(x + width - radius, y)
ctx.lineTo(x + radius, y)
var gradient = ctx.createLinearGradient(x, y + height / 2, x + width + extendLength, y + height / 2); // 从(130,130)到(160,160)渐变
gradient.addColorStop(0, isFocus ? '#62ccff' : '#fff'); // 渐变的起点色
gradient.addColorStop(1, isFocus ? '#0486fe' : '#fff'); // 渐变的结束色
ctx.shadowOffsetX = 6;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 16; // 模糊像素
ctx.shadowColor = "rgba(58, 86, 111, 0.15)";
ctx.fillStyle = gradient
ctx.fill() // ctx.stroke()
let textArr = text.split(' ')
ctx.font = "15px arial"
ctx.fillStyle = isFocus ? '#fff' : '#ccc'
ctx.fillText(textArr[0], x + width / 2 - 20, y + height / 2 + 5)
ctx.font = "11px arial"
ctx.fillText(textArr[1], x + width / 2, y