Blob下载文件 & 模拟滚动条实现
1.vue切换路由视图时,事件钩子顺序是 当前模块create-->上一个模块beforeDestroy-->当前模块mounted
因此注册全局事件(比如给window注册事件)应放在mounted里,不然有可能被上一个模块的beforeDestroy移去
2.Ajax请求 后端直接返回二进制流数据(可能是excel、word文件等) 在前端让用户下载
用到Blob() 和 window.URL的api
1 var blob = new Blob([res.data], {type: "application/vnd.ms-excel"}); 2 var a = document.createElement('a'); 3 a.download = 'pickcenter_log.xlsx'; 4 a.href = window.URL.createObjectURL(blob); 5 document.body.appendChild(a); 6 a.click(); 7 window.URL.revokeObjectURL(a.href); 8 document.body.removeChild(a);
3. 模拟一个滚动条,可以让滚动条出现在任意位置、相对窗口固定
视口设置为overflow:hidden; 内容盒子设置为position:relative,通过定位来实现滚动效果
如果原生设置了overflow:scroll ,有滚动条时滚动了一定长度,再把overflow设为hidden,虽然滚动条消失了,但是scrollLeft(scrollTop)的影响还存在,会看到之前滚动到的区域,scrollTop置零之后可以归位
mousedown和mousemove事件里preventDefault可以防止拖拽时选中了文字
具名函数表达式(注意:非函数声明)只能在该回调函数内部被访问到,如fnmove,在slideStart里访问会报错未定义
参考:
FunctionDeclaration : function Identifier ( FormalParameterList opt ){ FunctionBody } FunctionExpression : function Identifier opt ( FormalParameterList opt ){ FunctionBody }
opt表示可有可无,所以函数表达式分为匿名函数和具名函数,所谓的"具名函数表达式"(Named function expressions,NFE),这个函数的识别名,它的作用域是只能在函数的主体(FunctionBody)内部。
原因当然它只是个原本就可有可无的"代理"函数名,真正的这函数识别名称是被赋值的那个变量识别名。
<template> <div class="scroll-bar" :name="name" v-show="show"> <div class="scroll-track" @click.self="moveThumb"> <div class="scroll-thumb" @mousedown.prevent="slideStart"></div> </div> </div> </template> <script> export default { // visibleWidth可视区域宽 scrollWidth内容总宽度 barWidth滚动条轨道长度 elementId视口容器 scrollElementId内容盒子 props:['name','visibleWidth','scrollWidth','barWidth','elementId', 'scrollElementId', 'show'], data () { return { scrollLeft:0, pos:null } }, mounted(){ var $scrollBar = $('.scroll-bar[name="'+ this.name +'"]'); var $track = $scrollBar.find('.scroll-track'); $track.width(this.barWidth || this.visibleWidth); }, watch:{ show(val){ val && ($('#' + this.elementId).get(0).scrollLeft = 0); }, // 内容宽度变化 scrollWidth(val){ this.reComputeAll({resetLeft:true}); }, //可视区域宽度会随窗口缩小放大而变化 visibleWidth(val){ this.reComputeAll({resetLeft:false}); } }, methods:{ reComputeAll(params){ var $scrollBar = $('.scroll-bar[name="'+ this.name +'"]'); var $track = $scrollBar.find('.scroll-track'); var $thumb = $scrollBar.find('.scroll-thumb'); var barWidth = this.barWidth || this.visibleWidth; var thumbWidth = parseInt(this.visibleWidth * barWidth / this.scrollWidth); var thumbLeft = parseInt(this.scrollLeft * barWidth / this.scrollWidth); if (params.resetLeft) { thumbLeft = 0; this.scrollLeft = 0; $('#' + this.scrollElementId).css('left', '0px'); } !this.barWidth && $track.width(barWidth); $thumb.width(thumbWidth); $thumb.css('left', thumbLeft + 'px'); }, reComputeRelative(thumbLeft){ var $scrollBar = $('.scroll-bar[name="'+ this.name +'"]'); var $thumb = $scrollBar.find('.scroll-thumb'); var $element = $('#' + this.scrollElementId); var barWidth = this.barWidth || this.visibleWidth; var thumbWidth = parseInt(this.visibleWidth * barWidth / this.scrollWidth); (thumbLeft < 0) && (thumbLeft = 0); (thumbLeft > barWidth - thumbWidth) && (thumbLeft = barWidth - thumbWidth); $thumb.css('left', thumbLeft + 'px'); this.scrollLeft = parseInt(thumbLeft * this.scrollWidth / barWidth); $element.css('left', -this.scrollLeft + 'px'); }, slideStart(event){ var self = this; var $scrollBar = $('.scroll-bar[name="'+ this.name +'"]'); var $thumb = $scrollBar.find('.scroll-thumb'); var disX = event.clientX; !this.pos && (this.pos = event.clientX); var othumbLeft = parseInt($thumb.css('left')); function fnmove (e){ var thumbScroll = e.clientX - disX; var thumbLeft = othumbLeft + thumbScroll; self.reComputeRelative(thumbLeft); } $(document).on('mousemove', fnmove); $(document).on('mouseup', function fnup(e){ $(document).off('mousemove', fnmove); $(document).off('mouseup', fnup); }); }, moveThumb(e){ if (this.pos === null) return; var thumbLeft = e.clientX - this.pos; this.reComputeRelative(thumbLeft); } } } </script> <style lang='less'> @import '../../assets/css/config.less'; .scroll-bar{ position:fixed; bottom:0px; left:220px; .scroll-track{ position:relative; height:20px; background-color: #f5f5f5; border-radius:10px; } .scroll-thumb{ position:absolute; height: 20px; border-radius: 10px; box-shadow: 0 0 6px rgba(0,0,0,.4); background-color: #e7e7e7; } } </style>
4.字符串中含有<script></script>标签时,</script>要对/转译,或者分开"</scri" + "pt>" 因为编译时会优先读取</script>然后当做脚本已结束
5.getBoundingClientRect() 获取可是区域的位置和几何属性
6.vue在子组件添加ref属性,通过父组件的$ref可以收集子组件的引用
7.html5中,想让html页面被缓存需要加入manifest属性,没有该属性的html页面不参与缓存协商,不受cache-control控制,会请求最新值