文件、blob
文件下载失败,将Blob对象转换为Json,处理异常错误?
捕获异常:
/** 导出文件流成功失败分别干干什么
* @param {String} res 文件流或者JSON对象(错误情况下)
* @param {Boolean} blob res资源是否是blob对象,文件流 默认不传递该参数
*
* */
export function downStreamCheck(res, blob) {
let result = {};
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = e => {
try {
result = JSON.parse(e.target.result);
} catch (e) {
// console.log(e)
} finally {
if (typeof result.code !== 'undefined') { // 返回错误对象
Message({
message: result.message,
type: 'error',
duration: 5 * 1000
});
} else {
resolve();
}
}
}
if (!blob) {
reader.readAsText(new Blob([res.data], {
type: 'application/octet-stream'
}));
} else {
reader.readAsText(res.data);
}
})
}
调用方式:
this.downStreamCheck(result).then(() => {
//导出文件成功后的操作
this.result=result;
})
问题地址:处理文件下载失败,如何将Blob对象转换为Json?
《参考:FileReader》
模拟a标签实现接口下载
如果返回的正常的文件流一般模拟a标签实现下载,如下:
/**
* @param {String} resource 文件流
* @param {String} fileType 文件类型
* @param {String} fileName 文件名 (可以响应头部读取文件名,如下)
* let resultFileName = res.headers['content-disposition'];
* let name = resultFileName.substring(resultFileName.indexOf('=')).substring(1);
* 使用方式 this.$downloadBlob(data,'application/octet-stream','download.zip');其中文件名可以从响应头截取
*
* */
export function downloadBlob(resource, fileType, fileName) {
var data = new Blob([resource], {
type: fileType
});
if ('download' in document.createElement('a')) { //非IE
var downloadUrl = window.URL.createObjectURL(data);
var anchor = document.createElement("a");
anchor.href = downloadUrl;
anchor.download = fileName;
anchor.style.display = 'none';
document.body.appendChild(anchor);
anchor.click();
window.URL.revokeObjectURL(anchor.href);
document.body.removeChild(anchor);
} else { //IE10+下载
navigator.msSaveBlob(data, fileName);
}
}
获取响应头部返回的文件名
一般下载的文件都需要从响应头部读取文件名,如下代码:
/** 从响应头部读取文件名称
* @param {res} response
* */
export function responseFileName(res) {
if (res && res.headers) {
let resultFileName = decodeURI(res.headers['content-disposition']);
return resultFileName.substring(resultFileName.indexOf('=')).substring(1);
}
return '';
}
上面三个函数一般综合起来一起使用,下面vue使用方式,代码把三个方法注册到了全局,如下:
packetDownload(params).then((res) => {
this.$downStreamCheck(res).then(() => {
let fileName = this.$responseFileName(res);
this.$downloadBlob(res.data,'application/octet-stream',fileName);
})
})
二进制转base64
// 二进制转base64
export function arraybufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return 'data:image/png;base64,' + window.btoa(binary);
}
base64转文件(file对象)
// base64转文件
export function base64toFile(dataurl, filename = "file") {
let arr = dataurl.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let suffix = mime.split('/')[1];
let bstr = window.atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], `${filename}.${suffix}`, {type: mime});
}
cookie、缓存、跨域通讯、XSS
设置二级域名cookie共享
也即是把cookie的domain设置为顶级域名。
function getdomain(){
var domain = document.domain;
var ip = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
if(ip.test(domain)){
return domain;
}else{
return document.domain.split('.').slice(1).join('.');
}
}
var firstDomainName = getdomain();
document.cookie="userid=888abc;domain="+firstDomainName+";path=/";
前端强制页面不缓存no-cache、no-store
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
日期相关
实现周的切换(上一周、下一周)
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<style>
.con{overflow: hidden;}
.same,#time{float:left;}
#time{
width: 260px;
text-align: center;
}
</style>
</head>
<body>
<div class="con">
<button class="same" >前一周</button>
<div ></div>
<button class="same" >下一周</button>
</div>
<script type="text/javascript" src="js/jquery-1.11.3.min.js"></script>
<script type="text/javascript">
var currentFirstDate;
var startTime = '';
var endTime = '';
function formatDate(date,joinStr){
if(joinStr) {
return date.getFullYear()+ joinStr + (date.getMonth()+1)+ joinStr + date.getDate();
} else {
return date.getFullYear()+'年' + (date.getMonth()+1)+'月' + date.getDate()+'日';
}
}
function addDate(date,n) {
date.setDate(date.getDate()+n);
return date;
}
function setDate(date) {
var week = date.getDay()-1;
date = addDate(date,week*-1);
currentFirstDate = new Date(date);
var str = formatDate(date) + '-' + formatDate(addDate(date,6));
startTime = formatDate(addDate(date,-6),'-');
endTime = formatDate(addDate(date,6),'-');
$('#time').html(str);
}
function ajaxlist() {
}
$(function() {
setDate(new Date());
ajaxlist();
$('#last-week').on('click',function() {
setDate(addDate(currentFirstDate,-7));
// 接口请求
ajaxlist();
})
$('#next-week').on('click',function() {
setDate(addDate(currentFirstDate,7));
// 接口请求
ajaxlist();
})
})
</script>
</body>
</html>
事件
通过事件捕获实现登录拦截思路demo
document.addEventListener('click',function(event){
if(event.target.tagName.toLowerCase() == 'a') {
// 在此阶段可以判断是否登录,未登录进行阻止捕获
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
},true);
HTML5相关
canvas绘制文本内容自动换行
/** canvas中的文字字段断行
* @param {String} textContent 绘制的文本内容
* @param {Number} textMaxWidth 每行文本的最大宽度
* @param {Number} drawX 绘制文本的x坐标
* @param {Number} drawY 绘制文本的y坐标
* @param {Number} lineHeight 文本之间的行高
* @param {Number} lineNum 最多绘制的行数 超过设置的行数..展示, 不设置此参数自动往下断行
*
* */
function textBrokenLine(textContent,textMaxWidth,drawX,drawY,lineHeight,lineNum) {
// 创建canvas
var canvas = document.createElement('canvas');
canvas.id = 'canvas';
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');
ctx.font = "14px 微软雅黑";
ctx.fillStyle = 'black';
if(ctx.measureText(textContent).width <= textMaxWidth) {
ctx.fillText(textContent,drawX,drawY);
} else {
var drawTxt = ''; // 当前绘制的内容
var drawIndex = 0; // 当前绘制内容的索引
var drawLine = 1; // 第几行开始绘制
for(var i = 0; i < textContent.length; i++) {
drawTxt += textContent[i];
if(ctx.measureText(drawTxt).width >= textMaxWidth) {
if(lineNum) { // 有最多展示几行的参数进行特殊处理
if (drawLine >= lineNum) {
ctx.fillText(textContent.substring(drawIndex, i) + '..', drawX, drawY);
break;
} else {
ctx.fillText(textContent.substring(drawIndex, i + 1), drawX, drawY);
drawIndex = i + 1;
drawLine += 1;
drawY += lineHeight;
drawTxt = '';
}
} else {
ctx.fillText(textContent.substring(drawIndex, i + 1), drawX, drawY);
drawIndex = i + 1;
drawY += lineHeight;
drawTxt = '';
}
} else {
// 内容绘制完毕,但是剩下的内容宽度不到textMaxWidth
if (i === textContent.length - 1) {
ctx.fillText(textContent.substring(drawIndex),drawX,drawY);
}
}
}
}
// 获取canvas转化结果base64
var canvasDom = document.getElementById("canvas");
canvasDom.style.border = "red 1px solid";
var base64 = canvasDom.toDataURL("image/png");
console.log(base64);
// canvasDom.parentNode.removeChild(canvasDom);
}
// 调用
textBrokenLine('这是用户输入的一段文字,这是用户输入的一段文字,这是用户输入的一段文字',100,0,20,20);
其它
获取IE浏览器版本
function IEVersion(){
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
if(isIE) {
userAgent.match(/MSIE (\d+\.\d+);/g);
var fIEVersion = parseFloat(RegExp["$1"]);
if(fIEVersion == 7) {
return 7;
} else if(fIEVersion == 8) {
return 8;
} else if(fIEVersion == 9) {
return 9;
} else if(fIEVersion == 10) {
return 10;
} else {
return 6;//IE版本<=7
}
} else if(isEdge) {
return 'edge';//edge
} else if(isIE11) {
return 11; //IE11
}else{
return -1;//不是ie浏览器
}
}
JS跳转到app store内应用下载页面
跳转到应用商店:
(https)|(itms-apps)://itunes.apple.com/app/id{appID}
跳转到撰写评价:
(https)|(itms-apps)://itunes.apple.com/app/id{appID}?action=write-review
跳转到查看评价:
(https)|(itms-apps)://itunes.apple.com/app/viewContentsUserReviews?id={appID}
手机端和pc端均可适用。
示例代码:
window.location.href = 'itms-apps://itunes.apple.com/app/id414478124?action=write-review'
h5 JS判断是安卓还是ios设备,跳转到对应的下载地址
;(function(){
var u = navigator.userAgent;
var ua = navigator.userAgent.toLowerCase();
var dom = document.getElementById('btn');
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if(ua.match(/MicroMessenger/i)=="micromessenger") { //微信内置浏览器
dom.addEventListener('touchstart', function (event) {
},false);
}else{
if(isiOS){
dom.addEventListener('touchstart', function (event) {
//跳转到ios下载地址(示例:微信app)
window.location.href='itms-apps://itunes.apple.com/app/id414478124';
},false);
}
else if(isAndroid){
dom.addEventListener('touchstart', function (event) {
window.location.href='http://www.XXX.com/apk/demo.apk';
},false);
}else{ //PC 端
dom.addEventListener('click',function(){
//跳转到andriod下载地址
window.location.href='http://www.XXX.com/apk/demo.apk';
},false);
}
}
})();
pdf.js官网基本代码demo笔记
// atob() is used to convert base64 encoded PDF to binary-like data.
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
// Base64_encoding_and_decoding.)
var pdfData = atob(
'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
// Loaded via <script> tag, create shortcut to access PDF.js exports.
var pdfjsLib = window['pdfjs-dist/build/pdf'];
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.js';
// Using DocumentInitParameters object to load binary data.
var loadingTask = pdfjsLib.getDocument({data: pdfData});
loadingTask.promise.then(function(pdf) {
console.log('PDF loaded');
// Fetch the first page
var pageNumber = 1;
pdf.getPage(pageNumber).then(function(page) {
console.log('Page loaded');
var scale = 1.5;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.then(function () {
console.log('Page rendered');
});
});
}, function (reason) {
// PDF loading error
console.error(reason);
});
判断移动端、ipad设备
try {
if(/Android|Windows Phone|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
window.location.href = "https://pc.com/";
} else if(/iPad/i.test(navigator.userAgent)) {
window.location.href = "https://pad.com/"
}
} catch(e) {}
使用Nginx的Rewrite匹配特殊符号并替换再重定向
rewrite ^(.*)/rewriteSystem/(.*)$ $1/#/$2 redirect;
详细可参考《Nginx中的Rewrite的重定向配置与实践》
苹果手机 微信调用百度地图Javascript API 频繁闪退问题
最近在网页中调用百度地图API js大众版,但是在IOS8系统中,缩放的时候频繁闪退,安卓手机没有这个问题!
在网上查询了下,有网友回答说不要频繁的去new marker,而是初始化话一定量的marker,然后setPosition。但是我的页面中匹配当前城市 注入marker也没有几个,所以排除这答案。
最后发现有网友说版本不稳定引起的,于是把百度地图API回退到了1.5,结果还真是可以了。
百度地图API调用:
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.5&ak=dGg7NKEkMCp8j1pWHCHZ3nhk"></script>
使用webpack打包自己的library类库,怎样忽略eslint语法检测
在打包的时候在类库js最前面添加/* eslint-disable */忽略检测的语法,在配置文件中实现一个简单的类:
class ignoreEslintPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.emit.tap('ignoreEslintPlugin', (compilation) => {
var topInfo = '/* eslint-disable */\n';
for(let i in compilation.assets) {
if(i.lastIndexOf('.js') != -1 && i.lastIndexOf('.json') == -1) {
let content = topInfo + compilation.assets[i].source();
compilation.assets[i] = {
source: () => content,
size: () => content.length
}
}
}
})
}
}
调用:
plugins: [
new ignoreEslintPlugin()
]