FEBASEWEB组件包容性设计手册

前言包容性设计这个术语并不是一个新概念。这是自2005年以来一直存在的一个短语。它被定义为“尽可能多的人可以访问和使用的主流产品/服务的设计,而不需要特殊的适应或专门的设计“。 当我们重新思考我们的开发方法时,我们不仅仅是访问信息的基础级别。包容性发展意味着为尽可能多的人创造有价值的东西,而不仅仅是可以获得的东西。它将可访问性放在首位。 海登·皮克林(Heydon Pickering)用他的“ 包容性设计模式 ”(Inclusive Design Patterns)中的这句话总结了它: 通过选择我们认为普通用户可以阅读的字体,我们会有意识地疏远我们的一部分用户。相反,通过选择适合那些努力阅读的人的字体,我们得出了一个适合每个人的选择。这是一种高效,有效的包容性设计。可以简单的认为:组件包容性设计 = 可访问性第一 + 组件驱动开发 包容性设计是一种设计过程,还有很多的设计过程,没有对错,按需选择。 还有,现实点。“100%可访问性”是一个无法实现的理想-你总是会遇到某种边缘情况,导致某个用户发现某些内容难以使用-但你应该尽你所能去做。如果您计划包含一个使用WebGL制作的时髦的3D饼图,您可能希望包括一个数据表,作为数据的可访问的替代表示。或者,您可能只需要包含表并去掉3D饼图-每个人都可以访问该表,编写代码更快,CPU密集型更少,维护也更容易。另一方面,如果你正在一个展示有趣的3D艺术的画廊网站上工作,那么期望每一件艺术品都能被视障人士完全访问是不合理的,因为它是一种完全的视觉媒介。 面向用户设计 ( 上图为用户金字塔模型 & 包容性设计立方体模型 ) 设计过程名词解释: 通用/共用性设计 (universal design)用户金字塔模型自下而上,以关注主流健全用户为前提,力求提升设计对于特殊用户群体的适用。 无障碍设计 (barrier-free design)用户金字塔模型自上而下,以满足极端用户(金字塔顶端)的需求为首要任务,再拓展至主流用户群体。 包容性设计 (inclusive design)力图充分认识用户群体多样性,在设计的过程和结果中减少对用户产生无意识的排除。 WEB中的无障碍访问 视觉无障碍设计 确保文字、可交互控件和背景的对比度,满足最低标准。别只用颜色传达信息,让文字字号可调。确保界面上所有的控件都可借助辅助技术使用,如屏幕阅读器,放大镜和盲文显示器。 这就意味着必须让 accessibility APIs 可以通过程序确定每个控件的角色、状态、价值、标题。听觉无障碍设计「听觉障碍」包括:听不清/听不到到界面发出的声音。 让文本内容容易被理解,适当使用「文字替代」确保界面上的所有空间,在没有声音时,仍可正常使用。行动无障碍设计 确保所有界面控件交互都可只通过键盘完成或者只使用鼠标;确保界面控件被辅助技术正确标记;这些用户可能会使用诸如语音控制软件和物理切换控制等技术,这些技术一般使用与屏幕阅读器等其他辅助技术相同的API。认知无障碍设计「认知障碍」意味着用户可能需要辅助技术来帮助他们阅读文本,因此文本替代方案的存在非常必要。 避免重复或闪烁的显示方式,因为这可能会为认知障碍用户造成使用不便;给用户留出充足的时间操作。WEB中的可访问性 原生控件具有辅助交互,尽可能美化他们而不是造轮子(新元素上添加ARIA)没有aria比错误的aria更好 aria role表明交互承诺,不提供键盘行为或样式aria 可以隐藏装饰元素也可以增强/覆盖语义深入了解ARIA ARIA 规范介绍了 role 属性以及可与这些角色联用的关联 ARIA 属性的可接受值。 ARIA 制作实践文档探究了使用可用 ARIA 角色和属性的最佳做法。可访问性反模式与误区 暗黑模式滥用导致的暗黑模式(DARK PATTERN)包括: 伪装或插入内容的广告等模式使用误导或技巧问题诱骗用户做某事迫使用户披露个人信息(例如连接到社交网络)以执行基本任务阻止用户继续使用覆盖屏幕的东西迷之信噪比在网页设计中,信号是内容,噪音是内容周围的铬或额外项目。在设计时,目标是尽可能提高信噪比(信号很多,噪音很小)。 过时的UX模式UX模式过多,若不适合用户或业务,应停止使用。以下列表并不全面,但应作为指南来确定是否应更新正在使用的模式:轮播图;大背景图像;悬停状态以获取附加信息;无线嵌套菜单;悬停的回到顶部底部;折叠面板和标签;后退按钮;页面预加载器;社交分享和登录;内容分页;自动播放多媒体;非用户触发操作;无线分页;缺少导航路径;无法接受的合并功能; 可访问性的误区1. 我的用户中只有一小部分需要无障碍访问。 然而有些例外: 老年人 - 可能需要在视频或更大的字体大小上添加字幕才能阅读文本母语或母语不是英语的用户 - 可能需要更多时间阅读自动旋转幻灯片上的文本具有认知限制的用户 - 可能需要易于访问的字体或项目符号内容以帮助您集中注意力视力有限或视力不佳的用户 - 可能需要放大内容才能阅读和理解内容具有情境障碍的用户 - 可能需要更好的色彩对比度,因此屏幕上的眩光不会干扰他们阅读内容有临时残疾的用户 - 可能需要仅使用键盘访问所有内容,因为他们无法使用鼠标2. 使我们的网站或应用程序可访问需要花费太多时间/精力/金钱 ...

June 10, 2019 · 16 min · jiezi

带着canvas去流浪3绘制饼图

示例代码托管在:http://www.github.com/dashnowords/blogs博客园地址:《大史住在大前端》原创博文目录 华为云社区地址:【你要的前端打怪升级指南】 [TOC] 一. 任务说明使用原生canvasAPI绘制饼图(南丁格尔玫瑰)。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。 二. 重点提示南丁格尔玫瑰图的画法有很多种,Echarts中提供的以半径或面积两种不同模式,本文中以面积比例画法为例,绘制算法如下: 确定每个扇区的角度。由于所有扇区的角度加在一起为2 ,我们先按照数据比例来计算角度: $$_i = \frac{data_i}{\sum_{i=0}^ndata_i}*2\pi$$ 每个扇区面积与总面积之间的比例即为数值的比,将给定参数数组options.radius中的最大和最小数值作为数值最大的一块扇形的绘图数据,代入如下公式即可求得总面积S:$$\frac{\pi(R_{i}^2 - R_{min}^2)*_{i}/2\pi}{S} = \frac{data_i}{data_{sum}}$$ 再利用上述公式分别计算出每个扇形对应的外圆半径,在canvas中绘制路径并填充即可。三. 示例代码南丁格尔玫瑰图绘制示例代码: //绘制饼图drawPieChart(options); /** * 绘制饼图 * @param {[type]} options [description] * @return {[type]} [description] */function drawPieChart(options) { //记录最大数值以反求面积总和 options.maxValue = 0; //求数据集总和以在后续计算每个扇形的角度比例 options.totalNum = options.data.reduce((pre,cur)=>{ if (cur.value > options.maxValue) { options.maxValue = cur.value; } return pre+cur.value; },0); /*以最大值对应最大半径来计算面积总和,并覆盖原值 *使得最大的一块扇形外圆半径为options.radius[0] *内圆半径为options.radius[1] */ let Rmin = options.radius[0]; let Rmax = options.radius[1]; let r = Math.sqrt((Rmax*Rmax - Rmin*Rmin)*options.totalNum / options.maxValue + Rmin*Rmin); options.radius[1] = r; //移动坐标系原点至绘图中心 let paintingCenter={ x:parseInt(options.center[0],10)/100 * (options.chartZone[2] - options.chartZone[0]) + options.chartZone[0], y:parseInt(options.center[1],10)/100 * (options.chartZone[3] - options.chartZone[1]) + options.chartZone[1] } context.translate(paintingCenter.x, paintingCenter.y); //绘制每个扇形,过程中累加旋转角度 let allAngle = options.data.reduce((prev,cur,index)=>{ context.fillStyle = options.colorPool[index] let angle = calcPaintingData(cur,options); return prev + angle; },0); //绘制中空白色圆 context.beginPath(); context.fillStyle = 'white'; context.arc(0,0,options.radius[0],0,2*Math.PI,false); context.fill();}/** * 计算每个扇形所需要的绘图参数 */function calcPaintingData(data,options) { let scale = data.value / options.totalNum; let angle = scale * 2 * Math.PI; let Rmin = options.radius[0]; let Rmax = options.radius[1]; let r = Math.sqrt(scale * (Rmax*Rmax - Rmin*Rmin) + Rmin*Rmin); data.r = r; //绘制扇形 paintFan({ r:r, angle:angle, data:data, options:options }); return angle;//将角度值返回给外层函数以供累加}//绘制扇形function paintFan(opt) { context.beginPath(); context.lineTo(opt.r,0); context.arc(0,0,opt.r,0,opt.angle,false); context.lineTo(0,0); context.closePath(); context.fill(); context.rotate(opt.angle);}浏览器中可查看效果: ...

June 9, 2019 · 1 min · jiezi

Nodejs运行原理高并发性能测试对比及生态圈汇总-全栈工程师入门

Node.js是从纯前端走向更高阶层的前端,以及全栈工程师的唯一快速途径简单的说Node.js 就是运行在服务端的 JavaScriptNode.js 是一个基于Chrome JavaScript 运行时建立的一个平台Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好如果你是一个前端程序员,你不懂得像PHP、Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择Node.js 是运行在服务端的 JavaScript,如果你熟悉Javascript,那么你将会很容易的学会Node.js当然,如果你是后端程序员,想部署一些高性能的服务,那么学习Node.js也是一个非常好的选择Node.JS适合运用在高并发、I/O密集、少量业务逻辑的场景Node.js的模块组成如下: Node.js的运行机制V8引擎解析JavaScript脚本解析后的代码,调用Node APIlibuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个EventLoop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。V8引擎再将结果返回给用户。事件循环(Event Loop)Nodejs 执行之后会初始化一个事件循环,执行代码程序(这些程序可能会造成异步调用、定时器或者process.nextTick()),然后开始执行事件循环。事件循环的执行循序: 上边的每一个模块都是事件循环的一个阶段,每个阶段都有一个要执行的回调的FIFO队列。虽然每个阶段都不同,一般来说,当事件执行到一个阶段,先执行这个阶段特有的操作,然后操作这个阶段的队列,当队列执行完或者达到了回调上限,事件循环就会执行下一个阶段。各个阶段执行的任务如下: timers 阶段: 这个阶段执行setTimeout和setInterval预定的callback;I/O callbacks 阶段: 执行除了close事件的callbacks、被timers设定的callbacks、setImmediate()设定的callbacks这些之外的callbacks;idle, prepare 阶段: 仅node内部使用;poll 阶段: 获取新的I/O事件, 适当的条件下node将阻塞在这里;check 阶段: 执行setImmediate() 设定的callbacks;close callbacks 阶段: 执行socket.on('close', ...)这些 callbackprocess.nextTick()不属于上面的任何一个phase,它在每个phase结束的时候都会运行。也可以认为,nextTick在下一个异步方法的事件回调函数调用前执行。TIPS: Node.js中的事件循环机制不会掉头,只会由上往下,循环执行。完整的一次执行机制可以这样描述 在Node.js中,绝大部分API都是异步的,有一个很形象的故事描述了JAVA和Node.js的区别,JAVA是一个餐厅100个服务员对应100客户,Node.js是一个服务员玩命干,也对应100个客户,上菜的速度很大一部分取决于厨师的做菜速度Node.js的单线程并不是真正的单线程,只是开启了单个线程进行业务处理(cpu的运算),同时开启了其他线程专门处理I/O。当一个指令到达主线程,主线程发现有I/O之后,直接把这个事件传给I/O线程,不会等待I/O结束后,再去处理下面的业务,而是拿到一个状态后立即往下走,这就是“单线程”、“异步I/O”。I/O操作完之后呢?Node.js的I/O 处理完之后会有一个回调事件,这个事件会放在一个事件处理队列里头,在进程启动时node会创建一个类似于While(true)的循环,它的每一次轮询都会去查看是否有事件需要处理,是否有事件关联的回调函数需要处理,如果有就处理,然后加入下一个轮询,如果没有就退出进程,这就是所谓的“事件驱动”。这也从Node的角度解释了什么是”事件驱动”。在node.js中,事件主要来源于网络请求,文件I/O等,根据事件的不同对观察者进行了分类,有文件I/O观察者,网络I/O观察者。事件驱动是一个典型的生产者/消费者模型,请求到达观察者那里,事件循环从观察者进行消费,主线程就可以马不停蹄的只关注业务不用再去进行I/O等待。 优点: Node 公开宣称的目标是 “旨在提供一种简单的构建可伸缩网络程序的方法”。我们来看一个简单的例子,在 Java和 PHP 这类语言中,每个连接都会生成一个新线程,每个新线程可能需要2MB的配套内存。在一个拥有8GBRAM的系统上,理论上最大的并发连接数量是4,000个用户。随着您的客户群的增长,如果希望您的Web应用程序支持更多用户,那么,您必须添加更多服务器。所以在传统的后台开发中,整个Web应用程序架构(包括流量、处理器速度和内存速度)中的瓶颈是:服务器能够处理的并发连接的最大数量。这个不同的架构承载的并发数量是不一致的。而Node的出现就是为了解决这个问题:更改连接到服务器的方式。在Node 声称它不允许使用锁,它不会直接阻塞 I/O 调用。Node在每个连接发射一个在 Node 引擎的进程中运行的事件,而不是为每个连接生成一个新的 OS 线程(并为其分配一些配套内存)。缺点:如上所述,nodejs的机制是单线程,这个线程里面,有一个事件循环机制,处理所有的请求。在事件处理过程中,它会智能地将一些涉及到IO、网络通信等耗时比较长的操作,交由worker-threads去执行,执行完了再回调,这就是所谓的异步IO非阻塞吧。但是,那些非IO操作,只用CPU计算的操作,它就自己扛了,比如算什么斐波那契数列之类。它是单线程,这些自己扛的任务要一个接着一个地完成,前面那个没完成,后面的只能干等。因此,对CPU要求比较高的CPU密集型任务多的话,就有可能会造成号称高性能,适合高并发的node.js服务器反应缓慢。Node.js高并发使用Nginx+pm2,pm2中可以开启多线程负载均衡,模式分两种:pm2简介: PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。下面就对PM2进行入门性的介绍,基本涵盖了PM2的常用的功能和配置。 fork模式,单实例多进程,常用于多语言混编,比如php、python等,不支持端口复用,需要自己做应用的端口分配和负载均衡的子进程业务代码。缺点就是单服务器实例容易由于异常会导致服务器实例崩溃。 cluster模式,多实例多进程,但是只支持node,端口可以复用,不需要额外的端口配置,0代码实现负载均衡。优点就是由于多实例机制,可以保证服务器的容错性,就算出现异常也不会使多个服务器实例同时崩溃。 共同点,由于都是多进程,都需要消息机制或数据持久化来实现数据共享。pm2部署,默认开启负载均衡:npm i pm2 -g $ pm2 start app.js # 启动app.js应用程序$ pm2 start app.js -i 4 # cluster mode 模式启动4个app.js的应用实例 # 4个应用程序会自动进行负载均衡 pm2 start app.js -i max 根据你的cpu数量最大化启动多线程进行负载均衡如果要停止所有应用,可以pm2 stop all查看进程状态 pm2 listpm2真心很好很强大,可以在线热更新代码,更多的指令需要上官网看pm2和Nginx配合pm2 + nginx无非就是在nginx上做个反向代理配置,直接贴配置。 upstream my_nodejs_upstream { server 127.0.0.1:3001;}server { listen 80;server_name my_nodejs_server;root /home/www/project_root; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";proxy_max_temp_file_size 0; proxy_pass http://my_nodejs_upstream/;proxy_redirect off; proxy_read_timeout 240s; } 特别说明,我们不建议使用Node.js作为底层服务器,更多时候作为中间件和接入层使用,例如Electron开发跨平台应用Nginx开启多线程,负载均衡负载均衡的作用负载均衡:分摊到多个操作单元上进行执行,和它的英文名称很匹配。就是我们需要一个调度者,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡。负载均衡这里面涉及的东西相对也是比较多的,理论就不说太多了,网上,书上很多,今天我们就利用Nginx服务器来实现一个简单的负载均衡负载均衡算法源地址哈希法:根据获取客户端的IP地址,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。轮询法:将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。随机法:通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问。加权轮询法:不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。加权随机法:与加权轮询法一样,加权随机法也根据后端机器的配置,系统的负载分配不同的权重。不同的是,它是按照权重随机请求后端服务器,而非顺序。最小连接数法:由于后端服务器的配置不尽相同,对于请求的处理有快有慢,最小连接数法根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。下载Nginx,找到config文件夹下面的nginx.conf,修改下面配置文件每个upstream test{ server 11.22.333.11:6666 weight=1; server 11.22.333.22:8888 down; server 11.22.333.33:8888 backup; server 11.22.333.44:5555 weight=2; }//down 表示单前的server临时不參与负载.//weight 默觉得1.weight越大,负载的权重就越大//backup: 其他全部的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻 nginx命令汇总 :nginx 服务器重启命令,关闭nginx -s reload :修改配置后重新加载生效nginx -s reopen :重新打开日志文件nginx -t -c /path/to/nginx.conf 测试nginx配置文件是否正确关闭nginx:nginx -s stop :快速停止nginxquit :完整有序的停止nginx其他的停止nginx 方式:ps -ef | grep nginxkill -QUIT 主进程号 :从容停止Nginxkill -TERM 主进程号 :快速停止Nginxpkill -9 nginx :强制停止Nginx 启动nginx:nginx -c /path/to/nginx.conf平滑重启nginx:kill -HUP 主进程号在开启Nginx多线程负载均衡和部署pm2负载均衡后的架构图:第一种,Node.js作为底层服务器,直接操作数据库的方式: ...

June 9, 2019 · 2 min · jiezi

h5视频播放

<video class="ss" type="video/mp4" src="https://ksv-video-publish.cdn...; ></video> <div class="ctl"> <input type="button" value="播放" /> <input type="button" value="快进*1" /> <input type="button" value="静音" /> </div><script> var vd = document.querySelector("video") var btns =document.querySelectorAll(".ctl input") btns[0].onclick = function (){ if(vd.paused){ vd.play(); this.value = "暂停" }else{ vd.pause() this.value = "播放" } } btns[1].onclick = function (){ if(vd.playbackRate >=8){ vd.playbackRate =1 }else{ vd.playbackRate *=2 } this.value = "快进(X"+vd.playbackRate+")"; } btns[2].onclick = function (){ vd.muted = !vd.muted; this.value = vd.muted ? "取消静音" : "静音" } </script>

June 9, 2019 · 1 min · jiezi

WEB组件包容性设计手册

前言包容性设计这个术语并不是一个新概念。这是自2005年以来一直存在的一个短语。它被定义为“尽可能多的人可以访问和使用的主流产品/服务的设计,而不需要特殊的适应或专门的设计“。 当我们重新思考我们的开发方法时,我们不仅仅是访问信息的基础级别。包容性发展意味着为尽可能多的人创造有价值的东西,而不仅仅是可以获得的东西。它将可访问性放在首位。 海登·皮克林(Heydon Pickering)用他的“ 包容性设计模式 ”(Inclusive Design Patterns)中的这句话总结了它: 通过选择我们认为普通用户可以阅读的字体,我们会有意识地疏远我们的一部分用户。相反,通过选择适合那些努力阅读的人的字体,我们得出了一个适合每个人的选择。这是一种高效,有效的包容性设计。可以简单的认为:组件包容性设计 = 可访问性第一 + 组件驱动开发 包容性设计是一种设计过程,还有很多的设计过程,没有对错,按需选择。 还有,现实点。“100%可访问性”是一个无法实现的理想-你总是会遇到某种边缘情况,导致某个用户发现某些内容难以使用-但你应该尽你所能去做。如果您计划包含一个使用WebGL制作的时髦的3D饼图,您可能希望包括一个数据表,作为数据的可访问的替代表示。或者,您可能只需要包含表并去掉3D饼图-每个人都可以访问该表,编写代码更快,CPU密集型更少,维护也更容易。另一方面,如果你正在一个展示有趣的3D艺术的画廊网站上工作,那么期望每一件艺术品都能被视障人士完全访问是不合理的,因为它是一种完全的视觉媒介。 面向用户设计 ( 上图为用户金字塔模型 & 包容性设计立方体模型 ) 设计过程名词解释: 通用/共用性设计 (universal design)用户金字塔模型自下而上,以关注主流健全用户为前提,力求提升设计对于特殊用户群体的适用。 无障碍设计 (barrier-free design)用户金字塔模型自上而下,以满足极端用户(金字塔顶端)的需求为首要任务,再拓展至主流用户群体。 包容性设计 (inclusive design)力图充分认识用户群体多样性,在设计的过程和结果中减少对用户产生无意识的排除。 WEB中的无障碍访问 视觉无障碍设计 确保文字、可交互控件和背景的对比度,满足最低标准。别只用颜色传达信息,让文字字号可调。确保界面上所有的控件都可借助辅助技术使用,如屏幕阅读器,放大镜和盲文显示器。 这就意味着必须让 accessibility APIs 可以通过程序确定每个控件的角色、状态、价值、标题。听觉无障碍设计「听觉障碍」包括:听不清/听不到到界面发出的声音。 让文本内容容易被理解,适当使用「文字替代」确保界面上的所有空间,在没有声音时,仍可正常使用。行动无障碍设计 确保所有界面控件交互都可只通过键盘完成或者只使用鼠标;确保界面控件被辅助技术正确标记;这些用户可能会使用诸如语音控制软件和物理切换控制等技术,这些技术一般使用与屏幕阅读器等其他辅助技术相同的API。认知无障碍设计「认知障碍」意味着用户可能需要辅助技术来帮助他们阅读文本,因此文本替代方案的存在非常必要。 避免重复或闪烁的显示方式,因为这可能会为认知障碍用户造成使用不便;给用户留出充足的时间操作。WEB中的可访问性 原生控件具有辅助交互,尽可能美化他们而不是造轮子(新元素上添加ARIA)没有aria比错误的aria更好 aria role表明交互承诺,不提供键盘行为或样式aria 可以隐藏装饰元素也可以增强/覆盖语义深入了解ARIA ARIA 规范介绍了 role 属性以及可与这些角色联用的关联 ARIA 属性的可接受值。 ARIA 制作实践文档探究了使用可用 ARIA 角色和属性的最佳做法。可访问性反模式与误区 暗黑模式滥用导致的暗黑模式(DARK PATTERN)包括: 伪装或插入内容的广告等模式使用误导或技巧问题诱骗用户做某事迫使用户披露个人信息(例如连接到社交网络)以执行基本任务阻止用户继续使用覆盖屏幕的东西迷之信噪比在网页设计中,信号是内容,噪音是内容周围的铬或额外项目。在设计时,目标是尽可能提高信噪比(信号很多,噪音很小)。 过时的UX模式UX模式过多,若不适合用户或业务,应停止使用。以下列表并不全面,但应作为指南来确定是否应更新正在使用的模式:轮播图;大背景图像;悬停状态以获取附加信息;无线嵌套菜单;悬停的回到顶部底部;折叠面板和标签;后退按钮;页面预加载器;社交分享和登录;内容分页;自动播放多媒体;非用户触发操作;无线分页;缺少导航路径;无法接受的合并功能; 可访问性的误区1. 我的用户中只有一小部分需要无障碍访问。 然而有些例外: 老年人 - 可能需要在视频或更大的字体大小上添加字幕才能阅读文本母语或母语不是英语的用户 - 可能需要更多时间阅读自动旋转幻灯片上的文本具有认知限制的用户 - 可能需要易于访问的字体或项目符号内容以帮助您集中注意力视力有限或视力不佳的用户 - 可能需要放大内容才能阅读和理解内容具有情境障碍的用户 - 可能需要更好的色彩对比度,因此屏幕上的眩光不会干扰他们阅读内容有临时残疾的用户 - 可能需要仅使用键盘访问所有内容,因为他们无法使用鼠标2. 使我们的网站或应用程序可访问需要花费太多时间/精力/金钱 ...

June 8, 2019 · 16 min · jiezi

jQuery源码解析之你并不真的懂事件委托及target和currenttarget的区别

前言:请先回顾下我之前写的一篇文章:JavaScript之事件委托 一、事件委托(委派)含义:在#A上绑定click事件,但是让#B触发click事件,相当于在 #B 上假绑定了 click 事件 也就是说:#B 委托了 click 事件给了 #A(在 #A 上绑定) 举例: <div id="A" style="background-color: deeppink"> 这是A <div id="B" style="background-color: bisque"> 这是B <div id="C" style="background-color: aqua"> 这是C </div> <div id="D" style="background-color: blueviolet"> 这是D </div> </div></div> //在父元素上绑定click事件,但只能由子元素触发父元素上绑定的事件 $("#A").on("click" ,"#B",function (e) { console.log("点击了B,即B委托A的click事件被点击了") }) $("#A").on("click" ,"#C",function (e) { console.log(e,"点击了C,即C委托A的click事件被点击了") })二、jQuery 的事件委托顺序: 举例: (1)A、B、C 各自绑定了click事件 $("#A").on("click" ,function () { console.log("A被点击了") }) $("#B").on("click" ,function () { console.log("B被点击了") }) $("#C").on("click",function () { console.log("C被点击了") })点击 C,会依次执行 C、B、A 的click事件 ...

June 8, 2019 · 5 min · jiezi

跨域

前端跨域问题我想很多同学遇到过,或者是刚刚请求数据成功, 然而转眼之后就会报错XMLHttpRequest cannot load http://www.server.com/server.... No 'Access-Control-Allow-Origin' header is present on the requested resource.Origin 'http://www.client.com' is therefore not allowed access.我不知道大家有没有遇到过反正我是遇到过,不管在什么时候你都有可能遇到跨域跨域是什么?跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。为什么会产生跨域?产生跨域的主要原因是因为同源策略,什么是同源策略呢?我们来看下面的解释同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源,看看下面的产生跨域的场景你就会明白同源策略的含义。那么有的人会问了,同源策略会产生跨域为什么还要存在呢?平常我们访问网站的时候都是一个地址对应相同的内容,如果同源策略不存在网站的dom很有可能被钓鱼网站复制,那样你就会上当。那有的人又问了有了同源策略就安全吗?不是有了它就安全是因为同源策略是基础的安全机制,面对强大的攻击还是需要强大的攻防的 跨域场景url说明是否可以通信http://www.kuayu.com/img.jpg同一域名,不同文件,不同路径可以http://www.kuayu.com/img2.jpg同一域名,不同文件,不同路径可以url说明是否可以通信http://www.kuayu.com:6666/img.jpg同一域名,不同端口不可以http://www.kuayu.com/img2.jpg同一域名,不同端口不可以url说明是否可以通信https://www.kuayu.com/img.jpg同一域名,不同协议不可以url说明是否可以通信http://www.kuayu.com/img.jpg主域相同,子域不同不可以http://kuayu11.com/img2.jpg主域相同,子域不同不可以跨域的解决办法jsonp Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为同源策略。同源策略,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript的浏览器都会使用这个策略。同源策略上面咱们已经简单的价绍过了,详细请看上面首先我们先设置script标签,一个简单的jsonp实现,其实就是拼接url,然后将动态添加一个script元素到头部,我来看下面菜鸟教程给与的客户端例子 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JSONP 实例</title> </head> <body> <div id="divCustomers"></div> <script type="text/javascript"> // 创建函数 function callbackFunction(result, methodName) { // 声明ul标签 var html = '<ul>'; // 循环创建li 插入ul for(var i = 0; i < result.length; i++) { html += '<li>' + result[i] + '</li>'; } html += '</ul>'; // 写入html document.getElementById('divCustomers').innerHTML = html; } </script> // 使用函数 <script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script> </body> </html>我们再来封装一下简单的jsonp函数完整的代码如下面 ...

June 8, 2019 · 2 min · jiezi

2019年前端面试题03

let与var的区别? Let为ES6新添加申明变量的命令,它类似于var,但是有以下不同: 1、var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象 2、let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升 3、let不允许重复声明.封装一个函数,参数是定时器的时间,.then执行回调函数。 function sleep (time) { return new Promise((resolve) => setTimeout(resolve, time));}项目做过哪些性能优化? 1、减少HTTP请求数 2、减少DNS查询 3、使用CDN 4、避免重定向 5、图片懒加载 6、减少DOM元素数量 7、减少DOM操作 8、使用外部JavaScript和CSS 9、压缩JavaScript、CSS、字体、图片等 10、优化CSS Sprite 11、使用iconfont 12、字体裁剪 13、多域名分发划分内容到不同域名 14、尽量减少iframe使用 15、避免图片src为空 16、把样式表放在 中 17、把脚本放在页面底部怎么判断两个对象相等? 1、转化成字符串后比较字符串是否一致: JSON.stringify(obj)===JSON.stringify(obj2);2、Object.is(obj1,obj2):判断两个值是否 相同 。如果下列任何一项成立,则两个值相同。 * 两个值都是 [undefined](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined) * 两个值都是 [null](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/null) * 两个值都是true或者都是false * 两个值是由相同个数的字符按照相同的顺序组成的字符串 * ~两个值指向同一个对象~ * 两个值都是数字并且 * 都是正零+0 * 都是负零-0 * 都是 [NaN] * 都是除零和[NaN]外的其它同一个数字 什么是模块化开发?实现mvvm主要包含两个方面,数据变化更新视图,视图变化更新数据: 图片描述 关键点在于data如何更新view,因为view更新data其实可以通过事件监听即可,比如input标签监听 'input' 事件就可以实现了。所以我们着重来分析下,当数据改变,如何更新视图的。 数据更新视图的重点是如何知道数据变了,只要知道数据变了,那么接下去的事都好处理。如何知道数据变了,其实上文我们已经给出答案了,就是通过Object.defineProperty( )对属性设置一个set函数,当数据改变了就会来触发这个函数,所以我们只要将一些需要更新的方法放在这里面就可以实现data更新view了。 ...

June 8, 2019 · 2 min · jiezi

Hugo创建个人博客指南

最近准备建立一个个人博客网站,对比hexo与hugo后,决定使用Hugo静态页面生成引擎,使用的主题是tranquilpeak,使用的评论系统为Valine。写这篇文章的目的是详细记录一下个人博客创建过程。 准备工作Git、Golang环境GitHub账户或者Gitee账户(使用免费的pages服务搭建博客)Wordpress账户(提供个人头像)LeanCloud账户(管理评论数据)安装Git、golang、创建GitHub、码云(gitee)账户过程略过安装Hugo本篇博客安装使用Windows系统,其他系统请看Hugo官网。 直接在GitHub下载最新版本zip包,并添加到环境变量。或者使用choco在命令行下载choco install hugo安装成功后在命令行输入hugo version显示下图,说明安装成功。 Hugo Static Site Generator v0.55.6-A5D4C82D windows/amd64 BuildDate: 2019-05-18T07:57:00Z 创建并配置站博客创建博客hugo new site myblog下载hugo-tranquilpeak-theme主题 cd myblog/themesgit clone https://github.com/kakawait/hugo-tranquilpeak-theme.git tranquilpeak修改config.toml配置文件复制themes/tranquilpeak/exampleSite文件夹下config.toml到myblog覆盖原有config.toml。在GitHub查看tranquilpeak主题配置项以下为本博客配置文件 baseURL = "https://your_name.github.io/your_name/"# Tips: 必须配置,否则上传的博客在GitHub Pages无法找到css文件,不产生样式languageCode = "en-us"defaultContentLanguage = "zh-cn"# Tips: 配置中文title = "KXMing"# Tips: 博客名称theme = "tranquilpeak"# Tips: 配置主题disqusShortname = "valine"# Tips: 评论系统paginate = 10# Tips: 每个页面显示的文章数canonifyurls = truepublishDir = "docs"# Tips: 生成静态博客到docs文件夹,部署在GitHub Pages上时,一次性部署博客源码与发布博客[permalinks] post = "/:year/:month/:slug/"[taxonomies] tag = "tags" category = "categories" archive = "archives"# Tips: 定义的博客分类与逻辑关系[author] name = "your_name" # Tips: 博客侧边栏名字 bio = "前端开发" # Tips: 博客侧边栏个人简介 job = "Front-end" # Tips: 博客侧边栏职业 location = "深圳" # Tips: 博客个人资料页面地址 gravatarEmail = "964579219@qq.com" # Tips: 博客个人头像,取自WordPress头像# Tips: 定义的侧边栏菜单,icon取自Font-awesome[[menu.main]] weight = 1 identifier = "首页" name = "首页" pre = "<i class=\"sidebar-button-icon fa fa-lg fa-home\"></i>" url = "/"...[[menu.links]]...[[menu.misc]][params] dateFormat = "2006年1月2日" # Tips: 默认日期格式 syntaxHighlighter = "highlight.js" # Tips: 语法高亮js库 clearReading = true # Tips: 进入文章内容页面侧边栏菜单收起状态 hierarchicalCategories = true sidebarBehavior = 2 # Tips: 定义侧边栏状态(值为1-6,可自行测试显示状态) coverImage = "cover.jpg" imageGallery = true # Tips: 在有内容底部显示照片墙 thumbnailImage = true # Tips: 列表页是否显示内容图片 thumbnailImagePosition = "bottom" # Tips: 列表页显示内容图片在底部 autoThumbnailImage = true favicon = "/favicon.ico" # Tips: 浏览器标签页本网站显示的图标,放置在static文件夹下[params.header.rightLink] class = "" icon = "" url = "/#about"# Tips: 是否显示页面头部右侧个人头像,及个人头像点击事件# 这里添加Valine评论系统的相关参数[params.valine] enable = true appId = 'your appid' appKey = 'your appkey' notify = false avatar = 'mm' placeholder = '说点什么吧...' visitor = true创建第一篇博客hugo new post/first_blog.md文件顶部设置,其余配置请参考tranquilpeak ...

June 8, 2019 · 2 min · jiezi

全栈进阶课程-React168NextjsKoa2一步到位开发Github

全栈进阶课程 React16.8+Next.js+Koa2一步到位开发Github 课程使用Next.js、Koa、Redis、Github API等搭建了一个全栈项目——第三方Github客户端。通过课程学习让同学们理解Next.js搭建全栈同构项目的过程以及其SSR原理,深度理解业界广泛使用的OAuth登录体系,并且能够在工作项目中熟练运用,提升个人竞争力。 微信 eweixin5566

June 8, 2019 · 1 min · jiezi

全方面分析敏捷BI工具为何如此热门

BI产品被认为是继ERP之后,企业服务领域新的增长蓝海。市场普遍认为,商业智能和分析平台市场的主流,已经从IT主导的分析报告,转向了商业主导的分析报告。从国内企业管理软件市场的角度来看,BI软件一直是投资的热点,敏捷BI的快速发展是一个亮点。那么,敏捷BI经过短短几年的发展就获得用户的青睐,它真的那么强大吗?本文将从各个方面分析敏捷BI工具的发展趋势。 5 敏捷BI与传统BI,两者有许多的区别。 1、部署开发周期是不同的。这是敏捷BI工具的一个主要特性。传统BI产品的部署通常需要几个月的时间,需要总体架构设计。这样的部署周期在日新月异的商业环境下更显尴尬。IT部分负担沉重。传统的BI报告需求将由业务部门提交给IT部门,每个新的需求都需要重新建模和开发。不仅IT部门负担沉重,而且很多天的生产效率会使业务部门错过业务机会。正是传统的BI无法解决的问题和业务环境的迫切需求,使得敏捷BI能够出现。敏捷BI在线部署只需要一周时间,而且不需要经历复杂模型的漫长过程。业务人员可以从大量数据中立即生成分析结果,可以使用自助服务分析来获得报告。 2、操作难度不同。毕竟,敏捷BI工具更高级,所以更容易上手。报告设计的整个过程是零代码操作。你可以通过拖拽生成图表,也可以通过下载app查看报表。员工可以快速掌握使用技巧。 3、满足需求的程度是不同的。敏捷BI可以通过建立数据仓库、数据建模、分析和表示,解决企业复杂的数据分析需求和日常报表需求;另一方面,对于频繁的业务数据分析需求,敏捷BI还提供了直连数据库等方法来直接分析数据。 4、敏捷BI工具支持多终端应用。报表自适应企业数据大屏输出,Android、苹果、各种终端都可以。 简而言之,敏捷BI所体现的快速部署、大数据量秒级分析、可视化数据分析等优势赢得了市场的青睐。 目前,市场上有很多敏捷BI解决方案提供商,主流敏捷商业智能产品如Tableau、FineBI、QlikView等。对这些敏捷BI工具的测评可以在“主流敏捷商业智能平台供应商排名”中看到。

June 7, 2019 · 1 min · jiezi

权威解读什么是实时BI分析

有趋势表明,BI将会更注重实时性,而且Web方式下的实时性,更能支持实时的业务决策。这篇文章就可以帮助你理解实时BI分析的知识,以及实时数据如何实现数据可视化,以更好地管理和决策。 a1db1ab139b7496ea0482e345644b0fe 一、实时BI的概念实时BI,即实时商业智能,是指商业智能系统中数据实时动态刷新。这一提法来自SOA(面向服务的体系结构)以及组成SOA的开放和标准技术。据了解,Teradata还在多个实时分析和激活数据仓库策略方面进行了大量投资,使公司具有竞争力。 二、应用场景以快速发展的消费品公司为例。业务代表每天都需要通过手机上传客户数据、销售数据和竞争对手的产品数据。在过去,业务系统和分析系统是分开的。每年12点以后,分析系统提取业务系统的数据,并做出相应的分析报告。有时候,根据前一天的数据生成分析报告实际上需要半个小时甚至更长时间,但是现在使用实时BI分析系统,它的速度要快几十倍甚至几百倍,而且生成报告只需要几秒钟。销售代表的时间非常宝贵。每天都有很多客户来访,每个客户都需要时间。使用实时BI分析系统后,他们可以花更多的时间访问和开发用户。更重要的是,对于快速移动的消费品公司,他们可以尽快看到一线销售情况和竞争对手的状态,并做出实时的决策,这可以大大提高企业的竞争力。 三、实时BI分析的步骤实时BI分析主要有四大步骤。 1、捕获数据流。实时BI可以捕获实时数据流,并且存储在数据库中。 2、数据流处理。数据流可以通过多种方式进行处理,比如分割、合并、计算以及与外部数据源的结合。一旦处理完毕,可视化组件就可以读取数据。 3、数据可视化组件读取处理后的数据。处理后的数据以结构化格式(如JSON或XML)存储在数据库中,并由可视化组件读取。JSON/XML文件中处理数据的刷新率称为更新间隔。 4、可视化组件更新实时仪表板。可视化组件从图表接口上的结构化数据文件(JSON/XML)绘制图表、标尺或其他可视化行为。在客户机上显示处理数据的频率称为刷新间隔。在一些应用程序中,例如具有图表呈现的股票交易应用程序,预先设置了基于数据流的触发。 随着更先进的数据库和实时功能成为现实,这些操作也在不断发展,在当今的大数据应用程序中创建了一个实时BI分析生态圈。

June 7, 2019 · 1 min · jiezi

JAVA免费微信管家系统JeeWx-41-版本发布微信砍价活动闪亮登场

JEEWX 从4.0版本开始,技术架构全新换代更名“捷微H5”。这是一款开源免费的微信运营平台,是jeewx的新一代产品,平台涵盖了:微信公众号管理、各种微信活动、小程序、微网站、微商城、分销商城、小程序商城、小程序网站、砍价、投票、会员等等功能,是一套成熟的互联网运营产品。架构层面,采用JAVA语言,具备更高的并发能力和大数据能力,采用微服务架构,插件式开发模块化、UI体验更好;另外强大的代码生成器,显著提高开发效率,便于用户二次开发;最大的优势:插件模式,每个功能模块以插件方式提供,方便插拔集成,个性化定制。一、升级日志本版本4.0是大换代版本,采用微服务架构,全部功能重写,此版本开启插件服务模式1、新增活动:微信新年砍价;2、提供全新录制教学视频;3、提供最新的使用文档;4、修改域名变更,属性文件读取失败等问题;5、修改删除一级菜单,子菜单未跟着删除问题;6、重置token,增加redis未配置提示;7、九宫格、水果机,新增项目说明文档,本地测试地址;二、平台功能介绍【微信公众号】 1、微信账号管理2、微信菜单管理(支持小程序链接)3、关注欢迎语4、关键字管理5、文本素材管理6、图文素材管理7、强大的图文编辑器(支持素材选择)8、粉丝用户管理9、粉丝同步功能10、接受消息功能11、Oauth2.0链接12、微信第三方平台(全网发布)13、系统用户管理14、系统角色管理15、系统菜单管理16、项目logo设置17、活动插件管理【微信活动】 1、九宫格2、摇一摇3、微砍价三、项目介绍捷微 - H5活动源码列表(陆续更新..) 1.微信公众号管理 P3-Biz-commonweixin2.摇一摇送卡券 P3-Biz-shaketicket3.九宫格活动 P3-Biz-jiugongge4.新年砍价 P3-Biz-gzbargain5.启动项目 P3-Web四、开发入门 1.Eclipse + Maven + JDK7 2.项目以Maven方式导入eclipse 3.初始化数据库脚步 P3-Web\doc\db\jeewx-h5-mysql-20180810.sql 4.采用maven方式,启动主项目P3-Web,命令:tomcat:run 活动访问地址: http://localhost/jeewx 说明:插件不能单独启动,maven方式引入到Web项目 5.系统默认登录账号 admin/123456 五、下载地址源码下载: https://gitee.com/jeecg/h5huo... 官方网站: htttp://www.jeewx.com QQ技术群: 97460170 体验公众号: 六、系统演示 捷微H5活动平台(管理后台) 捷微H5活动平台(H5微信活动)1.砍价活动-效果图 2.九宫格活动-效果图 3.斧头帮砍价-效果图 4.摇一摇送卡券-效果图

June 7, 2019 · 1 min · jiezi

权威解读BI与大数据

BI与大数据已经是现代社会的热词,但很多人并不能区别两者之间的关系。本文就请来权威解读关于它们的定义,两者间的区别与联系,以及相关的工作职责。 111 一、名词解释BI,英文是Business Intelligence中文被解释为商业智能,是一种帮助企业更好地利用数据来提高决策质量的技术集合,是一个从大量数据中挖掘信息和知识的过程。简单地说,它是应用业务、数据和数据值的过程。 大数据,英文是Big Data,通过算法直接分析来自不同渠道和格式的海量数据,发现数据之间的相关性。 二、两者的区别数据利用: BI更注重数据的呈现和分析,大数据更注重数据的深度分析和利用。 数据存储: BI存储有限的数据(DWH/DM等)。大数据中存储的数据则是无限膨胀。Hadoop的诞生就是为了低成本和无限制的扩展。 应用场景:商业智能更多的是关于决策,而不是大数据。描述性事实更多地基于群体共性,帮助决策者掌握宏观统计趋势,常常应用于支持业务决策。大数据具有更广泛的内涵,往往描述个体和更多的个体决策。在企业中实现BI应用程序是为了更好地共享和使用数据。 三、BI工程师和大数据工程师现在很多公司的BI工程师的工作职责主要是做报表,主要内容是使用一些BI软件开发不同类型的报表,例如使用FineBI,tableau等来实现明细报表等等。等待。在传统行业,这个职位可能需要sql和相关工具,而互联网行业需要一定的代码能力。 大数据工程师在不同的公司担任不同的职位。一是进行底层平台开发和维护,如构建和维护hadoop集群、开发调度平台等,此类工作需要较强的编码能力,对常用的开源数据源源代码有一定的了解;第二个是做数据开发,构建自己公司的平台之类的,这种工作需要强大的SQL开发和优化能力,需要一定数量的数据仓库模型设计技巧和一些基本的Java和Python开发能力等;第三就是什么都要做一点。 对于那些想要询问BI工程师和大数据工程师工资高不高的人,影响工资的因素与你的技术能力、公司对其职位的重视程度、职位的紧迫性以及个人运气有关。无论是做哪方面的工作都有高薪人士,选个自己喜欢做的深入去做即可。

June 7, 2019 · 1 min · jiezi

2019年前端面试题02

px、em和rem的区别 px表示像素 (计算机屏幕上的一个点:1px = 1/96in),是绝对单位,不会因为其他元素的尺寸变化而变化;em表示相对于父元素的字体大小。em是相对单位 ,没有一个固定的度量值,而是由其他元素尺寸来决定的相对值。rem:相对单位,可理解为”root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持。 任意浏览器的默认字体高都是16px。所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。为了简化计算,在css中的body选择器中声明Font-size=62.5%,这就使em值变为16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了。优雅降级和渐进增强 渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。eval()的作用 eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。 语法: eval(string)JS哪些操作会造成内存泄露 JS的回收机制: 找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔,周期性的执行。 垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:“标记清除”和“引用计数”。引用计数不太常用,标记清除较为常用。1、标记清除 这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。 *关于这一块,建议读读 ,关于作用域链的一些知识详解,读完差不多就知道了,哪些变量会被做标记。 function test(){ var a=10;//被标记,进入环境 var b=20;//被标记,进入环境}test();//执行完毕之后a、b又被标记离开环境,被回收2、引用计数 另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。 function test(){ var a={};//a的引用次数为0 var b=a;//a的引用次数加1,为1 var c=a;//a的引用次数加1,为2 var b={};//a的引用次数减1,为1}哪些操作会造成内存泄露: 1.意外的全局变量引起的内存泄露,一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是 window,也就是说: function foo(arg) { bar = "aaaaa";}// 实际上等价于function foo(arg) { window.bar = "aaaaa";}// 类似的function foo() { this.variable = "qqqqq";}//this 指向全局对象(window)foo();2.闭包引起的内存泄露 ...

June 7, 2019 · 2 min · jiezi

重学前端学习笔记二十九JavaScript中要不要加分号

笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的专栏学习【原文有winter的语音】,如有侵权请联系我,邮箱:kaimo313@foxmail.com。一、自动插入分号规则1.1、三条规则要有换行符,且下一个符号是不符合语法的,那么就尝试插入分号。有换行符,且语法中规定此处不能有换行符,那么就自动插入分号。源代码结束处,不能形成完整的脚本或者模块结构,那么就自动插入分号。1.2、例子//第一行的结尾处有换行符,接下来 void 关键字接在 1 之后是不合法的,根据第一条规则,会在 void 前插入换行符。let a = 1void function(a){ console.log(a);}(a);// 根据no LineTerminator here 规则, a 的后面就要插入一个分号。var a = 1, b = 1, c = 1;a++b++c// a ==> 1 b,c ==> 21.3、例子 no LineTerminator here 规则展示UpdateExpression[Yield, Await]: LeftHandSideExpression[?Yield, ?Await] LeftHandSideExpression[?Yield, ?Await][no LineTerminator here]++ LeftHandSideExpression[?Yield, ?Await][no LineTerminator here]-- ++UnaryExpression[?Yield, ?Await] --UnaryExpression[?Yield, ?Await]1.4、IIFE(立即执行的函数表达式)(function(){ console.log(1);})()(function(){ console.log(2);})()// 不加分号,输出结果// 1 Uncaught TypeError: (intermediate value)(...) is not a function(function(){ console.log(1);})();(function(){ console.log(2);})()// 加分号,输出结果// 1 2// 关于这个问题,遇到过,当时排查几十分钟 _(:3」∠)_ , 由于我之前的是有换行,还有注释,当时一直不理解,类似下面这样(function(){ console.log(1);})()// 处理。。。业务(function(){ console.log(2);})()1.5、带换行符的注释// 带换行符的注释也被认为是有换行符,return 也有 [no LineTerminator here] 规则的要求,这里会自动插入分号function f(){ return/* This is a return value. */1;}f();// undefined二、no LineTerminator here 规则no LineTerminator here 规则表示它所在的结构中的这一位置不能插入换行符。 ...

June 7, 2019 · 1 min · jiezi

基于WebSocket的web端IM即时通讯应用的开发

基于WebSocket的web端IM即时通讯应用的开发功能列表:1、Web端的IM应用2、支持上线、下线、实时在线提醒3、单聊、群聊的建立4、普通文字、表情、图片的传输(子定义富文本)5、单人的顶级提醒,多对话的窗口的提醒6、调用图灵机器人的自动回复演示核心技术列表1、websocket、sockjs、stomp2、前端展示涉及的jquery、vue、elementUI、jquerybase64js3、后端springboot、jsoup、spring-security、spring-websocket成果展示:技术实现说明:Websocket部分 web端的IM应用,要想实现两个客户端的通信,必然要通过服务器进行信息的转发。例如A要和B通信,则应该是A先把信息发送给IM应用服务器,服务器根据A信息中携带的接收者将它再转发给B,同样B到A也是这种模式。而要实现web端的实时通讯,websocket也是其中最好的方式,其他的协议如长轮询、短轮询、iframe数据、htmlfile等。 在实际开发中,我们通常使用的是一些别人写好的实时通讯的库,比如socket.io、sockjs(我们本次使用了他,类似jquery,对其他即时通讯技术做了封装),他们的原理就是将上面(还有一些其他的如基于Flash的push)的一些技术进行了在客户端和服务端的封装,然后给开发者一个统一调用的接口。这个接口在支持websocket的环境下使用websocket,在不支持它的时候启用上面所讲的一些hack技术。 WebSocket是HTML5的一种新通信协议(ws协议),是一个消息架构,不强制使用任何特定的消息协议,它依赖于应用层解释消息的含义;与处在应用层的HTTP不同,WebSocket处在TCP上非常薄的一层,会将字节流转换为文本/二进制消息,因此,对于实际应用来说,WebSocket的通信形式层级过低,因此,可以在 WebSocket 之上使用 STOMP协议,来为浏览器 和 server间的 通信增加适当的消息语义。 STOMP(Simple Text-Orientated Messaging Protocol) 面向消息的简单文本协议。 同 HTTP 在 TCP 套接字上添加请求-响应模型层一样,STOMP 在 WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义; STOMP 源码http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js,有兴趣的可以看一下能大致了解其原理和用法。本例程序核心代码: <!--TO 创建socket连接 并订阅相关频道-->var socket = new SockJS('/im-websocket');stompClient = Stomp.over(socket);//设置stomp 控制台日志为不输出stompClient.debug=null;stompClient.connect({}, function (frame) { // 相当于连接 ws://localhost:8080/gs-guide-websocket/041/hk5tax0r/websocket hk5tax0r就是sessionid console.log("正在连接",socket._transport.url); //订阅通用私聊频道 群组也通过这里实现 stompClient.subscribe('/user/topic/private', function (greeting) { } ); //订阅用户上线下线的公共频道 stompClient.subscribe('/topic/userlist', function (greeting) { });},function errorCallBack (error) { // 连接失败时(服务器响应 ERROR 帧)的回调方法 });数据发送如下://第一个参数对应controller的 @MessageMapping注解 /app为后台定义的通用前缀//第三个参数为内容字符串stompClient.send("/app/private", {}, JSON.stringify(message));//发送服务器 ...

June 6, 2019 · 2 min · jiezi

图片批量上传jshtmlcss

如题,图片批量上传,效果如图所示 上代码HTML <!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>jquery多文件上传插件</title> <link rel="stylesheet" type="text/css" href="css/normalize.css" /> <link rel="stylesheet" type="text/css" href="css/demo.css"> <link href="dist/styles.imageuploader.css" rel="stylesheet" type="text/css"> </head><body> <section role="main" class="l-main" style="margin-top:50px;margin-bottom:50px;"> <header class="site-header"> <h1 class="site-title l-site-title" style="font-size:1.2em;">jquery多文件上传插件效果演示</h1> </header> <div class="uploader__box js-uploader__box l-center-box"> <form action="#" method="POST"> <div class="uploader__contents"> <label class="button button--secondary" for="fileinput">请选择文件</label> <input id="fileinput" class="uploader__file-input" type="file" multiple value="Select Files"> </div> <input class="button button--big-bottom" type="submit" value="Upload Selected Files"> </form> </div> </section> <script src="js/jquery-1.11.0.min.js" type="text/javascript"></script> <script src="dist/jquery.imageuploader.js" type="text/javascript"></script> <script type="text/javascript"> (function(){ var options = {}; $('.js-uploader__box').uploader({ 'selectButtonCopy':'请选择或拖拽文件', 'instructionsCopy':'你可以选择或拖拽多个文件', 'submitButtonCopy':'上传选择的文件', 'furtherInstructionsCopy':'你可以选择或拖拽更多的文件', 'secondarySelectButtonCopy':'选择更多的文件', }); }()); </script> </body></html>jquery.imageuploader.js /* * ©2016 Quicken Loans Inc. All rights reserved. *//* global jQuery FormData FileReader */(function ($) { $.fn.uploader = function (options, testMode) { return this.each(function (index) { options = $.extend({ submitButtonCopy: '上传选定的文件', instructionsCopy: '支持拖放', furtherInstructionsCopy: '你也可以删除文件', selectButtonCopy: '选择文件', secondarySelectButtonCopy: '选择多个文件', dropZone: $(this), fileTypeWhiteList: ['jpg', 'png', 'jpeg', 'gif', 'pdf'], badFileTypeMessage: '对不起,我们不能接受这种类型的文件。', ajaxUrl: '/images/add', testMode: false }, options); var state = { fileBatch: [], isUploading: false, isOverLimit: false, listIndex: 0 }; // create DOM elements var dom = { uploaderBox: $(this), submitButton: $('<button class="js-uploader__submit-button uploader__submit-button uploader__hide">' + options.submitButtonCopy + '<i class="js-uploader__icon fa fa-upload uploader__icon"></i></button>'), instructions: $('<p class="js-uploader__instructions uploader__instructions">' + options.instructionsCopy + '</p>'), selectButton: $('<input style="height: 0; width: 0;" id="fileinput' + index + '" type="file" multiple class="js-uploader__file-input uploader__file-input">' + '<label for="fileinput' + index + '" style="cursor: pointer;" class="js-uploader__file-label uploader__file-label">' + options.selectButtonCopy + '</label>'), secondarySelectButton: $('<input style="height: 0; width: 0;" id="secondaryfileinput' + index + '" type="file"' + ' multiple class="js-uploader__file-input uploader__file-input">' + '<label for="secondaryfileinput' + index + '" style="cursor: pointer;" class="js-uploader__file-label uploader__file-label uploader__file-label--secondary">' + options.secondarySelectButtonCopy + '</label>'), fileList: $('<ul class="js-uploader__file-list uploader__file-list"></ul>'), contentsContainer: $('<div class="js-uploader__contents uploader__contents"></div>'), furtherInstructions: $('<p class="js-uploader__further-instructions uploader__further-instructions uploader__hide">' + options.furtherInstructionsCopy + '</p>') }; // empty out whatever is in there dom.uploaderBox.empty(); // create and attach UI elements setupDOM(dom); // set up event handling bindUIEvents(); function setupDOM (dom) { dom.contentsContainer .append(dom.instructions) .append(dom.selectButton); dom.furtherInstructions .append(dom.secondarySelectButton); dom.uploaderBox .append(dom.fileList) .append(dom.contentsContainer) .append(dom.submitButton) .after(dom.furtherInstructions); } function bindUIEvents () { // handle drag and drop options.dropZone.on('dragover dragleave', function (e) { e.preventDefault(); e.stopPropagation(); }); $.event.props.push('dataTransfer'); // jquery bug hack options.dropZone.on('drop', selectFilesHandler); // hack for being able selecting the same file name twice dom.selectButton.on('click', function () { this.value = null; }); dom.selectButton.on('change', selectFilesHandler); dom.secondarySelectButton.on('click', function () { this.value = null; }); dom.secondarySelectButton.on('change', selectFilesHandler); // handle the submit click dom.submitButton.on('click', uploadSubmitHandler); // remove link handler dom.uploaderBox.on('click', '.js-upload-remove-button', removeItemHandler); // expose handlers for testing if (options.testMode) { options.dropZone.on('uploaderTestEvent', function (e) { switch (e.functionName) { case 'selectFilesHandler': selectFilesHandler(e); break; case 'uploadSubmitHandler': uploadSubmitHandler(e); break; default: break; } }); } } function addItem (file) { //var fileName = cleanName(file.name); var fileName = file.name; var fileSize = file.size; var id = state.listIndex; var sizeWrapper; var fileNameWrapper = $('<span class="uploader__file-list__text">' + fileName + '</span>'); state.listIndex++; var listItem = $('<li class="uploader__file-list__item" data-index="' + id + '"></li>'); var thumbnailContainer = $('<span class="uploader__file-list__thumbnail"></span>'); var thumbnail = $('<img class="thumbnail"><i class="fa fa-spinner fa-spin uploader__icon--spinner"></i>'); var removeLink = $('<span class="uploader__file-list__button"><button class="uploader__icon-button js-upload-remove-button fa fa-times" data-index="' + id + '"></button></span>'); // validate the file if (options.fileTypeWhiteList.indexOf(getExtension(file.name).toLowerCase()) !== -1) { // file is ok, add it to the batch state.fileBatch.push({file: file, id: id, fileName: fileName, fileSize: fileSize, groups:groups}); sizeWrapper = $('<span class="uploader__file-list__size">' + formatBytes(fileSize) + '</span>'); } else { // file is not ok, only add it to the dom sizeWrapper = $('<span class="uploader__file-list__size"><span class="uploader__error">' + options.badFileTypeMessage + '</span></span>'); } // create the thumbnail, if you can if (window.FileReader && file.type.indexOf('image') !== -1) { var reader = new FileReader(); reader.onloadend = function () { thumbnail.attr('src', reader.result); thumbnail.parent().find('i').remove(); }; reader.onerror = function () { thumbnail.remove(); }; reader.readAsDataURL(file); } else if (file.type.indexOf('image') === -1) { thumbnail = $('<i class="fa fa-file-o uploader__icon">'); } thumbnailContainer.append(thumbnail); listItem.append(thumbnailContainer); listItem .append(fileNameWrapper) .append(sizeWrapper) .append(removeLink); dom.fileList.append(listItem); } function getExtension (path) { var basename = path.split(/[\\/]/).pop(); var pos = basename.lastIndexOf('.'); if (basename === '' || pos < 1) { return ''; } return basename.slice(pos + 1); } function formatBytes (bytes, decimals) { if (bytes === 0) return '0 Bytes'; var k = 1024; var dm = decimals + 1 || 3; var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return (bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i]; } function cleanName (name) { name = name.replace(/\s+/gi, '-'); // Replace white space with dash return name.replace(/[^a-zA-Z0-9.\-]/gi, ''); // Strip any special characters } function uploadSubmitHandler () { if (state.fileBatch.length !== 0) { var groups = $("#groups option:selected").val(); var data = new FormData(); for (var i = 0; i < state.fileBatch.length; i++) { //data.append('files[]', state.fileBatch[i].file, groups+state.fileBatch[i].fileName); data.append('files[]', state.fileBatch[i].file); } data.append('group', groups); $.ajax({ type: 'POST', url: options.ajaxUrl, data:data, cache: false, contentType: false, /*enctype: 'multipart/form-data',*/ processData: false, success : function(result) { //上传成功后可以进行业务的下一步操作,自己根据业务写吧 } }); } } function selectFilesHandler (e) { e.preventDefault(); e.stopPropagation(); if (!state.isUploading) { // files come from the input or a drop var files = e.target.files || e.dataTransfer.files || e.dataTransfer.getData; // process each incoming file for (var i = 0; i < files.length; i++) { addItem(files[i]); } } renderControls(); } function renderControls () { if (dom.fileList.children().size() !== 0) { dom.submitButton.removeClass('uploader__hide'); dom.furtherInstructions.removeClass('uploader__hide'); dom.contentsContainer.addClass('uploader__hide'); } else { dom.submitButton.addClass('uploader__hide'); dom.furtherInstructions.addClass('uploader__hide'); dom.contentsContainer.removeClass('uploader__hide'); } } function removeItemHandler (e) { e.preventDefault(); if (!state.isUploading) { var removeIndex = $(e.target).data('index'); removeItem(removeIndex); $(e.target).parent().remove(); } renderControls(); } function removeItem (id) { // remove from the batch for (var i = 0; i < state.fileBatch.length; i++) { if (state.fileBatch[i].id === parseInt(id)) { state.fileBatch.splice(i, 1); break; } } // remove from the DOM dom.fileList.find('li[data-index="' + id + '"]').remove(); } }); };}(jQuery));cssstyles.imageuploader.css ...

June 6, 2019 · 12 min · jiezi

前端答疑chrome开发者工具正确食用看网页源码

写这个文章,是因为在今天早上,有两个兄弟找我要源码。有图有真相。我震惊于都 9102年了,身为了一个正(xie)经(xin)前端er,还不会看控制台? chrome 开发者工具之 Sources打开我们的 Sources 选项看,我们可以看到如下结构。分为三块功能,左(目录)中(资源展示)右(断点调试)。 Sources 工具(左边区域)我们选中 page ,在这个里面我们可以看到我们所有的资源以树状展示。我们在对应的域名下 www.lilnong.top 下,找到 https://www.lilnong.top/static/html/svg-data-background-img-download.html这个路径,点击就可以看到对应的资源 Sources 工具(中间区域)这里就可以看到对应资源详情了,我们都看到源码了,直接复制岂不美滋滋。当然这里还有其他用途,比如说调试代码。作为一个正(wai)气(men)凛(xie)然(dao)的前端er,我们就不发挥一下自己的脑回路? 不知道大家有没有遇到调试线上 Vue 文件的时候遇到 new 出来的对象没绑定到全局拿不到? 方案一 找个方法打个断点,触发一下,然后 this 绑定到 window 。这边我们就可以随心所欲。方案二 找到 el 绑定的 DOM 对象去拿 __vue__大家有玩过网页游戏吗? Console 写个代码?或者说偷偷看一下过关条件?这里也和游戏有关,有一兄弟,爱摸鱼。之前的几款游戏,比较简单,他自己就破解了。游戏一上外挂,就索然无味。 这天,一个 angular 写的游戏,他束手无策,玩了几天,身体日渐消瘦。我决定拯救他一下。 通过我上面写的本领,成功打断点,找到初始化的时候,增加了外置修改器。解救兄弟与水火之间Sources 工具(右边区域)这里是调试工具,下面我们介绍一下每个按钮的功能 当有断点的时候是个,三角,意思是放过这个断点。当无断点的时候会在下次调用的时候停住。下一行,如果是方法不会跳进去步入,如果是方法,可以跳进去步出,跳出当前方法下一步(我没用过)当前状态是捕获调试。蓝色的时候是不捕获调试,会跳过 debugger。方便你打了断点,然后又想测试效果这个是捕获错误。当前是不捕获。chrome 开发者工具之 Network如果说,上一个 Sources工具 基本都是和代码相关的。这个就比较常用了。 看接口的返回值看接口的请求头,响应头查看资源的加载速度查看资源的大小,缓存情况,响应情况(cdn、waiting 等时间) Network 之 preserve log该功能为长日志功能,正常来说看到的都是当前页面的。如果跳转页面或者说刷新之后就没了。通过打开 preserve log,我们可以长久的保留内容。那它有什么作用呢? 我们可以看到一些中间页的跳转,省去了抓包的麻烦。可以和上个页面的数据比对。Network 之 disable cache前端缓存也是比较麻烦的一个事情。经常需要强刷,清缓存一顿的操作。当我们打开 disable cache 之后,我们就不需要关了,每次都是无缓存的加载 Network 之 offline比如说在测试 PWA。或者说弱网的情况下的一种快速配置。 ...

June 6, 2019 · 1 min · jiezi

朋友这里有个仓库需要你-PR-一下

前段时间,发布了一篇文章:学不动了,来点有趣的吧。发现 github 仓库被 frok 了很多次,因此下定决心要好好的把代码整理一下,方便大家查看代码以及更加愉快的 Pull Request。 简介该项目名叫 matrixchange ,编写的目的在于方便开发者实现矩阵动画,当然该项目已经发布到 npm ,使用 npm/yarn 安装即可。 该库为开发者提供了一个数组和一个函数,具体的文档可以查看上一篇文章,或是在 github 上查看更为详细的内容。 ok 简介到此完毕。虽然这个简介有点短,但是该篇的目的并不在于让大家了解这个矩阵动画,而是想让大家一起来丰富这个仓库。 接下来进入正题。 动画形式何为矩阵动画?简单来说就是有一个矩阵,然后让它动起来,效果如下: 这就是一个简单的矩阵动画,动画形式如何? 从右上到左下按照斜线进行运动那么动画效果呢? 翻转消失,然后翻转呈现animite.css 可以解决绝大多数的动画效果,而且 animite.css 中的动画也大致可以分为入场动画好出场动画两个大类,既然如此,那么我们实现矩阵动画中需要的动画效果迎刃而解,我们仅需要丰富动画形式即可。 抽象既然我们准备批量实现我们的动画形式,那么抽象是必要的,按照之前给的效果图,这个是我抽象出来的对象: { interval: 140, duration: 1000, init(row, col) { this.row = row; this.col = col; this.count = col; }, check(i, j) { return j - i === this.count; }, next() { this.count--; }, end() { return this.count === -this.row; }}字段名类型代表的含义intervalnumber每次(获取需要运动的点)的时间间隔durationnumbertransition 动画专用,用于设置 transition 的持续时间,animate 动画不需要initFunction每次动画开始前会调用,用于初始化对象信息checkFunction用于确定每次需要运动的点nextFunction每次(获取需要运动的点)后都会调用该函数,用于重置判断条件endFunction判断该动画是否结束动画具体的执行流程为 ...

June 6, 2019 · 2 min · jiezi

前端bug录移动端下载图片

前天,快下班的时候,一朋友发来一个战绩图。这是要约我上分?(这兄弟一手 C 位吊打亲友)。我果断拒绝三连。结果,小韭菜问我,右边那个图怎么做?那好了,事情从这里开始 分析一下需求这个图好像叫雷达图,那我们先去看 echarts,简直不要太像好吗? 小韭菜没给我反应的机会提出了另一个想法:简单一点简单一点,我又想起了 Vue官网 有这个东西。 小韭菜看都没看就说:不用 VueWhat?我只是让你看看原理啊。那好吧,我看了一眼,就是 svg 实现 SVG 实现雷达图jsrun测试地址,如果 jsrun 挂了,可以去我个人网站上看测试地址。 <svg width="200" height="200" class="demo-svg warp"> <polygon points="100,10.899999999999991 175.32367609057616,75.52585404550416 145.49457852743743,162.61791536462093 71.43363673858582,139.31822592662246 41.795341202736594,81.08815994425322" class="demo-polygon" style="fill: #41B883;"></polygon> </svg>SVG 的 polygon<polygon> 标签用来创建含有不少于三个边的图形。points 属性定义多边形每个角的 x 和 y 坐标 那我们来看上面的图片,正好五个角,那我们就可以动手改改。简单的一匹 100,10.899999999999991175.32367609057616,75.52585404550416145.49457852743743,162.6179153646209371.43363673858582,139.3182259266224641.795341202736594,81.08815994425322实现下载雷达图因为快下班了,小韭菜看了一眼说搞定。然后又提出了一个需求,下载这个图片。我一想简单的一匹啊。我前两天才写了文章的 前端培训-初级阶段-场景实战(2019-06-06)-下载文件&下载进度 小韭菜之前用过 html2canvas 还是啥来着。直接这样搞download 直接下载(svgToDataurl)svgToCanvas 然后下载 canvas 的图片canvas 的 toBlob 结合 URL.createObjectURL 和 downloadcanvas 的 toDataUrl 结合 download为啥我上面写了这么多的方法。因为移动端不好使。不好使的原因就是 DataURL 和 BlobURL 在移动端(微信、QQ、QQ浏览器)无法下载。 SVG 怎么用 img 显示这个还是当时在张鑫旭张大师哪里看到的方法。SVGTODataURL data:image/svg+xml,%3Csvg xmlns='http://w这样我们就可以显示了。 download 直接下载上面我们显示了出来,直接下载吧。nonono,因为上面的 Dataurl 是 svg 格式的,下载也是 SVG 格式的。所以我们需要用 img 读取 svgurl。然后 canvas 读取 img 。然后 canvas 输出想要的图片格式。然后再下载。 ...

June 6, 2019 · 1 min · jiezi

Vue核心50讲-第一回Vue-与-MVVM-之间那些事儿

书接上文,上一回咱们说到了如今的前端江湖早已是框架三分天下的格局。接下来,咱们就要说到主角 Vue 了。在说真正的 Vue 内容之前,咱们还要先来说说 Vue 与 MVVM 之间的那些事儿。 什么是Vue想要近距离了解什么是 Vue,其实特别简单。咱们只需要访问 Vue的官方网站 就可以了。 映入眼帘的,咱们可以看到说 Vue 是渐进式 JavaScript 框架,英文叫做“Progressive JavaScript Framework”。当然,你现在并不需要知道什么是渐进式 JavaScript 框架。那么接下来,咱们再进一步看看 Vue 的官方是如何来介绍自己的呢。 Vue (读音 /vju/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。关于这个定义咱们不做过多的解释了,因为就算解释估计你现在也很难知道它在说个啥!如果你不满足,那我们就再看一个 Vue 官方提供的视频吧。 Vue的特点根据 Vue 的官方提供的信息,咱们可以看到 Vue 主要的特点集中在三点: 易用:只要你掌握了 HTML、CSS 和 JavaScript,就可以直接来学习 Vue 框架了。灵活:Vue 提供一个核心库,类似于 jQuery。依赖自身不断繁荣的生态系统,类似于 jQuery 的插件库一样,可以在一个库和一套完整框架之间自如伸缩。高效:核心库文件压缩之后只有 20KB,远比 jQuery 的压缩版文件小得多。并且还提供超快的虚拟 DOM。总体来讲,Vue 的官方就是告诉你,用我这个框架要求很低,会HTML、CSS 和 JavaScript 就可以了。而且,我这个框架的核心库 Vue.js 文件很小,你使用的时候不会对你现在的项目造成多大的影响。裤裆里着火,当然了!我们现在也没用 Vue 来开发个网页,所以它所谓的优势对于咱们现阶段来说只不过自说自话而已。是不是这个样子,咱们还需要在具体的案例中体验。 什么是 MVVM关于 Vue 咱们说了这么多,接下来再来说说关于 MVVM 吧。MVVM 呢,其实是一种开发模式。当然,这么说估计你也是一脸懵逼的。心急吃不了热豆腐,且听我慢慢道来~MVVM 其实表示的是 View-ViewModel-Model,就是视图层-视图模型层-模型层。View是作为视图层,简单来说可以把它理解为HTML页面;Model 是作为模型层,它是负责处理业务逻辑以及和服务器端进行交互的;ViewModel 是作为视图模型层,也就是 Vue 框架所起到的作用了,主要是作为 View 层和 Model 层之间的通信桥梁。 ...

June 6, 2019 · 1 min · jiezi

Vue核心50讲-第零回做足前戏让你平滑进入-Vue

既然说明了是前戏,那就是要诱惑你... ...不对,就是告诉你本套”书“讲的是什么。讲的是什么呢?讲的是前端框架 Vue。 前端江湖发展到今天,已是框架三分天下的局面。可能你会问了,哪三分呢?这三分乃是 Vue、React 和 Angular 这三个前端框架。虽说是三分天下,但也有强弱之分,最强的要数咱们的主角 Vue。 说到这啊,咱们得介绍介绍这个历史背景。早在公元两千零九年,为了克服 HTML 在构建 Web 应用上的不足,由 Misko Hevery 为头的一伙人创建了 AngularJS,后来被一家叫做 Google 的公司收购了。AngularJS 把曾经运用在后端开发的模式引入到了前端开发之中,这就是著名的开发模式 MVC。 由于那个时候的前端江湖还处在需要手动创建工程,使用各种库的荒蛮时代。AngularJS 就是在这样的历史背景下被创建出来的,然后迅速崛起。崛起之后啊,也暴露出了一些问题,比如框架庞大、臃肿,性能也是越来越差。这说话间,时间就来到了公元两千一十三年。Facebook 这家公司找准了机会,推出了 ReactJS 这个前端框架。 ReactJS 的设计极其独特,最厉害的是它首创了 Virtual Dom(虚拟DOM)。 由于 ReactJS 首创了 Virtual Dom 和 JSX 等新的概念和用法,导致学习成本居高不下。这个时候,有个人叫尤雨溪,他当时还在 Google 公司用着 AngularJS 呢。当时呢,尤雨溪想写个简单的框架来练练手,就创造了 Vue。直到公元两千一十五年,Vue 才真正出世。由于 Vue 简单易学,迅速收到各大公司支持。 至此,前端江湖中框架三分天下的格局已定。

June 6, 2019 · 1 min · jiezi

重磅重构开源-让H5标签代替C实时解码播放speex压缩协议的音频文件-IM的福音

这么牛逼的轮子,肯定要美图镇楼Speex是一套主要针对语音的开源免费,无专利保护的音频压缩格式。本轮子,适用超大型项目,因为库本身很大,当然本身IM项目就没有小项目吧Speex(音标[spi:ks])是一套开源免费的、无专利保护的、针对语音设计的音频压缩格式。Speex项目通过以提供昂贵的专用语音编解码器的免费替代方案为目标,来降低语音应用程序的进入门槛。此外,Speex非常适用于互联网应用程序,并提供了其他大多数编解码器中不存在的有用特性。最后,Speex是GNU项目的一部分,可以在修订后的BSD许可证下使用。编码流程使用Speex的API函数对音频数据进行压缩编码要经过如下步骤:定义一个SpeexBits类型变量bits和一个Speex编码器的内存指针变量enc。调用speex_bits_init(&bits)函数初始化bits。调用enc = speex_encoder_init(&speex_nb_mode)函数初始化enc。其中speex_nb_mode是SpeexMode类型的变量,表示的是窄带模式。还有speex_wb_mode表示宽带模式、speex_uwb_mode表示超宽带模式。调用函数 int speex_encoder_ctl(void * state, int request, void * ptr)来设定编码器的参数,其中参数state表示编码器的内存指针;参数request表示要定义的参数类型,如SPEEX_GET_FRAME_SIZE表示设置帧大小,SPEEX_SET_QUALITY表示编码的质量等级;参数ptr表示要设定的值。初始化完毕后,对每一帧声音作如下处理:调用函数speex_bits_reset(&bits)重置bits,然后调用函数speex_encode(enc_state,input_frame, &bits)进行编码,参数bits中保存编码后的Speex格式数据帧。编码结束后,调用函数speex_bits_destroy(&bits),speex_encoder_destroy(enc_state)来销毁SpeexBits和编码器。 解码流程对已经编码过的Speex格式音频数据帧进行解码要经过以下步骤:定义一个SpeexBits类型变量bits和一个Speex解码器的内存指针变量dec。调用speex_bits_init(&bits) 函数初始化bits。调用dec = speex_decoder_init(&speex_nb_mode) 函数初始化dec。调用函数speex_decoder_ctl(void * state, int request, void * ptr)来设定解码器的参数。调用函数 speex_decode(void * state, SpeexBits * bits, float * out)对参数bits中的Speex格式音频数据帧进行解码,参数out中存放解码后的音频数据帧。调用函数speex_bits_destroy(&bits), speex_decoder_destroy(void * state)来销毁SpeexBits和解码器说重点当做即时通信产品,像微信这种的手机端,它们接受到很有可能就是speex协议压缩后的音频文件。当然,文件后缀是wav或者ogg都无关紧要H5的audio标签可以播放 音频格式及浏览器支持目前, <audio>元素支持三种音频格式文件: MP3, Wav, 和 Ogg:浏览器 MP3 Wav Ogg Internet Explorer 9+ YES NO NOChrome 6+ YES YES YESFirefox 3.6+ NO YES YESSafari 5+ YES YES NOOpera 10+ NO YES YES音频格式的MIME类型Format MIME-typeMP3 audio/mpegOgg audio/oggWav audio/wav本开源库基于speex封装,抽取了必须要的文件后进一步封装,修改了在复杂环境下的兼容本源码支持环境 ...

June 5, 2019 · 1 min · jiezi

重学前端学习笔记二十八通过四则运算的解释器快速理解编译原理

笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的专栏学习【原文有winter的语音】,如有侵权请联系我,邮箱:kaimo313@foxmail.com。一、分析按照编译原理相关的知识,将其分成几个步骤。定义四则运算:产出四则运算的词法定义和语法定义。词法分析:把输入的字符串流变成 token。语法分析:把 token 变成抽象语法树 AST。解释执行:后序遍历 AST,执行得出结果。二、定义四则运算2.1、定义词法Token Number: 1 2 3 4 5 6 7 8 9 0 的组合Operator: +、-、*、/ 之一Whitespace:<sp>LineTerminator:<LE> <CR>2.2、定义语法语法定义多数采用 BNF。巴科斯范式(BNF: Backus-Naur Form 的缩写)是由 John Backus 和 Peter Naur 首次引入一种形式化符号来描述给定语言的语法(最早用于描述ALGOL 60 编程语言)。JavaScript 标准里面就是一种跟 BNF 类似的自创语法。1、加法是由若干个乘法再由加号或者减号连接成的: <Expression> ::= <AdditiveExpression><EOF><AdditiveExpression> ::= <MultiplicativeExpression> |<AdditiveExpression><+><MultiplicativeExpression> |<AdditiveExpression><-><MultiplicativeExpression>2、可把普通数字当成乘法的一种特例: <MultiplicativeExpression> ::= <Number> |<MultiplicativeExpression><*><Number> |<MultiplicativeExpression></><Number>上面就是四则运算的定义。 三、词法分析:状态机词法分析:把字符流变成 token 流,有两种方案,一种是状态机,一种是正则表达式,它们是等效的。3.1、实现状态机// 可能产生四种输入元素,其中只有两种 token,状态机的第一个状态就是根据第一个输入字符来判断进入了哪种状态var token = [];function start(char) { if(char === '1' || char === '2'|| char === '3' || char === '4'|| char === '5'|| char === '6'|| char === '7' || char === '8'|| char === '9'|| char === '0') { token.push(char); return inNumber; } if(char === '+' || char === '-' || char === '*' || char === '/') { emmitToken(char, char); return start } if(char === ' ') { return start; } if(char === '\r' || char === '\n') { return start; }}function inNumber(char) { if ( char === '1' || char === '2' || char === '3' || char === '4'|| char === '5' || char === '6' || char === '7' || char === '8' || char === '9' || char === '0') { token.push(char); return inNumber; } else { emmitToken("Number", token.join("")); token = []; // put back char return start(char); }}// 用函数表示状态,用 if 表示状态的迁移关系,用 return 值表示下一个状态。3.2、运行状态机function emmitToken(type, value) { console.log(value);}var input = "1024 + 2 * 256"var state = start;for(var c of input.split('')) state = state(c);state(Symbol('EOF'))// 输出结果1024+2*256四、语法分析:LLLL 语法分析根据每一个产生式来写一个函数。4.1、写好函数名function AdditiveExpression( ){}function MultiplicativeExpression(){}4.2、假设已经拿到 tokenvar tokens = [{ type:"Number", value: "1024"}, { type:"+", value: "+"}, { type:"Number", value: "2"}, { type:"*", value: "*"}, { type:"Number", value: "256"}, { type:"EOF"}];4.3、AdditiveExpression处理1、三种情况 ...

June 5, 2019 · 4 min · jiezi

vue如何自动化打包测试环境和正式环境的disttest文件

使用vue现在已经差不多2年了,想起来两年前的一次和某阿里处理的技术大牛(当时我们的技术总监)一起开发一个SPA项目的时候被硬着头皮去解决的一个难题,因为技术老大是阿里出身的,所以很多东西都是比较倾向于自动化,从项目ui设计到项目管理,到打包测试,到发布全部都要求我们要实现自动化,尽可能的减少手动操作。 当时技术大佬要求的事在jenkins进行一键打包,就是他点击不同的按钮在同一套代码上面分别打包测试环境运行的包和正式环境运行的包,刚刚接触vue的我摸不着头脑,老大给了我一天时间研究这个玩意,没办法,只好硬着头皮做,后来想想改造一下,也比较简单。 Step1、package.json中新增命令行脚本test命令,并指向build文件夹下的test.js。 Step2、在在build文件夹中新建test.js,内容可以直接拷贝同目录build.js内容,修改一些参数 这样就多了个test环境 Step3、 在build文件夹中新建webpack.test.conf.js,内容可以直接拷贝同目录webpack.prod.conf.js内容,修改一些参数。 这样构建时就会去config文件夹下的test.env.js寻找环境变量。 Step4、在config下创建test.js文件 Step5、在封装的axios.js的文件夹下创建config.js Step6、在封装的axios引入config.js 封装的get 和post请求 Step7、在config文件下的index增加test模块(可复制build)并更改相应的参数。 在打包的时候执行:npm run test 就会自动的指向测试环境的域名dist文件,执行npm run build 就会打包指向正式环境的域名的dist文件,在Jenkins里面的分别连接至gitlab/github,并将命令分别分配给run test && run build,需要发布的时候就直接点击不同的按钮,然后再Linux下自动打包不同环境的dist,可以提高开发效率,减少开发和沟通成本。

June 5, 2019 · 1 min · jiezi

2019年百度云计算市场突变状况

时间到了2019年六月份,对于云计算市场的变动,企业和站长都敏锐感觉到云服务器市场的变动,我们的企业推广其中最主要的就是百度,可是六月份百度搜索总裁向海龙辞职,下面高管也陆续离职了4个,百度搜索公司带来的盈利占到整个百度的七成以上.去年同时期,百度盈收几十亿元,今年已经负几十亿了,前两年还说BAT,然后现在百度市值不及阿里和腾讯的十分之一了. 百度2019年一过就各种推广自己的云服务器,结果买的人很少,推广还是看之前的三板斧,打电话、竞价、硬推,这些办法已经过时了,当阿里云每年的盈利都在涨幅,腾讯云依托自己新媒体扛把子身份,一步步扩张小程序时,百度还在玩抄袭、垄断、嫁接等忽悠人.百度的辉煌要过去了,云服务器计算领域要迎来新的变革,随着5G时代来临,总带宽变大,相对的我们的云服务器也将享受红利,更大的带宽,随着AMD和intel在服务器处理器市场大战,将来的硬件采购也将会大幅度便宜,这是要爆发的前期呀.对于你同时购买多个厂商的云服务器,那么管理这些云服务器就需要好的方式,采用SAAS化云平台就是最完美的解决方式,旗鱼云梯这个互联网产品.推出后受到了企业和个人站长的欢迎,能够实现多个云服务商主机管理在一个平台下,同时批量实现管理,一键web环境搭建,LAMP和LNMP的免费服务器,一键建立网站,免费的SSL的https服务,各厂商CMS系统支持,安全稳定的WAF防火墙.只有一流的团队,才能够实现这样的革命进步,旗鱼云梯是2019年服务器集群管理的新篇章,是企业和个人站长的最好集群化平台.

June 5, 2019 · 1 min · jiezi

一道面试题引发的思考

以下是某场的一道面试题(大概): 1、一个停车场,车辆入场时,摄像头记录下车辆信息2、屏幕上显示所接收的车辆的信息情况(车牌号)以及各层车位的车位余量3、停车场一共四层车位,其中的三层都为普通车位,还有一层为特殊车位(体现在停车计费价格上面的不同) 看到第一个条件的时候,我大概知道了这道题考察的应该是面向对象相关的,三个条件看完后以及基本确认了。 说到这里,简单地说一下面向对象,至于什么是面向对象我这里就不多说了,每个人也都有自己不同的理解,包括它的三要素(封装、继承、多态)。 简单地说一下为什么我们要面向对象,为什么要使用面向对象?说一下我的理解 先抛开面向对象,首先计算机的 程序执行 无非就是 顺序、判断、循环 我们现在所有用到的语言包括c、java、php... 没有其它的, 如js中的 if...else, switch...case...就是判断,for,while就是循环,也包括一些遍历、递归也都是基于这三种方式!我们每天所产出的代码,所有的这些都是通过顺序、判断和循环这三个方式都能轻松搞定,没有第四种方式,为什么呢?因为我们通过这三种方式来解决就实现了一个结构化的问题,也就是我们通过这三个就能满足所有的需求,也就不需要第四个了这样的化对我们的程序就已经结构化了,对于编译器也能很高效的执行、解析这些东西, 外插一嘴,goto语句其实就是游离在这三个之外,会导致程序、逻辑的混乱,很少有用基本被淘汰了,不能说他因为效率低,它的效率可能会很高,但是因为脱离了结构化,所以至少在业务代码上我们极少使用它。 说到这里,也就是程勋执行我们都简化成 这个结构,而面向对象也让我们的数据也简化了即结构化(这句话也不是我说的,而是ruby语言的作者),书里说了,面向对象是为了模拟、表示事件得万物,比如人、鸟类、到具体服务员类,有具体行为的类。其实js里面向对象意义根本不拘泥于此,书上的只是为了让我们好入门好学习而已,它的意义是将零散的数据进行结构化。计算机有个毛病,结构化的程序对于它来说是最简单的! 简单解释一下,我们浏览器加载网页加载的是什么?是流,流是什么呢?其实就是字符串,虽然我们看到之后是html,css,js代码,但是代码不就是字符串嘛,那我们字符串怎么办,浏览器拿到字符串首先就是dom节点的解析然后生成生成渲染树(渲染树与dom树不同的地方在于,dom树会把所有的dom节点都展示出来,渲染树只会展示display非none的元素),都是一步步顺序执行的。 相比来说,程序也是如此了,如果我们的程序中充满了散乱的数据,那我们还怎么按照结构化的要求去操作呢?比如说,通过人做一个对象,人有外貌,行为,状态(吃、传、喝、高矮胖瘦)这么多东西可以集成在一个对象中来操作,但是如果没有面向对象,这些特征,行为也就散乱了,一旦散乱了以后还怎么管理,并且这只是一个人,就有这么多东西,再来十个,一百个,再来只狗类呢?我们的程序就成了一盘散沙了,当然这些只是举例子,具体业务还要拿来具体分析。所以面向对象不仅符合计算机所喜爱的结构化,还能让我们管理起来,维护起来,都符合结构化。 再引用双越老师的一句话:编程就应该简单&抽象。 有一篇小说里面有一段话我觉得还蛮有意思的,早期的人们之所以没有设计出来计算机,就是因为他们想的不够简单,而不是不够复杂,其实计算机很简单,不就是0和1吗。 所有说我们编程,设计时候要做到 结构化,简单+抽象,抽象完之后才能简单,简单的前提是我们应该抽象好,我认为这就是我们为什么要面向对象最主要的原因,我们之所以面向对象编程就是因为它可以抽象,可以扩展。而不是面向具体,可能这些话对于初学前端的来说不好理解,但是随着你工作时间的提升,相信很快就会理解的。 **回到面试题,我们来分析** 这个面试题,如果我们没有面向对象,面向抽象的概念, 那我们应该很快就能拿起键盘了,一个停车场,三个普通车位,一个豪华车位,一个摄像头,一个大屏幕显示器,各种各样的车,可能我们很快就能做完,‘设计完’,毕竟面向具体是真的很简单,要求什么我就做什么。。。 不过说回来,如果面试官再让你减一个车位或者增加两个豪华车位,加两个摄像头?如果按照我们之前的来写,简单。。。改一下不就行了,加一个豪华车位,加两个摄像头。。。其实到这里想必已经凉凉了。 下面我们来使用面向对象 类图这里就不再画了 首先面试题中所提到的我们都可以看成类,比如停车场是一个类吧,它里面的车位是一个类吧,摄像头,屏幕。。。我们都可以看做是类 停车场,有层位,有摄像头,屏幕,所以我们先来创建一个停车场,这一类 class Park { constructor () { }}停车场有层位,层位里面有若干车位class Floor { constructor (num, places) { this.num = num this.places = places }}车位也归为一类,车位有自己的状态,有车,无车class Place { constructor () { this.empty = true }}车位分为普通车位,豪华车位,但是不论是普通还是豪华,他们也都有自己的状态,有车,无车,所以我们直接让这两个类继承车位类普通车位class NormalPlace extends Place{ constructor () { super() }}豪华车位class SpecialPlace extends Place{ constructor () { super() }}摄像头class Camera { constructor () { }}电脑,可以记录所有车的数据class Computer { constructor () { this.symbols = {} }}// 屏幕class Screen {}这样一看我们所有类都创建完了,差的是来分析他们的行为,状态,联系,这里不再多做分析。只举一个简单的例子,然后上完整代码停车场, 有层 摄像图 屏幕,有出入车时所发生的行为class Park { constructor (floors) { this.floors = floors this.camera = new Camera() this.screen = new Screen() } in (car) { } out (car) { }}我自己写了一个简单的demo,当然也没有考虑得特别细致***完整代码***<!DOCTYPE html> ...

June 5, 2019 · 4 min · jiezi

css3的3D

1.概念要玩转css3的3d,就必须了解几个词汇,便是透视(perspective)、旋转(rotate)和移动(translate)。透视即是以现实的视角来看屏幕上的2D事物,从而展现3D的效果。旋转则不再是2D平面上的旋转,而是三维坐标系的旋转,就包括X轴,Y轴,Z轴旋转。平移同理。 原文 !来源

June 5, 2019 · 1 min · jiezi

addEventjs源码解析

前言:看两三遍即可。 在看 jQuery 源码时,发现了这段注释: //源码5235行 /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { }Dean Edwards 的 addEvent.js 库为 jQuery 的事件绑定提供了很多想法,我们就来看下 2005 年的 addEvent.js 。 〇、先复习下 Object 的内存地址指向的知识 let a={ } let b=a b[0]='111' console.log(a,'a55') //{0:'111'}b 改变属性,a 也会改变,因为 b 与 a 指向同一地址(b=a) 一、addEvent()作用:为目标元素绑定事件(如 click) ...

June 5, 2019 · 3 min · jiezi

手机发布133566

# 1266886

June 5, 2019 · 1 min · jiezi

带着canvas去流浪2绘制折线图

示例代码托管在:https://github.com/dashnowords/blogs/tree/master/Demo/canvas-echarts/line-chart博客园地址:《大史住在大前端》原创博文目录 华为云社区地址:【你要的前端打怪升级指南】 一. 任务说明使用原生canvasAPI绘制折线图。(柱状图截图来自于百度Echarts官方示例库【查看示例链接】。 二. 重点提示一般折线图是比较好实现的,只需要调用最基本的moveTo()和lineTo( )方法来绘制即可。平滑折线图是一个难点,需要借助贝塞尔曲线来进行绘制,此时每段曲线的控制点算法就成了核心难点,对原理感兴趣的读者可以自行研究,本文直接利用算法的结论来进行实现。 上一节中为了以文字中点为参考,在绘制x轴文字时采用的方法是用measureText( )方法测量文字的宽度,然后偏移该距离的一半来达到效果,事实上我们可以通过设置textAlign属性为'center'来达到以文字宽度方向中线为参考点的绘制。 context.textAlign = 'center';context.drawText('Hello world',x ,y);三. 示例代码坐标轴及绘图参数设置请直接参见 【带着canvas去流浪】(1)绘制柱状图 或在示例demo中查看。 3.1 一般折线图折线图数据绘制示例代码: /** * 绘制数据 */function drawData(options) { let data = options.data;//数据点坐标 let xLength = (options.chartZone[2] - options.chartZone[0])*0.96;//线段尾部留白后x轴长 let yLength = (options.chartZone[3] - options.chartZone[1])*0.98;//线段尾部留白后y轴长 let gap = xLength / options.xAxisLabel.length;//x轴间隙 //缓存从数据值到坐标距离的比例因子 let yFactor =(options.chartZone[3] - options.chartZone[1]) *0.98 / options.yMax let activeX = 0;//记录绘制过程中当前点的坐标 let activeY = 0;//记录绘制过程中当前点的y坐标 context.strokeStyle = options.barStyle.color || '#1abc9c'; //02BAD4 context.strokeWidth = 2; context.beginPath(); context.moveTo(options.chartZone[0],options.chartZone[3]);//先将起点移动至0,0坐标 for(let i = 0; i < data.length; i++){ activeX = options.chartZone[0] + (i + 1) * gap; activeY = options.chartZone[3] - data[i] * yFactor; context.lineTo(activeX, activeY); } context.stroke(); }浏览器中可查看效果: ...

June 4, 2019 · 2 min · jiezi

2018年8月所遇知识点整理

*注:本文章是在工作过程中所接触的知识点的整理,涉及的东西比价杂乱,如有错误之处,欢迎纠错与指导一, 页面的锚链接二, WebSocket三, 热更新四, requestAnimationFrame五, 数据埋点

June 4, 2019 · 1 min · jiezi

2018年12月所遇知识点整理

*注:本文章是在工作过程中所接触的知识点的整理,涉及的东西比价杂乱,如有错误之处,欢迎纠错与指导一, get 请求src 含有中文地址请求失败,显示不出来二, vue v-clipboard 剪切板功能三, 树状结构数据四, 前端常见跨域解决方案五, es6新增 set六, 在 JS 对象中使用 . 和 [] 操作属性的区别HTML5 sessionStorage会话存储【整合到前端存贮里面去】 七, vue 使用less全局变量八, vue项目使用阿里巴巴的矢量图标九, 纯JS生成并下载各种文本文件或图片十,JavaScript数据结构和算法

June 4, 2019 · 1 min · jiezi

2018年9月所遇知识点整理

*注:本文章是在工作过程中所接触的知识点的整理,涉及的东西比价杂乱,如有错误之处,欢迎纠错与指导一, px还是rem二, Web性能信息采集指南三, Web性能信息采集指南四, 前端上传文件

June 4, 2019 · 1 min · jiezi

2019年1月所遇知识点整理

*注:本文章是在工作过程中所接触的知识点的整理,涉及的东西比价杂乱,如有错误之处,欢迎纠错与指导一, webpack之css模块化二, 组件化设计与开发三, webpack打包并将文件加载到指定的位置四, Postcss-salad五, 编写模块化CSS:BEM

June 4, 2019 · 1 min · jiezi

vue-核心之一-计算属性computed-和侦听属性watch

对于很多初学vue的初级前端开发工程而言,在了解了vue双向数据绑定v-model、模板语法、实例创建等基础的知识之后,对于一些复杂的数据操作还无从下手。 首先,什么是计算属性? 在vue官方文档中,对计算属性的初衷是由于模板内部的表达式虽然已经很便利,但是它只能进行简单的运算,而且面对复杂逻辑的时候,模板过重并且难以维护,所以官方给的建议是对于任何复杂的逻辑都应当使用计算属性。 那么,我们为什么要使用计算属性呢?它到底有什么好处,可以给我们带来哪些便利呢?我们一起来看下以下代码 <div id="app"> {{ message.split('').reverse().join('') }}</div>var vm = new Vue({ el: '#example', data: { message: 'Hello' }})对于初学着来说,如果要拆分对message进行处理或者其他的复杂操作,我们可能会想到上面这种形式去处理,但是如果说,要实行for循环呢? 有人会说,我可以在`methods: { reversedMessage: function () { return this.message.split('').reverse().join('')}}`这样写,但是,如果我需要这个message动态的去改变呢?为了适应复杂的业务逻辑,计算属性cumputed就横空出世了,虽然cumputed和methods可以完成同样的事情,但是copmputed是基于依赖进行缓存的,然而methods需要每一次的去进行计算。我们可以改写这个例子 <div id="app"> <h1>{{ reversedMessage}}"</h1></div>var app = new Vue({ el: '#app', data: { message: 'Hello' }, computed: { // 计算属性的 getter reversedMessage: function () { // `this` 指向 app 实例 return this.message.split('').reverse().join('') } }})我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。此时你可以动态的去修改message的值,可以动态的看到reversedMessage再动态的更新。 其次:计算属性是没有setter的,默认的情况下只有getter 不过你可以添加一个setter进去。例子: <div id="app">{{ allName }}</div>// 用computed实现var vm = new Vue({ el: '#app', data: { her: '尼古拉斯赵四', he: '刘英' }, computed: { allName: function () { get: function () { return this.her+ ' 的女儿是' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.her= names[0] this.he= names[names.length - 1] } } }})现在运行vm.allName时,setter也会执行,vm.her和vm.she也会被更新 ...

June 4, 2019 · 1 min · jiezi

20190604Vue的生命周期

什么是生命周期?每个Vue实例在被创建时都经过了一系列的初始化过程 设置数据监听编译模板将实例挂载到DOM数据变化时更新DOM在这一系列过程中,也会运行一些「生命周期钩子」的函数,用在给开发者在不同阶段添加自己的代码的机会。 「created」钩子,在一个实例被创建后执行代码new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 实例 console.log('a is: ' + this.a) }})// => "a is: 1"不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。 参考 Vue实例通俗的讲:就是在.Vue从加载前到销毁后,这一些系列过程中,有特定的阶段fn可以提供我们开发者来进行操作。 阶段钩子函数方法触发阶段操作beforeCreate创建前组件实例刚被创建,组件属性计算前,数据对象data都未定义,未初始化created创建后组件实例创建完成,属性已经绑定,数据对象data已经定义存在,DOM没为生成,$el未存在beforeMount挂载前Vue实例的$el和data都已经初始化完成,挂在前为虚拟的dom节点,模板还没有渲染到HTML页面上去,data.message未替换。mounted挂载后Vue实例挂载完成,模板已经渲染到HTML中,dota.message成功渲染。这个阶段可以做一些ajax请求操作,mounted在周期中只会执行一次。beforeUpdate更新前当dota更新之前,会触发beforeUpdate方法。updated更新后当data更新完成后,触发updated方法。beforeDestory销毁前Vue组件实例销毁前执行的方法。destroyed销毁后组件销毁后,调用的方法,对data的改变不会再触发函数周,vue实例已经解除事件监听和dom绑定,但dom结构依然存在。 示例import Axios from 'axios' // 这是一个轻量级的ajax库,import是es6模块导入的语法。export default { // 这是一个vue的模块,后面讲奥。 name: 'app', components: { }, data: function () { return { list: [] } }, mounted: function () { // 挂在完成后的生命周期钩子注册。 this.$nextTick(function () { // 等待下一次更新完成后执行业务处理代码。 Axios.get('/api/menulist', {// 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新 params: { } }).then(function (res) { this.list = res.data }.bind(this)) }) }}Vue实例的全局配置silent ...

June 4, 2019 · 1 min · jiezi

2019年4月所遇知识点整理

*注:本文章是在工作过程中所接触的知识点的整理,涉及的东西比价杂乱,如有错误之处,欢迎纠错与指导一, iframe的使用二, flex布局三, 开发环境、测试环境、生产环境的了解四, npm -i 与npm install -s与npm install -d五, 对于已经学好的页面,如何快速的改成自适应页面六, Chrome开发者工具的使用

June 4, 2019 · 1 min · jiezi

前端漫谈3-从-filter-聊到-Promise

前言在学习前端的时候,我总是能听到很多高级词汇,比如今天会聊到的 函数式编程(Functional Programming) & 高阶函数 (Higher-order function) 。但是当你真正的理解什么是 函数式编程 & 高阶函数 的时候,也许会发现,你几乎每天都会用到它,只是你不知道那就是高阶函数 / 函数式编程。 JavaScript 中的函数在 javascript 中,函数是一种值,举个例子: const double = function (x) { return x * 2}我们把一个函数作为值,赋给了变量 double ,这在我们的代码中很常见对吗? 你是不是经常会听到或者看到这样一句话:“在 JavaScript 中函数是一等公民” 粗看很不好理解,但是它的意思很简单:函数和 字符串/number 没有什么不一样,它可以声明为变量,也可以作为参数传入到其他函数中。 什么是高阶函数?什么是高阶函数?其实上一段我们已经说过了,我们可以把函数A作为参数传入到另一个函数B中,那么接收函数作为参数的函数B,就是 高阶函数 ,这只是方便大家理解,高阶函数的定义是: "一个函数的参数是另一个函数,或者一个函数的返回值是另一个函数" 高阶函数的例子filter说到 filter() 你肯定不陌生,他接收一个回调函数作为它的参数,所以它是一个典型的高阶函数,举个例子: 我们有这么一个数组,要筛选出对应 category 为 html&css 的书籍。 const books = [ {name:'gitbook',category:'git'}, {name:'reactbook',category:'react'}, {name:'vuebook',category:'vue'}, {name:'cssbook',category:'html&css'}, {name:'htmlbook',category:'html&css'}, ]传统的写法是这样: let html_css_books = []for (let i = 0; i < books.length; i++) { if(books[i].category === 'html&css'){ html_css_books.push(books[i]) }}console.log(html_css_books)我相信几乎没有人会选择上面的方式,大部分人都会用 filter ...

June 4, 2019 · 2 min · jiezi

年轻人劝你不要做前端

➢ 前端娱乐圈这些年前端有点热闹。 github刷量,vue撕x,版本帝angularJs...... 想要混前端,除了要有足够强的学习力。 还得有一颗天天过山车的心。 ➢ 大家的锅就是你的锅曾经在会议上和领导据理力争过。 领导说: “所有测试的bug都要先指派给前端,前端查清原因后再指给当事人”。 意思是测试人员在手工测试交互流程时 遇到无法登陆,图片没显示,购买不成功,点击没反应等都统一发给前端 有意思的是,站在项目的角度上,这好像是对的,也比较赞成。 站在前端的角度上,就完全成了一个政治正确的背锅侠。 但,所谓的正确,所谓的合理,所谓的流程都是有前提的。 想要马儿跑又想马儿不吃草,想要员工加班又不给加班费。 所以,前端,作为一切的表现层,你个锅,你背定了。 附上一句: 定位bug的时间不会给,定位bug的条件也一般给不了。 前端你自己看着办吧。 ➢ 背锅侠的一生三言两语说的不是很明白。 有些bug是测试直接修改数据库的。 有些bug是偶然性的,无法复现。 有些bug没有条件复测,如征信。 有些bug一看就是后端返回异常了。 还有些bug,纯粹是需求的伪装。 可流程就是流程,不能放水。 你得花式证明这个锅真不是你的,才能继续。 一旦出了未知的问题, 产品找你,ui找你,后台找你,测试找你,老总找你 为了定位或解决问题, 你得找产品,找ui,找后台,找测试,找运维,找...... 也就是说,前端除了做好本职的工作 还要在开发过程中 被动的沟通一些问题主动的定位一些问题让不配合的人配合你挤时间解决一些问题这些问题很多,大多数是似是而非的。 ➢ 切图仔 vs curd一些前端的状态不能一概而论。 不同的公司不同的业务有不同的情况。 9102年,前端不再只是切图仔。 但前端仍然不一定是公司的核心。 问: 你的leader是后端还是前端? 事多人杂,人微言轻 寒冬之下,谁加班,谁先走?

June 3, 2019 · 1 min · jiezi

学习编写高级HTML和CSS代码

性能与组织当能够扎实的理解并编写HTML和CSS这门专业知识。随着网站代码量和流量的增长,另一种新技能也开始发挥作用,这对于开发效率和用户体验都至关重要。我们在了解网站性能和组织的基础知识上还要继续努力。 代码库的组织和体系结构不仅极大的影响开发速度,还极大的影响页面呈现的速度。这两者对用户和开发人员来说都是个大问题。我们需要花时间为代码库设计正确的结构,确定所有不同组件如何协同工作,加快开发效率并创造更好的用户体验。 此外,一些小技巧也可以改善网站的性能。网站性能类似于二八定律,其中20%的优化将带来网站80%的性能提升。 策略与结构改善网站的性能和组织首先围绕如何构思良好的策略和结构的项目代码库结构。具体来说,就是构建良好的目录体系结构和设计模式,并找出项目中重用的公共代码的方法。 样式的结构什么样的组织架构才是最有效的呢? 一般来说,可以遵循以下方法。 这种做法包含集中化的样式分离,还包括根据公共基本样式、用户交互组件、业务逻辑模块。 # Base // 基本样式目录 - normalize.css // 常规的 - layout.css // 布局的 - typography.css // 排版的# Components // 组件样式目录 - alerts.css - buttons.css - forms.css - list.css - nav.css - tables.css# Modules // 模块样式目录 - aside.css - footer.css - header.css上面展示的体系结构包括三个目录,每个目录都具有独立的样式组。 我们的设计目标就是将网站是为一个系统而不是单个页面,代码架构应该反映出这种形态。请注意这里没有涉及到任何页面的特定样式。 Base目录包括了整个网站的布局和排版样式中使用的公共样式和变量。components目录包括了特定用户界面元素的样式,这些元素分为不同的组件文件,比如警告提示和按钮。最后,modules目录包含页面不同部分的样式,这些样式由具体的业务需求来决定。 组件样式纯粹是接口驱动的,与网站的核心业务逻辑无关。然后,模块包括特定于业务逻辑的样式。在HTML中标记模块时,通常在页面使用不同的用户界面组件。例如,页面的侧边栏可能具有在组件样式中定义的列表和按钮样式,而侧边栏所需的其他样式则从模块样式继承。样式的分离反映了程序员经过深思熟虑的设计和样式被共享和重用的能力。 以这种方式组织样式的策略并不是全新的。并且之前已经在不同的CSS方法中提到过,包括面向对象的CSS,OOCSS以及用于CSS的可扩展性和模块化架构(SMACSS)。这些方法对架构以及如何使用样式来说有着自己独特的方法。 面向对象的CSS面向对象的CSS方法是由Nicole Sullivan在为大型网站编写样式的工作中开创的。面向对象的CSS(`Object Oriented CSS`)确定了两个基本原则,这些原则将有助于构建具有强大架构和合理代码量的可弹性网站。 这两个原则包括: 整体结构与皮肤的分离从容器中分离内容整体结构与皮肤的分离包括从网站的主题中抽象出元素的布局,模块的结构应该是透明的,允许继承和显示其他样式而不会发生冲突。最常见的是这需要实体网格和布局结构,以及精心设计的模块。 将内容与容器分离涉及移除父元素嵌套子元素的依赖项。无论其父容器是什么,标题应该看起来都是一样的。为此,元素需要继承默认样式,然后根据需要使用多个类进行扩展。 HTML <div class="alert alert-error"> <p class="msg">......</p></div>CSS .alert {....}.alert-error {...}.msg {...}面向对象的CSS提倡构建组件库,保持灵活性,并使用网格。 这些都是很好的基本规则,它们可以帮你避免每次向网站添加新页面和新功能时都需要添加额外的样式。 ...

June 3, 2019 · 2 min · jiezi

将函数式进行到底用-Hooks-武装组件-TXD-前端月刊-201905-期

【阿里云 TXD 前端月刊】- 热门前端技术快报,聚焦业界新视界;五月清风徐来,跟我们一起来看一看新的风向即将吹向何方,前端的技术力量又将影响哪些新的领域。 欢迎 订阅 & 投稿编辑:墨止审稿:尹挚 学习专栏 《深入浅出 React Hooks》React 16.8 了,还不了解 React Hooks?!想做前端极客,想写出酷酷的代码,那就赶紧跟 @x-cold 一起来学习最新的 Hooks 知识吧!原文章看这里,一步步进入 React Hooks 的世界。 《一个合格的中级前端工程师必须要掌握的 28 个 JavaScript 技巧》对在毕业季还在找工作的同学,可以说很实用的,如果能全部掌握这些技巧,拿到几个offer应该是没有问题的,当然要注意平时的积累,能力要全面。 《Node.js 技术栈》这是作者从事 Node.js Developer 以来的学习历程,旨在为大家提供一个较详细的学习教程,侧重点更倾向于 Node.js 服务端所涉及的技术栈,如果本文能为您得到帮助,请给予支持! 新闻快报 Github 重磅推出包管理仓库 现在使用 Github,你的团队可以发布公共/私有的包到 Github 提供的包管理仓库,目前包含的类型有 Npm, Docker, Maven, NuGet, RubyGems等,更多的类型还在继续添加中。而且该托管服务是完全免费的。[[戳????传送门]](https://github.com/features/p... Flutter 实现 Web 访问,新增桌面和嵌入式的应用场景2019 谷歌 I/O 大会上,Flutter Team 公布了 Flutter 可进行 Web 访问、提供自定义图像分类模型等诸多新特性,并且可以应用在桌面系统及嵌入式设备中,给未来提供了更多的想象空间,展现了 Flutter 从移动 UI 到制霸多平台的雄心。Flutter for Web 已发布第一个预览版本,可以查看官网信息进行尝鲜,体验惊喜 [[惊喜门]](https://flutter.dev/web)。在 Facebook 年度开发者大会上宣布了会稳定支持 RN,但是 RN 还要继续步履蹒跚吗? ...

June 3, 2019 · 2 min · jiezi

jQuery源码解析之trigger

一、$().trigger()和$().triggerHandler() 的作用和区别 (1)trigger("focus") 触发被选元素上的指定事件(focus)以及事件的默认行为(比如表单提交);triggerHandler(xxx) 不会引起事件(比如表单提交)的默认行为 (2)trigger(xxx) 触发所有匹配元素的指定事件;triggerHandler(xxx) 只触发第一个匹配元素的指定事件 (3)trigger(xxx) 会冒泡;triggerHandler(xxx) 不会冒泡 二、$().trigger() $("#one").on("click",function () { console.log("one被点击了") }) $("#one").trigger('click')作用:看 一、(1) 源码: //触发type事件,data是自定义事件的额外参数 //源码9014行 trigger: function( type, data ) { return this.each( function() { jQuery.event.trigger( type, data, this ); } ); },解析:本质是调用的jQuery.event.trigger()方法 三、jQuery.event.trigger() 源码: //源码8850行 //type, data, this trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, //冒泡路径数组 eventPath = [ elem || document ], //判断event是否有'type'属性,有则取event.type,没有则取event type = hasOwn.call( event, "type" ) ? event.type : event, //同上 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; //当前元素 cur = lastElement = tmp = elem = elem || document; //文本内容或者是注释则不触发事件 // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } //由focus/blur转变到focusin/out,现在不触发focus/blur事件 // focus/blur morphs to focusin/out; ensure we're not firing them right now //rfocusMorph:focusin focus|focusout blur if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } //可以不看 if ( type.indexOf( "." ) > -1 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split( "." ); type = namespaces.shift(); namespaces.sort(); } //onclick,onfocus等等 ontype = type.indexOf( ":" ) < 0 && "on" + type; //event一般是字符串,所以一般是undefined //获取对应type类型的jQuery.event // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : //click,false new jQuery.Event( type, typeof event === "object" && event ); // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) //onlyHandlers一般为undefined //3 event.isTrigger = onlyHandlers ? 2 : 3; //"" event.namespace = namespaces.join( "." ); //null event.rnamespace = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : null; //清空event以防它被复用 // Clean up the event in case it is being reused event.result = undefined; //target属性为目标DOM元素 //我们一般取的e.target.value,也正是目标元素的值 if ( !event.target ) { event.target = elem; } //复制data并预先考虑event,创建handler集合 // Clone any incoming data and prepend the event, creating the handler arg list //简单点,就是 data=[event] data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); //赋值有需要特殊处理的type // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } //提前确定事件冒泡的路径 // Determine event propagation path in advance, per W3C events spec (#9951) //冒泡至document,再到window;关注全局的ownerDocument // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { //click bubbleType = special.delegateType || type; //clickclick //如果不是focus/blur的话,获取它的父元素 if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } //for循环的语法(a; b; c) //a在单次循环开始前执行 //b是单次循环的条件(这里即cur存在) //c是单次循环结束后执行 for ( ; cur; cur = cur.parentNode ) { console.log(cur,'cur8967') //将目标元素的祖先元素都push进数组 eventPath.push( cur ); tmp = cur; } //只有当tmp是document时,将window加上 // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === ( elem.ownerDocument || document ) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } //触发冒泡机制 // Fire handlers on the event path i = 0; //e.stopPropagation()这是阻止冒泡的方法 //isPropagationStopped() 检查是否阻止冒泡了,返回boolean while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { lastElement = cur; event.type = i > 1 ? bubbleType : special.bindType || type; console.log(i,'lastElement8987') // jQuery handler //( dataPriv.get( cur, "events" ) || {} )[ event.type ] // 先判断cur元素的events是否有绑定click //dataPriv.get( cur, "handle" ) //再获取cur元素的click事件处理程序 //获取目标元素的触发事件的事件处理程序 handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && //获取触发事件的处理程序 dataPriv.get( cur, "handle" ); /*让冒泡元素执行handle,这行代码是触发冒泡机制的关键*/ /*在执行click事件的处理程序后,自然就会执行e.stopPropagation(), * 从而让event.isPropagationStopped()=true*/ if ( handle ) { handle.apply( cur, data ); } //接下来处理原生的事件及处理程序 //click为onclick // Native handler handle = ontype && cur[ ontype ]; //如果有绑定原生onclick事件的话 if ( handle && handle.apply && acceptData( cur ) ) { //执行onclick事件的处理程序 event.result = handle.apply( cur, data ); if ( event.result === false ) { //阻止元素的默认行为(如提交表单submit) event.preventDefault(); } } } event.type = type; //如果没有人阻止默认行为的话,现在就阻止 /*比如触发<a>的click事件,但不会跳转*/ // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( ( !special._default || special._default.apply( eventPath.pop(), data ) === false ) && acceptData( elem ) ) { //在目标上,用重复的命名调用原生DOM事件,会在window层面上影响其他元素 // Call a native DOM method on the target with the same name as the event. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { //当我们触发FOO事件(如click)时,不要重复触发它的onFOO(onclick)事件 // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; //将jQuery对象的onclick属性置为null //比如<a>就不会去跳转了 if ( tmp ) { elem[ ontype ] = null; } //阻止重复触发同样的事件,因为我们已经把它冒泡了 // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; //如果已经执行阻止冒泡了,则为window添加阻止冒泡的监听 if ( event.isPropagationStopped() ) { lastElement.addEventListener( type, stopPropagationCallback ); } console.log(elem[ type ],'type9053') //执行type事件 elem[ type ](); if ( event.isPropagationStopped() ) { lastElement.removeEventListener( type, stopPropagationCallback ); } jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; },解析: ...

June 3, 2019 · 7 min · jiezi

Nodejs-事件循环

Node.js事件循环 Node.js 是单进程单线程应用程序,但是因为V8引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。Node.js 几乎每一个API都支持回调函数。Node.js 基本上所有都事件机制都是通过观察者模式实现Node.js 单线程类似进入一个while(true)事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。 事件驱动程序Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。 当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。 这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO) 在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。 //引入eventsconst events = require('events')// 创建eventEmitter对象const eventEmitter = new events.EventEmitter();// 创建时间处理程序 var connectHandler = function connected (){ console.log('连接成功') // 出发data_received事件 eventEmitter.emit('data_received')}// 绑定connection事件处理程序eventEmitter.on('connection', connectHandler)// 使用匿名函数绑定data_received事件eventEmitter.on('data_received',() => { console.log('数据接收成功。')})// 触发connection事件eventEmitter.emit('connection')console.log('程序执行完毕') Node应用程序是如何工作的 ?? 在Node应用程序中,执行异步操作都函数将回调函数作为最后一个参数,回调函数接收错误对象做一个第一个参数。 const fs = require("fs")fs.readFile('input.txt',(err,data) => { if(err) { console.log(err) }else{ console.log(data.toString()) }})console.log("程序执行结束!")这段代码,input.txt文件我给删除了,所以在执行过程中,发生错误,错误err对象就会输出错误信息。

June 3, 2019 · 1 min · jiezi

献礼6181700集前端视频教程免费看

一年一度“618”,岁岁年年狂剁手。随着网购时代的到来,越来越多的剁手节让大家谜一样的沉浸其中,无法自拔,什么618、双十一、双十二、双旦等等年前定下的攒钱目标还没开始就要宣告结束这就是人生不得不承认的事实 然而比618来得更猝不及防的是各大电商的营销文案一个比一个精彩一个比一个诱惑 所谓清空购物车一时爽,事后剁手火葬场小妙深知购物狂+剁手党的疯狂也深知这样一个“节日”对自媒体人来说意味着什么当然是拼文案拼营销拼姿势啊反正,钱是越花越少的经验是越攒越多的精彩文案给你摆在这这个手你剁不剁? 小妙作为剁手大军的一员,深深了解大家的纠结与痛苦而我今年就不一样了,不但不剁手,还可以免费学到知识 免费看?免费?是的,你没看错,真的免费!!! 即日起,注册妙味视频平台的新用户,即可获得价值239元包含1700+集的前端优质视频教程的7天观看权限无论你是在学布局还是在学小程序,亦或是在学Vue、react,这里应有尽有,爱学习的你,还没心动么,心动了的话就赶快行动起来吧 活动详情见海报:

June 3, 2019 · 1 min · jiezi

关于animation和betterscroll遇到的问题

最近做了一个项目,不是蛮复杂,但是有些知识点可以分享下,先上图 因为4M的限制 所以图片有点模糊,大家凑合着看哈,首先说到这个刷新按钮 1、刷新按钮 添加旋转动画很简单 @-webkit-keyframes rotate{ from {transform: rotate(0deg);}to {transform: rotate(360deg);}} animation:rotate 0.8s linear infinite; 这样就可以实现 按钮的旋转了 但接下来会有问题:1、旋转的过程中其他的元素变得模糊 2、还有还会引起父级的高度变化 解决方案: transform:translate3d( 0, 0, 0);z-index: 1; 亲测有效! 2、局部滚动better-scroll 用法API参考:http://ustbhuangyi.github.io/... 说说遇到的问题: (1)我的项目里面,点击筛选按钮,会有一个侧边栏的列表展示,所以我进页面就请求列表,生成筛选的列表,并创建了scroll 对象,问题就是 当我显示和隐藏侧边栏的列表的时候,scroll因为scrollerHeight丢失,而会出现卡顿前几秒不滚动的现象。 针对这个问题:我想到的是,请求数据不在一进页面而是 点击按钮以后 请求接口 创建scroll对象并且在 this.$nextTick 里面创建 this.$nextTick(()=>{ this.sideBarScroll = new BScroll("#sideBar_scroller",{ scrollY: true, bounce:false, click: true });});(2)上述那么做了以后会发现一个问题,每次显示侧边栏就创建一个scroll对象 肯定是不行的,肉眼可以看到的问题时就 会有多个滚动条累计在一起 也就是生成了多个scroll对象 解决方案: this.$nextTick(()=>{ if(!this.sideBarScroll){ this.sideBarScroll = new BScroll("#sideBar_scroller",{ scrollY: true, scrollbar:{ fade:false, interactive:false }, bounce:false, click: true }); } else{ this.sideBarScroll.refresh(); } })好啦 先分享这么多,希望对大家有帮助! ...

June 3, 2019 · 1 min · jiezi

使用ReactElectronDvaWebpackNodejsWebsocket快速构建跨平台应用

目前Electron在github上面的star量已经快要跟React-native一样多了这里吐槽下,webpack感觉每周都在偷偷更新,很糟心啊,还有Angular更新到了8,Vue马上又要出正式新版本了,5G今年就要商用,华为的系统也要出来了,RN还没有更新到正式的1版本,还有号称让前端开发者失业的技术flutter也在疯狂更新,前端真的是学不完的 回到正题,不能否认,现在的大前端,真的太牛了,PC端可以跨三种平台开发,移动端可以一次编写,生成各种小程序以及React-native应用,然后跑在ios和安卓以及网页中 , 这里不得不说-------京东的Taro框架 这些人 已经把Node.js和webpack用上了天对webpack不熟悉的,看我之前的文章 ,今天不把重点放在webpack 欢迎关注我的专栏 《前端进阶》 都是百星高赞文章 手写React优化版脚手架前端性能优化不完全手册手写vue脚手架本文源码git仓库地址先说说Electron官网介绍:使用 JavaScript, HTML 和 CSS 构建跨平台的桌面应用 ,如果你可以建一个网站,你就可以建一个桌面应用程序。 Electron 是一个使用 JavaScript, HTML 和 CSS 等 Web 技术创建原生程序的框架,它负责比较难搞的部分,你只需把精力放在你的应用的核心上即可。什么意思呢?Electron = Node.js + 谷歌浏览器 + 平常的JS代码生成的应用,最终打包成安装包,就是一个完整的应用Electron分两个进程,主进程负责比较难搞的那部分,渲染进程(平常的JS代码)部分,负责UI界面展示两个进程之间可以通过remote模块,以及IPCRender和IPCMain之间通信,前者类似于挂载在全局的属性上进行通信(很像最早的命名空间模块化方案),后者是基于发布订阅机制,自定义事件的监听和触发实现两个进程的通信。Electron相当于给React生成的单页面应用套了一层壳,如果涉及到文件操作这类的复杂功能,那么就要依靠Electron的主进程,因为主进程可以直接调用Node.js的API,还可以使用C++插件,这里Node.js的牛逼程度就凸显出来了,既可以写后台的CRUD,又可以做中间件,现在又可以写前端。谈谈技术选型使用React去做底层的UI绘制,大项目首选React+TS状态管理的最佳实践肯定不是Redux,目前首选dva,或者redux-saga。构建工具选择webpack,如果不会webpack真的很吃亏,会严重限制你的前端发展,所以建议好好学习Node.js和webpack选择了普通的Restful架构,而不是GraphQL,可能我对GraphQL理解不深,没有领悟到精髓在通信协议这块,选择了websoket和普通的http通信方式因为是demo,很多地方并没有细化,后期会针对electron出一个网易云音乐的开源项目,这是一定要做到的先开始正式的环境搭建 config文件放置webpack配置文件server文件夹放置Node.js的后端服务器代码src下放置源码main.js是Electron的入口文件json文件是脚本入口文件,也是包管理的文件~开发模式项目启动思路:先启动webpack将代码打包到内存中,实现热更新再启动Electron读取对应的url地址的文件内容,也实现热更新设置webpack入口 app: ['babel-polyfill', './src/index.js', './index.html'], vendor: ['react'] } 忽略Electron中的代码,不用webpack打包(因为Electron中有后台模块代码,打包就会报错)externals: [ (function () { var IGNORES = [ 'electron' ]; return function (context, request, callback) { if (IGNORES.indexOf(request) >= 0) { return callback(null, "require('" + request + "')"); } return callback(); }; })() ] 加入代码分割optimization: { runtimeChunk: true, splitChunks: { chunks: 'all' } },设置热更新等 plugins: [ new HtmlWebpackPlugin({ template: './index.html' }), new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), ], mode: 'development', devServer: { contentBase: '../build', open: true, port: 5000, hot: true },#### 加入babel ...

June 3, 2019 · 6 min · jiezi

前端漫谈2-从-Dva-的-Effect-到-Generator-Promise-实现异步编程

你能学到什么如何使用 Generator + Promise 实现异步编程异步编程的原理解析前言结合 上一篇文章 ,我们来聊聊 Generator 基础原理说到异步编程,你想到的是async 和 await ,但那也只是 Generator 的语法糖而已。dva 中有一个 Effect 的概念,它就是使用 Generator 来解决异步请求的问题,我们也来聊一聊 Generator + Promise 如何异步编程: 开始之前,我们需要了解一些基本的概念: Generator作为 ES6 中使用协程的解决方案来处理异步编程的具体实现,它的特点是: Generator 中可以使用 yield 关键字配合实例 gen 调用 next() 方法,来将其内部的语句分割执行。 简言之 : next() 被调用一次,则 yield 语句被执行一句,随着 next() 调用, yield 语句被依次执行。Promise表示一个异步操作的最终状态(完成或失败),以及其返回的值。参考Promise-MDN所以,异步编程使用 Generator 和 Promise 来实现的原理是什么呢? 因为 Generator 本身 yield 语句是分离执行的,所以我们利用这一点,在 yield 语句中返回一个 Promise 对象首次调用 Generator 中的 next() 后, 假设返回值叫 result ,那么此时 result.value 就是我们定义在 yield 语句中的 Promise 对象注意:在这一步,我们已经把原来的执行流程暂停,转而执行 Promise 的内容,已经实现了控制异步代码的执行,因为此时我们如果不继续执行 next() 则 generator 中位于当前被执行的 yield 后面的内容,将不会继续执行,这已经达到了我们需要的效果 ...

June 2, 2019 · 2 min · jiezi

h5-调用摄像头拍照和录像

<input type="button" title="开启摄像头" value="开启摄像头" onclick="getMedia()" /> <video id="video" width="500px" height="500px" autoplay="autoplay"></video><canvas id="canvas" width="500px" height="500px"></canvas><button id="snap" onclick="takePhoto()">拍照</button>function getMedia() { let constraints = { video: {width: 500, height: 500}, audio: true }; //获得video摄像头区域 let video = document.getElementById("video"); //这里介绍新的方法,返回一个 Promise对象 // 这个Promise对象返回成功后的回调函数带一个 MediaStream 对象作为其参数 // then()是Promise对象里的方法 // then()方法是异步执行,当then()前的方法执行完后再执行then()内部的程序 // 避免数据没有获取到 let promise = navigator.mediaDevices.getUserMedia(constraints); promise.then(function (MediaStream) { video.srcObject = MediaStream; video.play(); }); }function takePhoto() { //获得Canvas对象 let video = document.getElementById("video"); let canvas = document.getElementById("canvas"); let ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, 500, 500); } 来源:CSDN 原文:https://blog.csdn.net/lishund... ...

June 1, 2019 · 1 min · jiezi

小站长对抗黑站的心路历程

先说介绍一下,我最早学的是前端技术,自己自学的,会了基本制作静态页面后,就开始学SEO技术,看遍了各个培训机构的教学视频,也花了钱加入了一个培训机构的会员,慢慢通过实践建站,知道了如何做好SEO,如何一步步把网站访问量做起来。 在各个培训机构中,对于建网站过程都说的很简单,尤其管理云服务器,基本就是一笔带过,教你安装使用一个单机版的linux面板,就完事了。就是这个细节不足,给我以后网站被黑埋下了祸根,对于linux服务器安全防护,很多站长,包括SEO培训机构都没怎么重视,都是教给你如何做好SEO技术,其他的一概不管。 学好SEO后搭建个小网站,购买了一个1核1G的百度服务器,因为听各个培训机构说用百度服务器收录好点,所以一直就用百度服务器。因为是小站所以访问量开始每天在几百pv,由于我会前端技术也做了MIP技术,手机移动端打开速度快。慢慢排名爬上去了,权重有了,排名有了,麻烦就来了,基本互联网排名好的小站都受到过黑客攻击,都是些赌博网站,给你加恶意跳转,修改网页内容等手段,到这时很多站长才意识到该做服务器安全了。 我自己的经验之谈,开始寻找很久的解决办法,最后还是自己找到的主要原因,首先是网站本身的CMS程序,我更换了网站程序,服务器里只有静态页面,后来发现还是被黑。然后就发现是服务器安装的linux面板,安全防护上根本就是窗户纸,换了3个单机版linux面板,也购买了他们的收费插件,但还是被黑,这时候就不敢再使用单机版linux面板了,被黑修复后,就一直寻找解决办法。2019年年初,我发现了旗鱼云梯网站,发现是云端平台化的linux运维工具,抱着尝试的心态,购买了一个服务器,通过平台上建站使用了一个月,发现网站很稳定,通过查看平台自带的WAF防火墙和本地安全防护工具,大量的攻击都给拦截了,可视化这点给满分。通过长时间使用,我觉得该和SEO站长推荐这个平台,首先是B/S构架云端操作,通过QQ或微信就能够登录使用,老式的单机版linux面板还需要记一大串地址,然后是可以批量化管理云服务器,我在阿里云、百度云、腾讯云的云服务器都可以同时管理,实现了批量化操作的方式。旗鱼云梯在SEO方面做了大量的适配,错误页面404设置多种风格。网站301跳转,帮助站长实现权重统一性。Sitemap功能,利于蜘蛛抓取,日志查看,可以看到每天的蜘蛛访问量,等等功能,是新手站长和老站的最好工具,这点现在这些单机版linux面板就完全没有。推荐平台化linux面板旗鱼云梯,各位站长可要抓紧入驻,避免自己的网站还是裸奔,免费的安全防护就是旗鱼云梯平台特色,就这点我觉得比较方便实惠好用。

June 1, 2019 · 1 min · jiezi

译-在你学习-React-之前必备的-JavaScript-基础

原文地址:JavaScript Basics Before You Learn React原文作者: Nathan Sebhastian写在前面为了不浪费大家的宝贵时间,在开头申明一下,这篇文章针对的阅读对象是:没有写过 React 或者刚刚才接触 React 并且对于 ES6 的语法不太了解的同学,这是一篇基础入门的文章,在一开始我并没有准备翻译一篇这样的基础文章,但是在阅读完全文之后,我想起自己刚开始学习 React 时的迷茫,ES6 有那么多,我需要掌握多少呢?对于一个急于上手 React 写代码的人来说,这篇文章告诉你最基本要掌握的知识,让你快速的写起来。但是后期的提高,仍旧需要去夯实 Javascript 的基础。 前言在理想的状态下,你可以在深入了解React之前了解 JavaScript 和Web 开发的所有知识。 不幸的是,我们生活在一个不完美的世界,所以在 React 之前把所有的JavaScript 都咀嚼一遍只会让你举步维艰。 如果你已经拥有一些 JavaScript 经验,那么在 React 之前你需要学习的只是实际用于开发 React 应用程序的 JavaScript 功能。 在学习 React之前你应该学会的JavaScript 的知识点: ES6 类使用 let / const 声明变量箭头函数解构赋值Map 和 filterES6 模块系统这是你将在 80% 的时间内使用的20% 的 JavaScript 新特性,因此在本文中,我将帮助你学习所有这些特性。 创建 React 应用程序的探索开始学习 React 的常见情况是运行 create-react-app 包,它会设置运行 React 所需的一切。 该过程完成之后,打开 src / app.js 这里给我们展示了整个应用程序中唯一的 React 类: ...

June 1, 2019 · 5 min · jiezi

老生常谈跨域问题

前段时间在网上跟一个大厂据说很NB的同行大佬聊天,然后大佬问了我一个问题,“在实际生产中前端怎么解决跨域问题” 我当时就回答说我们目前的状况是需要服务端做一些配合解决的,然后大佬很不满意的暗示了我一下JSONP用过吗?我当时就觉得很不可思议,实际生产中就只有get请求吗?而且这玩意儿在实际生产中都基本不用的,我开始有点怀疑我是不是掉队了,所以今天大概梳理下这块的知识点。 浏览器在请求不同域的资源时,会因为同源策略的影响请求不成功,这就是通常被提到的“跨域问题”。作为前端开发,跨域经常遇到,我们通常所说的JS跨域,指的是在处理跨域请求的过程中,技术面会偏浏览器端较多一些,那什么是跨域呢?JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象,当协议、子域名、主域名、端口号,其中的任意一个不同的时候都是不同的域,那也就是算做跨域。请求跨域的时候并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了,正是因为同源策略的限制,同源策略的要求是协议、域名、和端口号都完全一致才可以进行正常的通信。 需要说明的几个点:1.如果是协议和端口造成的跨域问题,前端是无能为力的。2.在跨域问题上,域只是通过访问URL的头部(.com或者.cn以及之前部分)来识别的,而不是根据域名对应的IP地址是否相同去判断的。3.在实际生产中JSONP的局限性很大,基本上不会去考虑,使用几率很小。 目前我们的状况是在服务器端头部增加配置: header( "Access-Control-Allow-Origin:*" );header( "Access-Control-Allow-Methods:POST,GET" );各位路过的大佬有什么优秀的方案吗?请不吝赐教

May 31, 2019 · 1 min · jiezi

Canvas2D基础

Canvas2D基础什么是Canvas<canvas>是H5中最受欢迎的元素,在页面上划出一片区域,利用JS在上面画出图形,起初由Apple公司提出,各大浏览器厂商也对其做了不同程度上的实现。canvas中规定了了2D context和3D context(WebGL),目前绝大部分浏览器支持2D context。WebGL的发展还比较缓慢。 基本使用1、toDataURL() 将画好的图像输出为图片 //get data URI of the imagevar imgURI = drawing.toDataURL("image/png");//display the imagevar image = document.createElement("img");image.src = imgURI;document.body.appendChild(image);2、原点是基于canvas元素左上角3、2D Context的两个基本绘画操作 fill and stroke Rectangles(矩形)1、fillRect() context.fillRect(10, 10, 50, 50);//draw a blue rectangle that’s semi-transparentcontext.fillStyle = "rgba(0,0,255,0.5)";context.fillRect(30, 30, 50, 50);2、strokeRect() //draw a red outlined rectanglecontext.strokeStyle = "#ff0000";context.strokeRect(10, 10, 50, 50);//draw a blue outlined rectangle that’s semi-transparentcontext.strokeStyle = "rgba(0,0,255,0.5)";context.strokeRect(30, 30, 50, 50);3、clearRect() //draw a red rectanglecontext.fillStyle = "#ff0000";context.fillRect(10, 10, 50, 50);//draw a blue rectangle that’s semi-transparentcontext.fillStyle = "rgba(0,0,255,0.5)";context.fillRect(30, 30, 50, 50);//clear a rectangle that overlaps both of the previous rectanglescontext.clearRect(40, 40, 10, 10);Drawing Paths1、如何画一个表盘 ...

May 31, 2019 · 2 min · jiezi

APICloud发布低代码开发平台

云原生的出现,致使传统IT模式正在集中向云架构、云开发转型,其中在企业业务的互联网化、数字化进程中尤为突出,并衍生出“敏捷开发”、“快速迭代”的刚性需求。面对双模IT,如何打造全新的IT团队与模式?并更好的满足由业务部门发起庞大且零散的IT需求,成为众多CIO与CTO的巨大挑战。在复杂的供需环境中,低代码开发平台正在快速的出现和普及。 与此同时,效率一直是企业生产力水平的重要标杆,而效率的服务对象则是需求;数字化时代的下半场,能否突破传统效率边界,甚至决定着一个企业的生死存亡;区别于企业IT部门主导需求的传统模式,互联网和云的背景下更多是由业务部门自主发起需求,IT部门提供技术与服务,这样的模式更适用于互联网的快速打法,而供需关系的转化,则使低代码开发平台成为了颠覆传统效率的利器,或将企业IT生产力引领至全新的高度。 5月23日,APICloud新产品媒体发布会如约而至,发布会以“探索人效革命” 为主题,依托本次公布的低代码开发平台与新产品,APICloud将进一步对To B行业的IT生产力进行赋能,全面开启低代码时代新篇章。 活动中,APICloud创始人兼CEO刘鑫发布了全新的低代码开发平台,他介绍道:“所谓“低代码开发平台”,是指那些无需编码或通过少量代码就可以快速生成应用程序的工具,其一方面可以降低企业应用开发人力成本,另一方面可以将原有数月甚至数年的开发时间成倍缩短,从而帮助企业实现降本增效的价值。”在此过程中低代码展现出与企业创新需求高度匹配的特性,使用低代码开发平台构建企业级应用,逐渐成为提升IT生产力的重要趋势;为此,APICloud通过多年技术创新与数据积累,打造的低代码开发平台也顺势而生。 基于APICloud低代码开发平台,刘鑫详细介绍了全新的IT生产力工具“Plus Mode”,这款涵盖需求分析、产品原型、UI设计、前端开发、后端开发为一体的组合型工具,依托APICloud低代码开发平台而建,将可视化界面与拖拽式产品进行无缝结合,Plus Mode以“提升人效”为核心理念,凭借APICloud丰富的行业案例数据库与敏捷的低代码开发能力为支撑,帮助企业IT项目快速落地。 产品、UI、开发本为IT项目环环相扣的组成部分,Plus Mode为IT项目中每个角色提供工具的同时,大量前置环节的工作量通过大数据复用进行实现,从而为每个环节提升30%至60%的工作效率;对于已上线的产品,Plus Mode也表现出十分融合的友好度,可根据数据需求直接生成API接口,快速打通新、老产品功能与数据的调用;凭借门槛低、上手快的特性,Plus Mode可帮助企业快速训练出一支具备高效协作能力的IT项目团队。 Plus Mode的核心行业数据库由APICloud平台多年积累而成,根据不同行业、不同功能、不同应用场景进行梳理,目前包含11个行业,63类功能模块,Plus Mode的行业数据库与产品工具均以公有云形式提供,IT团队可随时随地进行协作,行业数据库也会基于互联网创新产品的不断迭代而进行实时更新。 为了更好地贯穿“人效”理念,此次发布会APICloud提出了一套线上+线下的组合拳战术,除了生产力工具,APICloud COO 郭琪妹还发布了全新概念的共享办公服务,不同于传统共享办公模式,该服务主要面向于使用APICloud平台的技术团队以及创业团队,APICloud通过线下联合办公的模式,对入驻的团队进行技术赋能,加速技术变现能力,同时以此加强IT项目的协作效率,该业务是APICloud北京、重庆双总部战略的延伸,两地的技术团队与创业团队均可申请入驻。 为了进一步完善开发者生态建设,打通移动应用从开发至上线的全部链条,APICloud联合腾讯云推出更适于移动应用的云解决方案,APICloud用户可直接在平台中选购腾讯云的优质服务,并享受一定优惠返利。 当今企业级IT建设正不断向移动化、模块化、标准化、可视化方向发展,低代码平台在提升人效的同时,提供了全新的通用性解决方案,此次APICloud发布的新产品正是这一解决方案的延伸,对于未来,APICloud将持续在行业数据、技术创新以及效率工具领域进行布局,进一步探索互联网产业的效率变革。

May 31, 2019 · 1 min · jiezi

H5-深度解析

先科普一下,HTML5并不是一项技术,而是一个标准。所以其实要么我们是作为理论派讨论HTML5标准,要么是作为实践派讨论HTML5标准在某浏览器的应用。H5 实际上是一个解决方案,一个看起来酷炫的移动端onepage网站的解决方案移动端的适配方案rem适配 优点: 1. 引用简单,布局简便 2. 根据设备屏幕的DPR,自动设置最合适的高清缩放 3. 有效解决移动端真实1px问题但是绝不是每个地方都要用rem,rem只适用于固定尺寸!在这里rem也是一种单位,并且可以为咱们的布局提供无线的变化,根据开发者的设定,它将会在不同的分辨率屏幕上展示不同的色彩。这个单位的定义和em类似,不同的是em是相对于父元素,而rem是相对于根元素<html>,当我们指定一个元素的font-size为2rem的时候,也就说这个元素的字体大小为根元素<html>字体大小的两倍,如果html的font-size为12px,那么这个2rem的元素font-size就是24px。 html {font-size: 12px;} h1 { font-size: 2rem; } 2*12 = 24px html {font-size: 16px;} h1 { font-size: 2rem; } 2*16 = 32px单位定义特点remfont size of the root element以根元素字体大小为基准emfont size of the element以父元素字体大小为基准当然上边只是我们介绍rem简单的示例,具体运用到项目中我还需进行rem的计算,根据根元素的font-size通过Javascript来计算我们的rem单位适配选取一个设备宽度作为基准,设置其根元素大小,其他设备根据此比例计算其根元素大小。比如使得iPhone6根元素font-size=16px。设 备设备宽度根元素font-size/px宽度/remiPhone5320计算-iPhone63751623.4375iPhone73751623.4375iPhone7plus414计算-根元素fontSize公式:width/fontSize = deviceWidth/deviceFontSize下方为动态计算 (function flexible (window, document) { var docEl = document.documentElement var dpr = window.devicePixelRatio || 1 // adjust body font size function setBodyFontSize () { if (document.body) { document.body.style.fontSize = (12 * dpr) + 'px' } else { document.addEventListener('DOMContentLoaded', setBodyFontSize) } } setBodyFontSize(); // set 1rem = viewWidth / 10 function setRemUnit () { var rem = docEl.clientWidth / 10 console.log(rem) docEl.style.fontSize = rem + 'px' } setRemUnit() // reset rem unit on page resize window.addEventListener('resize', setRemUnit) window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() } }) // detect 0.5px supports if (dpr >= 2) { var fakeBody = document.createElement('body') var testElement = document.createElement('div') testElement.style.border = '.5px solid transparent' fakeBody.appendChild(testElement) docEl.appendChild(fakeBody) if (testElement.offsetHeight === 1) { docEl.classList.add('hairlines') } docEl.removeChild(fakeBody) }}(window, document))上方的代码则是本人经常使用的rem计算方法,我们可以根据我们自己的需求设定基于多大的屏幕以及rem的换算倍率等 ...

May 31, 2019 · 2 min · jiezi

小程序swiper轮播CSS3动画及跳转到指定swiperitem实现思路

需要解决的问题近几日一直在看怎样制作微信小程序的swiper轮播图。因为我既需要生成小程序的代码,也需要生成H5版代码,如果编写两套效率会比较低下,所以选择了uni-app。 uni-app已经在基础组件swiper中已经直接支持了轮播动画。 我主要需要解决的是以下几个问题: ①在swiper中怎样添加css3流行的animate.css动画。②添加好后如果滑动了轮播图,怎样能保证下一屏的动画不自动播放。③怎样能实现轮播图的无限循环播放。④怎样能实现,当用户点击一个按钮之后,可以跳转到指定的swiper-item中。也就是跳转到指定的屏。⑤小程序和H5版的代码会生成一个头部,在H5版中需要隐藏掉导航栏。以下就是我整个制作的思路过程,仅供参考。另外,代码是uni-app开发,所以在小程序中和H5中测试都没有问题。另外为了方便小程序开发同学了解,会提供小程序版代码和uni-app代码供参考。 代码实现在H5开发中经常使用的就是animate.css。在微信中自然是支持的,因为微信会对上传的小程序有大小限制,所以这里我使用了一个极简化的animate.css,其中删掉了很多-webkit-animation开头的css3。因为我们只需要在小程序和H5中运行,这样做影响也不大。如果需要的话,可以从下面的代码中获取。 我们先来看下代码: <template> <view class="content"> <button type="primary" @tap="goChange">跳转到第二屏</button> <swiper class="content-swiper" :vertical="true" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="1000" @change="changeSwiper" @animationfinish="changeFinish" :current-item-id="item_id" circular="true"> <swiper-item item-id="slide0"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_0"></image> </view> </swiper-item> <swiper-item item-id="slide1"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_1"></image> </view> </swiper-item> <swiper-item item-id="slide2"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_2"></image> </view> </swiper-item> <swiper-item item-id="slide3"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_3"></image> </view> </swiper-item> </swiper> </view></template><script> export default { data() { return { item_id: 'slide2', animate_0: 'animated swing', animate_1: '', animate_2: '', animate_3: '' } }, onLoad() { }, methods: { changeSwiper(event){ // 清空除了当前swiper以外的所有动画 let current = event.detail.current; // 当前页下标 this.item_id = 'slide'+current; // 这里必须记录,否则只能跳转一次 switch (current){ case 0: this['animate_1'] = this['animate_2'] = this['animate_3'] = ''; break; case 1: this['animate_0'] = this['animate_2'] = this['animate_3'] = ''; break; case 2: this['animate_0'] = this['animate_1'] = this['animate_3'] = ''; break; case 3: this['animate_0'] = this['animate_1'] = this['animate_2'] = ''; break; } }, changeFinish(event){ // swiper动画完成之后,给当前swiper添加动画效果 let current = event.detail.current; switch(current){ case 0: this['animate_0'] = 'animated swing'; break; case 1: this['animate_1'] = 'animated shake'; break; case 2: this['animate_2'] = 'animated tada'; break; case 3: this['animate_3'] = 'animated heartBeat'; break; } }, goChange(){ this.item_id = 'slide1'; } } }</script><style lang="scss"> @import '../../common/animate.css'; .content { text-align: center; .content-swiper{ height: 100vh; image{ height: 200upx; width: 200upx; margin-top: 200upx; } } }</style>首先uni-app支持sass。在css中直接引入了简洁版animate.css。问题①之后通过查看文档,发现circular这个参数可以实现类似H5页面使用swiper.jsloop参数的功能。这里我掉到了uni-app和微信小程序文档描述的坑中。因为一直在找loop(循环)这个参数,我甚至都以为实现不了这个无限循环的功能了呢。原来小程序中这个参数叫做circular(圆形)。o(╯□╰)o 问题③因为我这里要实现一个竖屏的滑动效果,所以将参数vertical设置为true。在uni-app中,通过change事件,可以监听每一个轮播屏的改变。在这个事件中,我记录的当前屏的下标current。然后将非当前屏的全部css3动画取消掉。最后在animationfinish事件中,当swiper滑动动画结束后,给当前屏的元素添加css3动画。问题②在uni-app中有个current-item-id参数,代表当前所在滑块的 item-id。这个文档我看了好久,才明白。原来是需要在swiper-item中指定上item-id。然后当用户点击事件触发时,修改绑定到current-item-id上的值即可。我的代码初始化时指定到了item-id为slide2这一屏上。问题④最后一个问题时uni-app中隐藏掉H5导航栏。只需要在pages.json中设置titleNView为false即可。微信小程序代码<!--index.wxml--><view class="container"> <button bindtap='goChange'>跳转到</button> <swiper vertical="true" circular="true" current="{{currentId}}" indicator-dots="true" bindchange="changeSwiper" bindanimationfinish="changeFinish"> <swiper-item> <image src='../../static/uni.png' class='animated {{animate_0}}'></image> </swiper-item> <swiper-item> <image src='../../static/uni.png' class='animated {{animate_1}}'></image> </swiper-item> <swiper-item> <image src='../../static/uni.png' class='animated {{animate_2}}'></image> </swiper-item> </swiper></view>//index.jsconst app = getApp()Page({ data: { currentId: 0, animate_0: 'swing', animate_1: '', animate_2: '' }, onLoad: function() { }, goChange: function() { this.setData({ currentId: 2 }); }, changeSwiper: function(event) { let current = event.detail.current; switch (current) { case 0: this.setData({ animate_1: '', animate_2: '' }); break; case 1: this.setData({ animate_0: '', animate_2: '' }); break; case 2: this.setData({ animate_0: '', animate_1: '' }); break; } }, changeFinish: function(event) { let current = event.detail.current; switch (current) { case 0: this.setData({ animate_0: 'swing', }); break; case 1: this.setData({ animate_1: 'shake', }); break; case 2: this.setData({ animate_2: 'tada', }); break; } }})我将代码托管到了腾讯云开发者平台,需要的话可以参考。在代码目录unpackage/dist/build/h5中,就是生成好的H5版页面。需要注意的是,要部署到web服务器使用,不支持本地file协议打开。其中生成了两个版本的代码,方便大家参考。 ...

May 31, 2019 · 2 min · jiezi

重学前端学习笔记二十六CSSOM

笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的专栏学习【原文有winter的语音】,如有侵权请联系我,邮箱:kaimo313@foxmail.com。一、介绍CSSOM 是 CSS 的对象模型,在 W3C 标准中,它包含两个部分:描述样式表和规则等 CSS 的模型部分(CSSOM),和跟元素视图相关的 View 部分(CSSOM View)。二、CSSOM2.1、创建样式表用 style 标签和 link 标签创建样式表<style title="Hello">a { color:red;}</style><link rel="stylesheet" title="x" href="data:text/css,p%7Bcolor:blue%7D">2.2、CSSOM API 的基本用法// 获取文档中所有的样式表document.styleSheets// 虽然无法用 CSSOM API 来创建样式表,但是可以修改样式表中的内容document.styleSheets[0].insertRule("p { color:pink; }", 0)document.styleSheets[0].removeRule(0)// 获取样式表中特定的规则(Rule),(使用它的 cssRules 属性来实现)document.styleSheets[0].cssRules2.3、CSSStyleRule 的两个属性selectorText 和 style,分别表示一个规则的选择器部分和样式部分。1、selector 部分:是一个字符串,按照选择器语法设置即可。 2、style 部分:是一个样式表,它跟元素的 style 属性是一样的类型,所以可以像修改内联样式一样,直接改变属性修改规则中的具体 CSS 属性定义,也可以使用 cssText 这样的工具属性。 // 获取一个元素最终经过 CSS 计算得到的属性的方法window.getComputedStyle(elt, pseudoElt);三、CSSOM ViewCSSOM View 这一部分的 API,可以视为 DOM API 的扩展,它在原本的 Element 接口上,添加了显示相关的功能,可以分成三个部分:窗口部分,滚动部分和布局部分。3.1、窗口 API用于操作浏览器窗口的位置、尺寸等。moveTo(x, y):窗口移动到屏幕的特定坐标moveBy(x, y):窗口移动特定距离resizeTo(x, y):改变窗口大小到特定尺寸resizeBy(x, y):改变窗口大小特定尺寸// 窗口 API 还规定了 window.open() 的第三个参数:window.open("about:blank", "_blank" ,"width=100,height=100,left=100,right=100" )3.2、滚动 API1、视口滚动 API可视区域(视口)滚动行为由 window 对象上的一组 API 控制scrollX:是视口的属性,表示 X 方向上的当前滚动距离,有别名 pageXOffsetscrollY:是视口的属性,表示 Y 方向上的当前滚动距离,有别名 pageYOffsetscroll(x, y):使得页面滚动到特定的位置,有别名 scrollTo,支持传入配置型参数 {top, left}scrollBy(x, y):使得页面滚动特定的距离,支持传入配置型参数 {top, left}通过这些属性和方法,可以读取视口的滚动位置和操纵视口滚动。 ...

May 30, 2019 · 1 min · jiezi

详解-Github-App-的玩法

之前在使用 Github issues 搭建博客平台的时候,研究过一番如何取得 Github 授权并调用 API 的办法。后来选择了较简单的账号密码和 Token 的方法。但是有读者反馈这样的操作依然稍显麻烦,且在第三方的页面输入账号密码总感觉不安全。后来经过研究,总算找到了 Github App 这种更为优雅的办法。 什么是 Github App要回答这个问题,可以直接套用官方文档的说法: GitHub Apps are first-class actors within GitHub. A GitHub App acts on its own behalf, taking actions via the API directly using its own identity, which means you don't need to maintain a bot or service account as a separate user.简单翻译一下,就是 Github App 可以通过 Github 提供的认证信息去调用 Github API。 细心的读者会发现,Github 还提供了一个叫做“OAuth App”的东西,它的使用方式和 Github App 非常类似,最大的不同点是 OAuth App 所获取的权限都是固定且只读的,用户只能读取固定的数据而不能修改数据;而 Github App 几乎可以获取Github提供的所有功能权限,且所获取的权限可以被设定为“只读”,“可读可写”和“禁止访问”,对于权限的授权粒度会更细。 ...

May 30, 2019 · 2 min · jiezi

小程序与小程序之间传参

现在手头上有一个需求。需要在小程序a上面跳到小程序b。并把参数带上传过去。。主要用上两个参数,发送端参数:https://developers.weixin.qq....接收端参数:https://developers.weixin.qq.... 发送端代码如下:test是我按钮的一个方法。。appid为你想要跳的小程序,extradata是你要发送的参数。 接收端如下:(因为小程序未上线。只能在本地测试环境模拟) 需设置这三个。。appid是必填。。如果没填的话,参数一直都是接收不到的。 其实很简单,,就是自己没填appid,收不到参数,,搞了一晚~~~

May 30, 2019 · 1 min · jiezi

让Nodejs支持H5-History模式connecthistoryapifallback源码分析

导读本文主要是对connect-history-api-fallback库进行一次源码分析。connect-history-api-fallback是一个用于支持SPA History路由模式的nodejs库。阅读本文前,应对HTML5 History模式有一定程度的了解! 源码分析/** * 前端需要开启history模式,而后端根据url并不知道前端在请求api还是在请求页面,如localhost:4200/home这种url,前端理所当然认为“我需要得到html,并跳转到首页”,然而后端并不能区分。 * 因此需要一种判断机制,来使得后端能分析出前端的请求目的。 * connect-history-api-fallback 这个中间件正好帮我们完成了上述分析操作,来看下它是怎么实现的吧! * 第一次把自己的源码分析思路写出来,说得不对的地方,请指出! */'use strict';var url = require('url');exports = module.exports = function historyApiFallback(options) { // 接收配置参数 options = options || {}; // 初始化日志管理器 var logger = getLogger(options); // 中间件是要返回一个函数的,函数形参有req, res, next return function(req, res, next) { var headers = req.headers; if (req.method !== 'GET') { // 如果请求方法不是GET类型,说明不需要返回html,那么就调用next(),把请求交给下一个中间件 logger( 'Not rewriting', req.method, req.url, 'because the method is not GET.' ); return next(); } else if (!headers || typeof headers.accept !== 'string') { // 如果没有请求头,或者请求头中的accept不是字符串,说明不是一个标准的http请求,也不予处理,把请求交给下一个中间件 logger( 'Not rewriting', req.method, req.url, 'because the client did not send an HTTP accept header.' ); return next(); } else if (headers.accept.indexOf('application/json') === 0) { // 如果客户端希望得到application/json类型的响应,说明也不是在请求html,也不予处理,把请求交给下一个中间件 logger( 'Not rewriting', req.method, req.url, 'because the client prefers JSON.' ); return next(); } else if (!acceptsHtml(headers.accept, options)) { // 如果请求头中不包含配置的Accept或者默认的['text/html', '*/*'],那么说明也不是在请求html,也不予处理,把请求交给下一个中间件 logger( 'Not rewriting', req.method, req.url, 'because the client does not accept HTML.' ); return next(); } // 走到这里说明是在请求html了,要开始秀操作了 // 首先利用url模块的parse方法解析下url,会得到一个对象,包括protocol,hash,path, pathname, query, search等字段,类似浏览器的location对象 var parsedUrl = url.parse(req.url); var rewriteTarget; // 然后得到配置中的rewrites,也就是重定向配置; // 重定向配置是一个数组,每一项都包含from和to两个属性; // from是用来正则匹配pathname是否需要重定向的; // to则是重定向的url,to可以是一个字符串,也可以是一个回调方法来返回一个字符串,回调函数接收一个上下文参数context,context包含三个属性(parsedUrl,match,request) options.rewrites = options.rewrites || []; // 遍历一波重定向配置 for (var i = 0; i < options.rewrites.length; i++) { var rewrite = options.rewrites[i]; // 利用字符串的match方法去匹配 var match = parsedUrl.pathname.match(rewrite.from); if (match !== null) { // 如果match不是null,说明pathname和重定向配置匹配上了 rewriteTarget = evaluateRewriteRule(parsedUrl, match, rewrite.to, req); if(rewriteTarget.charAt(0) !== '/') { // 推荐使用/开头的绝对路径作为重定向url logger( 'We recommend using an absolute path for the rewrite target.', 'Received a non-absolute rewrite target', rewriteTarget, 'for URL', req.url ); } logger('Rewriting', req.method, req.url, 'to', rewriteTarget); // 进行重定向url操作 req.url = rewriteTarget; return next(); } } var pathname = parsedUrl.pathname; // 首先说明一下:校验逻辑默认是会去检查url中最后的.号的,有.号的说明在请求文件,那就跟history模式就没什么鸟关系了 // 我暂且将上述规则成为“点号校验规则” // disableDotRule为true,代表禁用点号校验规则 if (pathname.lastIndexOf('.') > pathname.lastIndexOf('/') && options.disableDotRule !== true) { // 如果pathname的最后一个/之后还有.,说明请求的是/a/b/c/d.*的文件(*代表任意文件类型); // 如果此时配置disableDotRule为false,说明开启点号校验规则,那么不予处理,交给其他中间件 logger( 'Not rewriting', req.method, req.url, 'because the path includes a dot (.) character.' ); return next(); } // 如果pathname最后一个/之后没有.,或者disableDotRule为true,都会走到最后一步:重写url // 重写url有默认值/index.html,也可以通过配置中的index自定义 rewriteTarget = options.index || '/index.html'; logger('Rewriting', req.method, req.url, 'to', rewriteTarget); // 重写url req.url = rewriteTarget; // 此时再将执行权交给下一个中间件(url都换成index.html了,后面的路由等中间件也不会再处理了,然后前端接收到html就开始解析路由了,目的达到!) next(); };};// 判断重定向配置中的tofunction evaluateRewriteRule(parsedUrl, match, rule, req) { if (typeof rule === 'string') { // 如果是字符串,直接返回 return rule; } else if (typeof rule !== 'function') { // 如果不是函数,抛出错误 throw new Error('Rewrite rule can only be of type string or function.'); } // 执行自定义的回调函数,得到一个重定向的url return rule({ parsedUrl: parsedUrl, match: match, request: req });}// 判断请求头的accept是不是包含在配置数组或默认数组的范围内function acceptsHtml(header, options) { options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*']; for (var i = 0; i < options.htmlAcceptHeaders.length; i++) { if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) { return true; } } return false;}// 处理日志function getLogger(options) { if (options && options.logger) { // 如果有指定的日志方法,则使用指定的日志方法 return options.logger; } else if (options && options.verbose) { // 否则,如果配置了verbose,默认使用console.log作为日志方法 return console.log.bind(console); } // 否则就没有日志方法,就不记录日志咯 return function(){};}

May 30, 2019 · 2 min · jiezi

h5微信自定义分享

为了h5页面在微信分享效果更好,我们接入了 h5 微信sdk,下面对接入流程总结。1、在项目中引用微信的js-sdkjs-sdk地址(支持https):http://res.wx.qq.com/open/js/... 或者 http://res2.wx.qq.com/open/js... 2、在微信公众平台绑定安全域名3、配置config在1,2步操作成功后,进入我们写代码正题,我们需要在入口js中配置config wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', timestamp: , nonceStr: '', signature: '', jsApiList: [] });参数说明:appId:公众号的唯一标识,在公众号中可以取到;timestamp:生成签名的时间戳nonceStr: 生成签名的随机串signature: 最后生成的签名jsApiList: 需要使用的JS接口列表,我们这里是用分享接口,将分享几个api接口填进去,例如:['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareQQ'](备注:出于安全考虑,微信要求开发者必须在服务器端实现签名的逻辑,故timestamp, nonceStr,signature 可以通过请求自己服务器返回。如果有兴趣了解是如何生成的,如下图1所示。) 图1 4、wx.ready中配置自定义分享信息config 配置玩成功后,可以在wx.ready回调填写自定义的信息,如下: wx.ready(function () { wx.onMenuShareQQ({ //分享QQ title: data.wxTitle, // 分享标题 link: data.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致且分享的地址不要带端口 desc: data.wxDesc, imgUrl: data.wxImg || defaultIcon, // 分享图标 success: function () { // 用户确认分享后执行的回调函数 // alert(e); }, cancel: function () { // 用户取消分享后执行的回调函数 } }); wx.updateAppMessageShareData({ // 分享好友 title: data.wxTitle, // 分享标题 link: data.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致且分享的地址不要带端口 desc: data.wxDesc, imgUrl: data.wxImg || defaultIcon, // 分享图标 type: "", // 分享类型,music、video或link,不填默认为link dataUrl: "", // 如果type是music或video,则要提供数据链接,默认为空 success: function (e) { // 用户点击了分享后执行的回调函数 // alert(e); } }); wx.onMenuShareTimeline({ // 分享朋友圈 title: data.wxTitle, // 分享标题 link: data.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致且分享的地址不要带端口 desc: data.wxDesc, imgUrl: data.wxImg || defaultIcon, // 分享图标 success: function (e) { // 用户点击了分享后执行的回调函数 // alert(e) } }); });总结到这一步分享的操作基本就完成了,建议在测试时将debug打开,看看分享提示,从而判定是否分享成功。如果不成功,可以参考一下在开发时候遇到的坑。 ...

May 30, 2019 · 1 min · jiezi

重学前端学习笔记二十五CSS的正常流

笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的专栏学习【原文有winter的语音】,如有侵权请联系我,邮箱:kaimo313@foxmail.com。一、正常流的行为正常流的排版行为:依次排列,排不下了换行。1.1、float在正常流基础上,有 float 相关规则,使得一些盒占据了正常流需要的空间,可以把 float 理解为文字环绕。 1.2、vertical-align有 vertical-align 相关规则规定了如何在垂直方向对齐盒。基线、文字顶 / 底、行顶 / 底等概念。 1.3、margin 折叠1、参考文章:CSS中margin折叠问题记录 2、块级格式上下文Block Formatting Context(简称 BFC) Web页面的一种布局方式,通俗点说,也是指页面上一个渲染区域,里面的元素按文档流中的顺序垂直排列,并且发生垂直方向上的 margin折叠,同时这个区域内的元素布局不会对外面的元素有任何影响。3、产生一个BFC:当元素满足一下任何一个条件 float 属性取值不是 noneoverflow 属性取值不是 visibledisplay 的值为 table-cell, table-caption, inline-block 中的任何一个position 的值不为 static 或 relative 中的任何一个4、BFC 内部垂直方向上的 margin折叠 可以用https://codepen.io/pen/测试: <div id="father"> <div id="first-child">box1</div> <div id="second-child">box2</div> <div id="three-child">box3</div></div>*{ margin: 0; padding: 0;}#father{ width: 2000px; height: 400px; background: #0016d9;}#first-child{ margin-top: 20px; background: chocolate; width: 60px; height: 60px;}#second-child{ background: chartreuse; width: 60px; height: 60px; margin-bottom: 20px;}#three-child{ margin-top:40px; background: fuchsia; width: 60px; height: 60px;}这段代码渲染出来的结果: ...

May 29, 2019 · 2 min · jiezi

APICloud联合腾讯云推出云主机解决方案各种福利等你拿

为了帮助开发者一站式打通云、开发、运维全流程服务,更全面提供基于自身业务情况的云服务器、数据库、存储等基础设施服务,APICloud联合腾讯云重磅推出“云主机解决方案“。开发者可通过控制台简单清晰的购买流程实现一键下单,开发者无需进行多平台来回切换,真正实现与腾讯云一站式打通,完成云主机的购买和运维管理。开发者可通过APICloud平台放心选购与腾讯云官网实时同步价格的云资源,更可享受APICloud赠送的更高价值的平台服务,不仅有模块抵扣券、VIP代金券、学习进阶包等,还有满额返现的双重福利等你来拿! 快快一起来了解优惠福利~一、【无门槛福利】买就送300元模块抵扣券&VIP8折券活动时间:2019/5/23-2019/6/30注意啦!注意啦!注意啦!重要的事情说三遍!活动期间,凡首次从APICloud平台购买云主机产品的用户均可获得VIP8折券1张及价值300元模块抵扣券(AC模块工作室任选一个);最重要的是不限订单金额~你懂的 二、【购买返现】消费满5000即可享受返现凡基于APICloud平台购买包年云主机产品的用户,一次性购买满5000元,即可获得300元现金福利,满10000元及以上可获得800元现金福利! 三、【推广返利】推荐朋友购买最高可享受10%返利1.APICloud针对开发者推出推广返现活动:受邀用户通过推广者分享的链接购买云主机相关产品,推广者即可获得返利; 速戳生成你的专属推广链接吧:https://www.apicloud.com/post... (请使用电脑登录) 2.奖金福利一览表: 3.了解更详细的推广返现规则:https://www.apicloud.com/reba...(请使用电脑登录) 注:返现金额将在35个工作日内审核完毕直接充值到用户的APICoud账户余额中,此部分的金额支持购买平台任何付费产品喔~是不是想想就很赞的感觉 此活动解释权归APICloud主办方所有关于云主机更多福利信息可详询:QQ 2405217190

May 29, 2019 · 1 min · jiezi

利用canvas实现图片下载功能来实现浏览器兼容问题

前言:项目中需要实现图片下载功能,第一个想到的是使用a标签的download属性来实现,但是在不同浏览器下测试会发现,有的浏览器无效,点击后直接预览图片,所以,上网找到了另外一种兼容不同浏览器的图片下载的方法,那就是利用canvas来处理图片,实现下载; 1.项目中点击事件绑定: <a href="#" @click.prevent="downloadIamge(imgsrc, name)"><span>{{name}}</span></a>2.点击事件中操作: downloadIamge (imgsrc, name) { const url = imgsrc this.convertUrlToBase64(url).then((base64) => { const blob = this.convertBase64UrlToBlob(base64) if (getBrowser() === 'IE' || getBrowser() === 'Edge') { window.navigator.msSaveBlob(blob, name) } else { const a = document.createElement('a') const body = document.querySelector('body') a.download = name || 'image' a.href = URL.createObjectURL(blob) a.style.display = 'none' body.appendChild(a) a.click() body.removeChild(a) window.URL.revokeObjectURL(a.href) } }) },分析:3.this.convertUrlToBase64(url)就是利用canvas和toDataURL把图片转成base64格式并返回 convertUrlToBase64 (url) { return new Promise((resolve, reject) => { const img = new Image() img.crossOrigin = 'Anonymous' img.src = url img.onload = function () { const canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, img.width, img.height) const ext = img.src.substring(img.src.lastIndexOf('.') + 1).toLowerCase() const dataURL = canvas.toDataURL('image/' + ext) const base64 = { dataURL: dataURL, type: 'image/' + ext, ext: ext } resolve(base64) } }) },其中:img.crossOrigin = 'Anonymous'是前端对图片的跨域处理; ...

May 29, 2019 · 2 min · jiezi

关于-elementui-的隐藏组件elscrollbar

虽然在官方文档中没有给出这个组件,但是在源码中是有的。所以我们可以直接使用: <el-scrollbar></el-scrollbar>但是我们需要微调一下样式,两种情况的演示代码如下: 已知内容高度<div style='height:800px'><el-scrollbar class='page-component__scroll'></el-scrollbar><div><style>.page-component__scroll{ height: 100%;}.page-component__scroll .el-scrollbar__wrap { overflow-x: auto;}<style>高度由内容撑开<html> <body> <div style='height:100%'> <el-scrollbar class='page-component__scroll'></el-scrollbar> <div> </body></html><style>html,body{ height:100% overflow:hidden; /*有效防止在页面进行手动刷新时显示内置滚动条*/}.page-component__scroll{ height: 100%;}.page-component__scroll .el-scrollbar__wrap { overflow-x: auto;}<style>

May 29, 2019 · 1 min · jiezi

移动Web深度剖析

随着前端技术的急速发展,随着互联网行业的日益发展,HTML5作为一种比较新型的开发技术早已经被很多大的企业所应用,通过HTML5语言可以开发适用于任何设备上的酷炫网站页面,所以HTML5的发展趋势可想而知。话说HTML5退出了也好长一段时间了,现在还拿出来炒冷饭O(∩_∩)O哈哈~ HTML5与SEO为了更好地处理今天的互联网应用,HTML5添加了很多新元素及功能,比如:图形的绘制,多媒体内容,更好的页面结构,更好的形式处理,和几个Api拖放元素,定位,包括网页 应用程序缓存,存储,网络工作者。HTML5推出一个很重要的概念就是语义化标签。这一概念给网页的SEO带来了很大的帮助。 使搜索引擎更加容易抓取和索引 对于一些网站,特别是那些严重依赖于FLASH的网站HTML5是一个大福音。如果你有一个都是FLASH的站点,你就一定会看到切换到HTML5的好处。首先,搜索引擎的蜘蛛将能够抓取你的站点和索引你的内容。所有嵌入到动画中的内容将全部可以被搜索引擎读取。在搜索引擎优化的基本理论中,这一方面将会驱动你的网站获得更多的右击流量。 提供更多的功能,提高用户的友好体验 使用HTML5的另一个好处就是它可以增加更多的功能。对于HTML5的功能性问题,我们从全球几个主流站点对它的青睐就可以看出。社交网络大亨Facebook已经推出他们期待已久的基于HTML5的iPad应用平台,潘多拉也推出他们基于HTML5的音乐播放器的新版本。游戏平台Zynga也在推出了三款新的在移动设备浏览器上运行的基于HTML5的游戏等等。每天都有不断的基于HTML5的网站和HTML5特性的网站被推出。保持站点处于新技术的前沿,也可以很好的提高用户的友好体验。 可用性的提高,提高用户的友好体验 HTML5的推出给前端行业带来了一片新的天空,不单单提供了大量的API,给移动端开发也是一个很大的福音。 说了这么多,扯了这么多,那么上面这些和移动端又有什么关系。实质上是没有关系的,在做移动端开发,由于移动端对于HTML5的支持还是很不错的。推荐大家在做移动端开发的时候,尽量使用HTML5新添加的那些语义化的标签。 HTML5在特别老的手机上会有问题,因为手机是无法识别这些新标签的。所以我们需要使用JavaScript的createElement方法,手动创建标签,以解决兼容问题,不做多余赘述,这不是本文的重点。 meta标签看到meta标签,不禁的让我想起一次面试经历,面试官当时问了我一个问题<head>里面都有什么?记得当时只是回答了都有哪些标签,然而,面试官想要知道的不只是简简单单的几个标签。meta一个熟悉既陌生的标签。它到底能做什么? META标签:通常所说的meta标签,是在HTML网页源代码中一个重要的html标签。META标签用来描述一个HTML网页文档的属性,例如作者、日期和时间、网页描述、关键词、页面刷新等。 根据百度百科介绍,可以做很多事情的ing,有的时候SEO也是依赖于meta标签。元数据是用来概括描述数据的一些基本数据。也就是描述数据的数据。 SEOmeta标签共有两个属性,分别是http-equiv属性和name属性。meta标签用来描述一个HTML网页文档的属性,但却是文档的最基本的元数据 name name属性主要用于描述网页,与之对应的属性值为content,content中的内容主要是便于搜索引擎机器人查找信息和分类信息用的。 meta标签的name属性语法格式是:<meta name="参数" content="具体的参数值" />。 其中name属性主要有以下几种参数: 名称作用举例Keywords(关键字)keywords用来告诉搜索引擎你网页的关键字<meta name ="keywords" content="science,human">description(网站内容描述)description用来告诉搜索引擎你的网站主要内容<meta name="description" content="this's Aaron blog!">author(作者)标注网页的作者<meta name="author" content"root,wo_99936@qq.com">generator(页面生成器)规定用于生成文档的一个软件包(不用于手写页面)<meta name="generator" content="FrontPage 4.0">revised(页面修改信息)这常用于最后更改的网站<meta name="revised" content="story,2015/07/22" />copyright(版权信息)版权信息<meta name="copyright" content="All Rights Reserved" />http-equiv http-equiv顾名思义,相当于http协议中文件头的作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变量值。 名称作用举例content-Type(显示字符集的设定)设定页面使用的字符集<meta http-equiv="content-Type" content="text/html; charset=gb2312"/>Expires(期限)可以用于设定网页的到期时间。一旦网页过期,必须到服务器上重新传输,这里必须使用GMT的时间格式<meta http-equiv="expires" content="Fri, 12 Jan 2001 18:18:18 GMT">Pragma(cache模式)禁止浏览器从本地计算机的缓存中访问页面内容<meta http-equiv="Pragma" content="no-cache"/>Refresh(刷新)自动刷新并指向新页面,其中的2是指停留2秒钟后自动刷新到URL网址<meta http-equiv="Refresh" content="2; URL=http://www.root.net&quot;/>Set-Cookie(cookie设定)设置cookie, 如果网页过期,那么存盘的cookie将被删除<meta http-equiv="Set-Cookie" content="cookievalue=xxx; expires=Friday, 12-Jan-2001 18:18:18 GMT; path=/";/>Window-target(显示窗口的设定)强制页面在当前窗口以独立页面显示,用来防止别人在框架里调用自己的页面<meta http-equiv="Window-target" content="_top"/>meta标签的一个很重要的功能就是设置关键字,来帮助你的主页被各大搜索引擎登录,提高网站的访问量。在这个功能中,最重要的就是对Keywords和description的设置。因为按照搜索引擎的工作原理,搜索引擎首先派出机器人自动检索页面中的keywords和decription,并将其加入到自己的数据库,然后再根据关键词的密度将网站排序。 移动端辅助参数HTML5推出之后又给meta赋予了新的使命。meta可以辅助对移动段适配提供一些参数,供浏览器使用。 // 标签的 name 是:可视区域窗口name = "viewport"// 设置可视区内容的属性content// 宽度等于设备的宽度;一般情况下 width 可以接受两种参数(number||device-width)// 由于 number [任意数值]在某些移动设备的兼容性不好,所以一般都会使用 device-width。width="device-width"// 页面初始比例,配合缩放最大最小使用(number)initial-scale = 1.0 // 最小缩放比例,一般会和初始比例保持一致minimum-scale = 1.0// 最大缩放比例maximum-scale = 1.0// 示例<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />meta除了上述所说的以外还有一些其他辅助功能。 ...

May 28, 2019 · 3 min · jiezi

前端培训初级阶段场景实战20190606下载文件下载进度

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。 这两天,碰到了不止一次前端下载的的问题。其实之前我写过一篇文章 download使用浅析,主要依靠 download 属性来实现浏览器端下载,因为是走浏览器的下载,所以没有进度条。今天我们就来说说我的解决方案。 sf 的一个问题,需要显示进度条。答案地址,问题地址一个朋友的问题,下载的文件需要 headers 验证,无奈只能 ajax 拿数据,但是拉回来的还是字符串,需要自己处理。一个朋友的问题,监测下载进度。今天我们要讲什么?如何使用 download 属性,下载文件。这节主要是讲如何使用,以及前端下载的核心操作。下载文件,并显示进度条。这节是正常操作,如果你只为了解原理,看到这里就够了其他数据类型如何互相转换这节就不一样了。因为之前的 api 是使用 blob 实现,但是 ajax 传回来的数据有好多种类型,我们如何将他们相互转换?如何使用 download 属性,下载文件。download使用浅析 这一文中已经介绍了,可以去看看。我这里简单说一下。<a>标签如果设置了 download 属性,他就会去下载这个地址。测试地址-原生 download 属性测试。 下载文件,并显示进度条下载文件上面已经实现了,那我们先说说如何显示进度条。 显示进度条其实浏览器也是有进度条的,但是咱们拿不到。那我们就来模拟一下载,然后显示进度条。 ajax 实现下载进度条,测试地址-显示进度条 xhr = new XMLHttpRequest();xhr.open('get', file1.url);xhr.onprogress = (e)=>console.log(e)//e 就是一个 ProgressEvent 对象,其中 loaded 是已下载的, total 是总大小。xhr.send()fetch 实现下载进度条,测试地址-fetch显示进度条并下载fetch 的实现上来说有一些功能是没有的,比如 abort、进度等。那我们就需要去通过一些别的手段来模拟实现。实现代码如下,我们操作成读流,然后统计长度。下载文件进度条已经显示好了,那我们可以下载文件了。首先我们要分几种情况 缓存下载(一个资源如果已经下载完了,再次去访问)本地下载(资源已经在浏览器中) blob url 下载 如这种地址 blob:https://www.lilnong.top/deb4c297-821c-4545-9b23-0fbdd76890c7base64 url 下载 如这种地址 data:application/octet-stream;base64,aGVsbG8gbGlub25n blob = new Blob(['hello linong']) freader = new FileReader() freader.readAsDataURL(blob)//将 blob 读成 dataurl freader.onload=e=>console.log(freader.result)// 异步的,所以需要回调里面拿 ...

May 28, 2019 · 1 min · jiezi

前端小知识10点2019528

1、火狐(firefox)的mouseenter问题 <MyIcon onMouseEnter={e => { this.mouseEnter(e,); }} onBlur={() => {}} onMouseLeave={e => { this.mouseOut(e,); }}/>onMouseEnter事件在火狐上会不断地触发mouseenter和mouseleave事件,所以需要先设置一个flag=false,在onMouseEnter时设为true,在onMouseLeave设为false,让不断触发的onMouseEnter事件只触发一次即可 this.state={ flag:false}mouseEnter(){ if(!this.state.flag){ //...do something this.setState({ flag:true, }) }}mouseOut(){ this.setState({ flag:false, })}2、ESLint Unary operator '++' usedi++是不安全的,所以用i+=1 //badfor(let i=0;i<a.length;i++)//goodfor(let i=0;i<a.length;i+=1)3、兼容 ie11之 SVG 的transform旋转从 0 度 //非IE可以这样写svg.style('transform', `rotate(0deg)`)//IE需要这么写svg.attr('transform',`rotate(0,0 0)`)转到 180 度 //非IE可以这样写svg.style('transform', `rotate(180)`)//IE需要这么写svg.attr('transform', `rotate(180,0 0)`)详情请参考:https://www.zhangxinxu.com/wordpress/2015/10/understand-svg-transform/ 4、border-block-end边界块结束 border-block-end: 1px solid #d5d5d5;第一次知道这个属性,好像是新边框属性,但兼容性不太好,IE11 不兼容,所以还得改回下面这样: border-bottom: 1px solid #d5d5d5;5、调整 svg 中<g>标签的位置使用<g>标签自带的transform属性 <g transform={'translate(0 30) scale(1.4)'}></g>6、get请求中的参数有中文,ie11无法识别使用encodeURI()方法来识别,也不影响其他浏览器 encodeURI( url )7、document.activeElement.tagName返回文档中当前获得焦点的元素 ...

May 28, 2019 · 1 min · jiezi

htmlcss-实现导航栏-文字居中

效果文字水平垂直居中 html代码<header> <div class="header-container"> <div class="header-nav"> <ul> <li><a href="#">首页</a></li> <li><a href="#">集团介绍</a></li> <li><a href="#">专家联盟</a></li> <li><a href="#">合作机构</a></li> <li><a href="#">新闻动态</a></li> </ul> </div> </div> </header>css代码header .header-nav { height: 100px;}header .header-nav ul { width: 100%; height: 100px; border: 1px solid #000;} header .header-nav ul li { display: inline-flex; align-items: center; justify-content: center; height: 100px;}header .header-nav ul li a { display: block; padding: 0 30px; line-height: 100px; font-size: 20px;}

May 28, 2019 · 1 min · jiezi

网站footer沉底效果的三种解决方案

问题背景很多网站设计一般是两个部分,content + footer,content里面装的是网站主体内容,footer里面展示网站的注册信息等等,因为网站内容高度不定的原因,会出现下面两种情况:1.内容较少时,这个footer固定在在页面的底部。如下所示:2.内容较长时,footer跟在内容后面滑动,大致表现如下图红色框起来的部分(对应网址:http://www.sbc-mcc.com/): 这个需求在PC端还是很常见的,我在自己的应用中也遇到了这个问题,今天总结了一下实现这种布局的几个方法。 方法1 使用js计算为什么第一个就采用js控制的呢,因为实不相瞒,当初我第一次遇到这个问题的时候,直接就使用js去解决的(主要是我知道js肯定能实现的,所以也就没有花时间去想别的方法)主要思路是:在页面加载完成后计算屏幕高度 - content内容真实的高度的值,如果差值大于footer的高度,就给footer的style加上fixed定位,使它固定在屏幕底部。demo代码如下: <!DOCTYPE html><html><head> <title>footer沉底效果</title> <style type="text/css"> div { margin: 0, padding: 0; box-sizing: border-box; position: relative; } html, body { width: 100%; height: 100%; } #container { width: 100%; height: 100%; } #content { background: blue; } #footer { width: 100%; height: 100px; background: red; } .footer-fixed { position: fixed; left: 0; bottom: 0; } </style></head><body><div id="container"> <div id="content"> content </div> <div id="footer"> footer </div></div><script type="text/javascript"> let height = document.getElementById('container').clientHeight - document.getElementById('content').clientHeight; // 这里给footer加上另外的class,使其固定 if (height > 100) document.getElementById('footer').classList.add('footer-fixed');</script></body></html>本着能使用css解决就绝对不使用js的原则,这个方法虽然最容易想到,但是还是不推荐使用,而且,这段css代码要获取clientHeight,将会导致页面页面重排和重绘,性能考虑上来说,也不推荐。 ...

May 27, 2019 · 2 min · jiezi

流程图软件哪个好用绘制流程图的软件

亿图流程图制作软件是一款用于绘制各种流程图,同时兼具跨平台,云储存,分享功能的专业流程图制作软件。操作简单,功能强大,非常容易实现可视化、分析和交流复杂信息。软件内置海量精美的流程图模板与图库,帮助你轻松绘制项目管理流程图,程序流程图,工作流程图,过程流程图等。手绘流程图效率低、效果差怎么办?流程图怎么画?上哪里找专业的流程图制作工具?亿图流程图制作软件轻松帮你解决上述烦恼。 配置需求 Windows? 2000, Windows? XP, Windows 2003, Windows Vista, Windows 7,Windows 8, Windows 10 Mac OS X 10.7 + Linux Debian, Ubuntu, Fedora, CentOS, OpenSUSE, Mint, Knoppix, RedHat, Gentoo及更多 流程图制作软件特色 支持多个系统:同时支持支持Windows,Mac和Linux,并且版本同步更新。 智能化操作:拥有自动设置,根据条件为主题进行颜色填充,添加图形,排版,用户只需关心形状的关系,其他的流程图制作软件会自动搞定。 矢量的制图软件,帮助快速制作流程图。 拥有多个主题:拥有多个主题风格,只需一键即可更改。 模板多: 内置一系列优秀的流程图模板,还有免费的在线模板,可以帮助新手更快的上手创建漂亮专业的流程图,从而节省创建时间。 导出格式多:不仅可以导出为Word,图片,Visio,PDF矢量等文件格式,还可以导出为HTML网页,SVG矢量图等,有助于分享。 自动更新:您将收到通知,当有新版本或新的模板时。您可以直接安装。 什么是流程图 流程图是以简单的图标符号,通过箭头以及线条依次表示流程走向,一步一步的呈现某个过程或工作流程的示意图。它以简单直观的形式提供了一种结构,各种数据操作一目了然,使人不会产生歧义。 流程图软件适用领域 用流程图流程图一般应用于企业、公司、医疗、教学、生产线上。流程图可以给我们清楚的展现出一些复杂的数据,让我们分析或观看起来更加清楚明了。一个公司的运营模式,一个工场的生产流程都只需要用一张流程图就可以简单的概括出来,流程图制作软件是这些办公人员必备的武器之一。 什么时候使用流程图 无论为人还是处事,人们总喜欢化繁为简,使用流程图,可以形象地体现某个过程的每一个步骤,以及你是如何实现这个过程的,不存在太多内部行话让人迷惑不清,流程图不单单可以用来处理过程文档,还可以用于项目管理,帮助解决问题,提供逻辑架构等。

May 27, 2019 · 1 min · jiezi

流程图怎么做画流程图用什么软件容易

亿图流程图制作软件是一款用于绘制各种流程图,同时兼具跨平台,云储存,分享功能的专业流程图制作软件。操作简单,功能强大,非常容易实现可视化、分析和交流复杂信息。软件内置海量精美的流程图模板与图库,帮助你轻松绘制项目管理流程图,程序流程图,工作流程图,过程流程图等。如何用来绘制一个流程图呢好用的画流程图软件 第一步 选择从模板创建或者创建一个新页面方法一:创建一个新的页面点击文件-新建-流程图。双击模板下的流程图选择需要绘制的种类,进入编辑状态。方法二:使用模板创建程图点击文件-新建-流程图。当找到需要的模板时,双击模板或者点击右上角预览窗口下的创建导按钮,即可成功创建一个含有预设内容的流程图。 第二步 添加图形方法一:用图形的浮动按钮添加从左侧模板库中拖出一个流程形状。 点击四周的浮动按钮。方法二: 从库里拖放添加从界面左边的符号库里拖动一个图形。把拖动的图形移动到要吸附的标题旁,松开鼠标会自动链接。第三步 排版和连接线样式排版十分灵活,可以智能的调整大小和对齐,还可以根据已经存在图形的位置标出对齐线,其自动性为我们带来便捷。 第四步 添加文本和其他内容添加文本双击流程图图形。输入文本。点击绘图页面的任意空白区域或者按 ESC 键完成输入文字。另外流程图制作软件不仅可以添加文件,还可以添加超链接,附件、图释和其他内容以提供上下文信息。 第五步 美化功能流程图软件不仅在实用性上下足功夫,同时也相当注重美观设计,更改主题形状可以起到美化导图的作用。点击页面布局中的主题,我们可以根据自己的喜好选择,点击即可应用。也可以点击页面布局的颜色按钮,打开更改主题格式下拉框,可以设置主题边框的颜色和填充的颜色。还可以点击界面下方的填充条,或者按F4在界面的右侧将会显示更多的样式。 第六步 一键导出到Word,PPT作为专业实用性软件,和其他的软件有很好的兼容性,从导出格式上就可以看出来,支持12种导出格式,完全满足的日常办公的常用需求。制作好流程图。点击文件>导出。即可打开导出格式列表。流程图制作软件不仅可以制作流程图,还可以通过其在线服务将制作的流程图共享给其他人。可以免费注册账号,通过账户登录即可使用在线服务。 所见即所得的打印打印是一种将流程图进行输出的好方法,便于保存及分享。 流程图制作软件打印不改变图片并且保持高清,可自由调整大小。特殊情况 比如打印不止一张时 可以在 打印设置 对话框设置。

May 27, 2019 · 1 min · jiezi

HTML5-canvas-瀑布流文字效果的示例代码分享

HTML5 canvas 瀑布流文字效果的示例代码分享 文章中分享了HTML5 canvas 瀑布流文字效果的示例代码,一块来看一下吧。 cloth*{padding: 0;margin: 0;}body{background:#000;}var c = document.getElementById("c");var ctx = c.getContext("2d");//制作全屏c.height = window.innerHeight;c.width = window.innerWidth;//汉字从Unicode字符集var chinese = "igeekbar~";//将字符串转换为一个数组中的单个字符chinese = chinese.split("");var font_size = 20;var columns = c.width/font_size; //雨的列数//每列的一个数组var drops = [];//下面是×坐标//1 = y 在下降(最初是相同的)for(var x = 0; xdrops[x] = 1;//画function draw(){//黑BG的帆布//半透明BG显示轨迹ctx.fillStyle = "rgba(0, 0, 0, 0.05)";ctx.fillRect(0, 0, c.width, c.height);ctx.fillStyle = "#0F0"; //字体颜色ctx.font = font_size + "px arial";//循环字体for(var i = 0; i{//随机汉字打印var text = chinese[Math.floor(Math.random()*chinese.length)];//x = ifont_size, y = value of drops[i]font_sizectx.fillText(text, ifont_size, drops[i]font_size);//在屏幕上划线后,把它的顶部随机发送到顶部//将一个随机性添加到复位中,使分散在轴上的下降if(drops[i]*font_size > c.height && Math.random() > 0.975)drops[i] = 0;//增加的Y坐标drops[i]++;}}setInterval(draw, 33);加粗文字 ...

May 27, 2019 · 1 min · jiezi

Vue-scrollBehavior-滚动行为实现后退页面显示在上次浏览的位置

前提:之前写过关于keep-Alive组件,来实现在列表页进入详情页后,后退,返回列表,显示上次访问的位置(原理就是缓存列表页数据来实现),目前发现另外一个问题,就是如果后台操作改变数据的状态,缓存的办法就会导致数据更新不及时导致一些页面错误(例如:商品疑问,在后台答复之后,不可以修改内容,前台更新不及时就会导致,前台显示可编辑,但实际状态是不可编辑了),所以又继续研究另外一种解决办法,scrollBehavior 来实现。 简介:使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。 注意: 这个功能只在支持 history.pushState 的浏览器中可用。官方文档简介:滚动行为 使用方法:const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置 }})或者集成模式写法: utils.js export function scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置}index.js import Vue from 'vue'import Router from 'vue-router'import { scrollBehavior } from './utils'Vue.use(Router)const router = new Router({ mode: 'history', scrollBehavior, routes: [ ...routesPC, ...routesMO ]})export default routerscrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。在该方法内,可以通过判断路由to,from两个对象来做一些必要的判断;savedPosition 参数是记录的上次滚动的位置;通过return {x:number,y:number}来控制页面滚动的位置; ...

May 27, 2019 · 1 min · jiezi

搭建npm私库超简单

原因我搭私库的原因很简单,目前正在开发一个组件库,提供给公司内部使用,我不想去注册npm,也不想等待npm的审核,只想要有个仓库快速测试发布自己的npm包。 怎么搭目前最方便的方案就是verdaccio,搭建非常方便,一般就几分钟就搞定了,需要的工具: 安装nodejs和npm全局安装verdaccioshh和pm2(非必须,如果你要部署到远程服务器的话)接下来详细介绍搭建的步骤。 全局安装verdaccio安装verdaccio之前,我默认大家都已经安装了nodejs和npm环境,这个就不再赘述了。如果是本地搭建的话,直接进行下面的操作就可以了。如果是在远程服务器搭建,通过ssh连接远程服务器就行。 # 全局安装npm install verdaccio - g修改verdaccio配置修改配置的目的就是让我们的私库可以通过公网的ip访问,首先查看npm全局安装包的所在位置: npm root -g/usr/local/Cellar/node/8.4.0/lib/node_modules其中/usr/local/Cellar/node/8.4.0/lib/node_modules便是我们npm包全局安装的地址。按以下命名查找配置文件所在的位置然后 vim default.yaml配置情况如下 ## This is the default config file. It allows all users to do anything,# so don't use it on production systems.## Look here for more config file examples:# https://github.com/verdaccio/verdaccio/tree/master/conf## path to a directory with all packagesstorage: ./storage# path to a directory with plugins to includeplugins: ./pluginsweb: # WebUI is enabled as default, if you want disable it, just uncomment this line #enable: false title: Verdaccioauth: htpasswd: file: ./htpasswd # Maximum amount of users allowed to register, defaults to "+inf". # You can set this to -1 to disable registration. #max_users: 1000# a list of other known repositories we can talk touplinks: npmjs: url: https://registry.npmjs.org/packages: '@*/*': # scoped packages access: $all publish: $authenticated proxy: npmjs '**': # allow all users (including non-authenticated users) to read and # publish all packages # # you can specify usernames/groupnames (depending on your auth plugin) # and three keywords: "$all", "$anonymous", "$authenticated" access: $all # allow all known users to publish packages # (anyone can register by default, remember?) publish: $authenticated # if package is not available locally, proxy requests to 'npmjs' registry proxy: npmjs# You can specify HTTP/1.1 server keep alive timeout in seconds for incomming connections.# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.# WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enought.server: keepAliveTimeout: 60# To use `npm audit` uncomment the following sectionmiddlewares: audit: enabled: true# log settingslogs: - {type: stdout, format: pretty, level: http} #- {type: file, path: verdaccio.log, level: info}# listenlisten: 0.0.0.0:4873最后一行为新增的配置, 用于支持外网ip访问 ...

May 27, 2019 · 2 min · jiezi

前端核心工具yarnnpmcnpm三者如何优雅的在一起使用

一位用不好包管理器的前端,是一个入门级前端,一个用不好webpack的前端,是一个初级前端三个包管理器是可以一起用的,只要你够胆大心细,就没任何问题!推荐两篇文章 手写优化版React脚手架手写Vue的脚手架前端性能优化不完全手册在javeScript编写中,我们尽量不要定义全局变量,封装函数尽量不要有副作用,因为全部变量的查询时间会比局部变量的查询慢,更是考虑在Node的环境中无法被垃圾回收的问题老规矩 先看原理npmnpm 是 Node.js 能够如此成功的主要原因之一。npm 团队做了很多的工作,以确保 npm 保持向后兼容,并在不同的环境中保持一致。npm是围绕着 语义版本控制(semver)的思想而设计。给定一个版本号:主版本号.次版本号.补丁版本号, 以下这三种情况需要增加相应的版本号:主版本号: 当API发生改变,并与之前的版本不兼容的时候次版本号: 当增加了功能,但是向后兼容的时候补丁版本号:当做了向后兼容的缺陷修复的时候npm 2 会安装每一个包所依赖的所有依赖项。如果我们有这么一个项目,它依赖项目A,项目A依赖项目B,项目B依赖项目C,那么依赖树将如下所示: 这个结构可能会很长。这对于基于Unix的操作系统来说只不过是一个小烦恼,但对于Windows来说却是个破坏性的东西,因为有很多程序无法处理超过260个字符的文件路径名。npm 3采用了扁平依赖关系树来解决这个问题,所以我们的3个项目结构现在看起来如下所示:存了已经下载的每个版本的压缩包。本地缓存的内容可以通过npm cache ls命令进行查看。本地缓存的设计有助于减少安装时间。 这样,一个原来很长的文件路径名就从./node_modules/package-A/node_modules/package-B/node-modules/some-file-name-in-package-c.js变成了/node_modules/some-file-name-in-package-c.js。这种方法的缺点是,npm必须首先遍历所有的项目依赖关系,然后再决定如何生成扁平的node_modules目录结构。npm必须为所有使用到的模块构建一个完整的依赖关系树,这是一个耗时的操作,是npm安装速度慢的一个很重要的原因。想当然的以为每次运行npm install命令时,NPM都得从互联网上下载所有内容。但是,npm是有本地缓存的,它保存了已经下载的每个版本的压缩包。本地缓存的内容可以通过npm cache ls命令进行查看。本地缓存的设计有助于减少安装时间。cnpmcnpm跟npm用法完全一致,只是在执行命令时将npm改为cnpm。npm安装插件是从国外服务器下载,受网络影响大,可能出现异常,如果npm的服务器在中国就好了,于是淘宝团队干了这事。来自官网:“这是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。”官方地址:http://npm.taobao.org安装: npm install -g cnpm --registry=https://registry.npm.taobao.orgYarnYarn一开始的主要目标是解决上一节中描述的由于语义版本控制而导致的npm安装的不确定性问题。虽然可以使用npm shrinkwrap来实现可预测的依赖关系树,但它并不是默认选项,而是取决于所有的开发人员知道并且启用这个选项。Yarn采取了不同的做法。每个yarn安装都会生成一个类似于npm-shrinkwrap.json的yarn.lock文件,而且它是默认创建的。除了常规信息之外,yarn.lock文件还包含要安装的内容的校验和,以确保使用的库的版本相同。yarn是经过重新设计的崭新的npm客户端,它能让开发人员并行处理所有必须的操作,并添加了一些其他改进。运行速度得到了显著的提升,整个安装时间也变得更少像npm一样,yarn使用本地缓存。与npm不同的是,yarn无需互联网连接就能安装本地缓存的依赖项,它提供了离线模式。允许合并项目中使用到的所有的包的许可证通常情况下不建议通过npm进行安装。npm安装是非确定性的,程序包没有签名,并且npm除了做了基本的SHA1哈希之外不执行任何完整性检查,这给安装系统程序带来了安全风险。(作者曾经在一个上百个依赖包的项目中使用npm丢包过,代价非常大,泪水不自觉掉下来)首先看一次非常失败的包下载 竟然是从全局读取的资源(不配置webpack别名是因为就这一个路径这么长) 首先我们从原理入手 ,我们使用 npm init, yarn init ,cnpm init 的时候 发生了什么 ?生成package.json文件json文件内部声明初始的版本信息、作者信息等,如果你是需要上传到npm上作为命令行工具,应该配置bin等声明入口字段那么当我们使用npm i , yarn add ,cnpm i 操作时候会发生什么 ?首先会根据你的命令行后缀是否加了 -g 或者global判断,下载的包是放在全局的环境,还是当前package.json文件对应的node_module文件夹目录下(这点尤其重要,有人出BUG,就是因为在用npm , cnpm时候没有注明添加的是全局依赖还是本地依赖,导致json文件上没有对应的包名,项目永远起不来)然后根据你的指令--save 或者-D、--save -dev判断是开发依赖还是线上依赖,其实这点在yarn上没有问题,因为yarn有自己的一套检查包完整性的机制,不会丢包,还会自动判断添加依赖,出bug一般是cnpm和npm,没有明确-g或者--save,npm只有检查程序员签名的机制,没有检查包完整性的机制,也不会自动添加依赖到json文件,那么就会出现丢包的假象,所以建议主要使用yarnyarn和npm对比 npm的缺点汇总:同一个项目,安装的时候无法保持一致性。由于package.json文件中版本号的特点,下面三个版本号在安装的时候代表不同的含义。 "5.0.3", "~5.0.3", "^5.0.3"“5.0.3”表示安装指定的5.0.3版本,“~5.0.3”表示安装5.0.X中最新的版本,“^5.0.3”表示安装5.X.X中最新的版本。这就麻烦了,常常会出现同一个项目,有的同事是OK的,有的同事会由于安装的版本不一致出现bug。安装的时候,包会在同一时间下载和安装,中途某个时候,一个包抛出了一个错误,但是npm会继续下载和安装包。因为npm会把所有的日志输出到终端,有关错误包的错误信息就会在一大堆npm打印的警告中丢失掉,并且你甚至永远不会注意到实际发生的错误。yarn的优点速度快 。速度快主要来自以下两个方面:并行安装:无论 npm 还是 Yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。而 Yarn 是并行执行所有任务,提高了性能。离线模式:如果之前已经安装过一个软件包,用Yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。 ...

May 27, 2019 · 1 min · jiezi

LaravelLayimGatewayWorker实现实时聊天功能

LayIM客户端源码 LayIM服务端源码 Laravel+Layim+GatewayWorker实现实时聊天功能它是什么?基于wbsocket的有前端有后端的支持分布式部署的网页版实时聊天。 有啥功能?想象一下,精简版的qq临时会话加好友单聊群聊消息实时推送查看聊天记录效果预览 体验地址http://laravel-layim.jc91715.top/pc 体验账号 1111@qq.com 111111112222@qq.com 111111113333@qq.com 11111111介绍1 Layim 是什么? 想象一下,没有后台的qq的是什么样子,介绍地址http://layim.layui.com/,不开源,需要授权奥 2 GatewayWorker 是什么? 我的理解是这样的,它是一个容器,你给它发送消息,它可以把消息,发送到你想要的地方,支持分布式部署,详细请看文档手册http://doc2.workerman.net/ 3 结语Layim 良心产品,它已经把后端的数据结构抽象出来了,很容易去推算出后端的表结构是什么样子。个人认为 GatewayWorker 就是为Layim的后端而生的,简直是无缝结合起来。也可以使用第三方如环信等产品。如果你想自己把握数据的私密性还是自建的比较好。个人只在当中使用laravel把Layim 和GatewayWorker 串连起来,解决了Layim 没有后端的尴尬境地。当然Layim它的商业应用使用最多的应该是它的客服窗口,就是右下角的那个客服窗口,它的优势可能并不在于全部功能。对于开发者来说,这样的一个好的产品,不把它给后台完善了,总有点缺憾不是 让网页版实时聊天焕发第二春难免疏漏不足之处,敬请批评改正如果对你有所帮助,请喝个咖啡

May 26, 2019 · 1 min · jiezi

如何理解proto和prototype

(如何理解_proto_和prototype)原型空间我们知道在js中万物皆对象,现在我们假设每一个对象创建时都会产生一个原型空间(原型对象 ) 现在我们记住三句话实例由其定义共享原型空间由__proto__来寻找定义的原型空间由prototype来寻找自己的原型空间 实例由其定义共享原型空间ps p:prototype[p]: _proto_此图片为转载 此图片为转载 从上面两张图可以清楚看出这种关系这样就可以形成原型链所有函数都是由Function构造函数构造的function函数也是Function构造函数构造的所以时function自己构造了自己所以自己指向自己的原型空间我们可以看出图中function的原型空间和animal的原型空间都是object类型(其实第二列的原型空间都是object的实例,但逻辑上不是) //所有函数类型的隐式原型都相同 因为都是Function的原型对象创建//所以构造函数的__proto__是Function//那么Function的隐式原型 ?var fun = new Function();console.log(fun.__proto__===Function.prototype);console.log(Function.__proto__===Function.prototype);//所以Function本身的隐式原型和显示原型相同//可以看出Object也是函数定义的所以他的隐士原型应该是Function 的显示原型console.log(Object.__proto__===Function.prototype)那么object的原型空间的原型空间应该是undefined但这样就会让原型链没有尽头为了逻辑完善就令其为null可以看出原形空间的定义是由其定义的原型空间来定义的(实例和其定义共享原型空间) function Animal(){}function Bird(){}function Swallow(){}Bird.prototype= new Animal()Swallow.prototype=new Bird() var swallow = new Swallow()console.log(swallow.__proto__.prototype)console.log(Swallow.__proto__.prototype)console.log(Bird.__proto__.prototype)console.log(Animal.__proto__.prototype)console.log(Function.prototype.__proto__.prototype)console.log(Swallow.prototype)console.log(Animal.prototype)var animal = new Animalconsole.log(animal.__proto__.__proto__)var obj = {}console.log(typeof (obj.__proto__.__proto__))////ps没有修正construct那么若假设Pobject来定义了Object的原型空间的原型空间那么图中所有的(undefined)的位置的_proto_都会指向Pobject的原型空间以这个逻辑就可以让无限迭代下去(指针的指针的.....的指针)这样向上寻找原型链和向下寻找原型链就统一了,但js设计封锁了向上无限迭代(Object的原型空间为null)

May 26, 2019 · 1 min · jiezi

Javascript即将到来的3个新特性

1、Optional Chaining(可选链式调用) const data = { user: {},};console.log(data.user.address.street); // Uncaught TypeError: Cannot read property 'street' of undefined这是我们现在 ES6 中会遇到的问题,原因是 user 中没有 address 对象,然后我们这样判断: const street = data && data.user && data.user.address && data.user.address.street;console.log(street); // undefined这样的写法很差劲 新特性可以这样写( ?. 类似于angular5的安全操作符) console.log(data.user?.address?.street) //undefined2、Nullish coalescing(空值合并)我们判断空值一般这样: value != null ? value : 'default value';或者这样: value || 'default value'新特性可以这样写( ?? ): value ?? 'default value';3、Pipeline operator(管道运算符)举个例子,通过三个函数对字符串进行处理,通常是这样: function a(str) { return str + ", " + str;}function b(str) { return str[0].toUpperCase() + str.substring(1);}function c(str) { return str + '!';}let result = c ( b ( a("hello") ) ); // "Hello, hello!"通过 管道运算符,我们可以这样写: ...

May 26, 2019 · 1 min · jiezi

Canvas-文字碰撞检测并抽稀

需求背景一般在做地图相关的需求是才会用到文字抽稀,我也是在为公司的地图引擎实现一个功能时才实现了该方法,在这里将其简化了,就在普通的 Canvas 上进行操作,并没有引入地图概念 效果 碰撞检测计算文字在 canvas 中所占据的范围// 计算文字所需的宽度var p = { x: 10, y: 10, name: "测试文字"};var measure = ctx.measureText(p.name);// 求出文字在 canvas 画板中占据的最大 y 坐标var maxX = measure.width + p.x;// 求出文字在 canvas 画板中占据的最大 y 坐标// canvas 只能计算文字的宽度,并不能计算出文字的高度。所以就利用文字的宽度除以文字个数计算个大概var maxY = measure.width / p.name.length + p.y;var min = { x: p.x, y: p.y };var max = { x: maxX, y: maxY };// bounds 为该文字在 canvas 中所占据的范围。// 在取点位坐标作为最小范围时,textAlign、textBaseline 按照以下方式设置会比较准确。// 如设置在不同的位置展示,范围最大、最小点也需进行调整// ctx.textAlign = "left";// ctx.textBaseline = "top";var bounds = new Bounds(min, max);Bounds 范围对象 ...

May 26, 2019 · 1 min · jiezi

Python爬虫入门教程-6100-蜂鸟网图片爬取之一

1. 蜂鸟网图片简介国庆假日结束了,新的工作又开始了,今天我们继续爬取一个网站,这个网站为 http://image.fengniao.com/ ,蜂鸟一个摄影大牛聚集的地方,本教程请用来学习,不要用于商业目的,不出意外,蜂鸟是有版权保护的网站。 2. 蜂鸟网图片网站分析第一步,分析要爬取的网站有没有方法爬取,打开页面,找分页 http://image.fengniao.com/index.php?action=getList&class_id=192&sub_classid=0&page=1&not_in_id=5352384,5352410http://image.fengniao.com/index.php?action=getList&class_id=192&sub_classid=0&page=2&not_in_id=5352384,5352410http://image.fengniao.com/index.php?action=getList&class_id=192&sub_classid=0&page=3&not_in_id=5352384,5352410http://image.fengniao.com/index.php?action=getList&class_id=192&sub_classid=0&page=4&not_in_id=5352384,5352410上面的页面发现一个关键的参数page=1这个就是页码了,但是另一个比较头疼的问题是,他没有最后的页码,这样我们没有办法确定循环次数,所以后面的代码编写中,只能使用while了 这个地址返回的是JSON格式的数据,这个对爬虫来说,非常友好!省的我们用正则表达式分析了。 分析这个页面的头文件,查阅是否有反爬措施 发现除了HOST和User-Agent以外,没有特殊的点,大网站就是任性,没啥反爬,可能压根不在乎这个事情。 第二步,分析图片详情页面,在我们上面获取到的JSON中,找到关键地址 关键地址打开之后,这个地方有一个比较骚的操作了,上面图片中标注的URL选的不好,恰好是一个文章了,我们要的是组图,重新提供一个新链接 http://image.fengniao.com/slide/535/5352130_1.html#p=1 打开页面,你可能直接去找规律了,找到下面的一堆链接,但是这个操作就有点复杂了,我们查阅上述页面的源码 http://image.fengniao.com/slide/535/5352130_1.html#p=1http://image.fengniao.com/slide/535/5352130_1.html#p=2http://image.fengniao.com/slide/535/5352130_1.html#p=3....网页源码中发现了,这么一块区域 大胆的猜测一下,这个应该是图片的JSON,只是他打印在了HTML中,我们只需要用正则表达式进行一下匹配就好了,匹配到之后,然后进行下载。 第三步,开始撸代码。 3. 蜂鸟网图片写代码from http_help import R # 这个文件自己去上篇博客找,或者去github找import threadingimport timeimport jsonimport reimg_list = []imgs_lock = threading.Lock() #图片操作锁# 生产者类class Product(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.__headers = {"Referer":"http://image.fengniao.com/", "Host": "image.fengniao.com", "X-Requested-With":"XMLHttpRequest" } #链接模板 self.__start = "http://image.fengniao.com/index.php?action=getList&class_id=192&sub_classid=0&page={}&not_in_id={}" self.__res = R(headers=self.__headers) def run(self): # 因为不知道循环次数,所有采用while循环 index = 2 #起始页码设置为1 not_in = "5352384,5352410" while True: url = self.__start.format(index,not_in) print("开始操作:{}".format(url)) index += 1 content = self.__res.get_content(url,charset="gbk") if content is None: print("数据可能已经没有了====") continue time.sleep(3) # 睡眠3秒 json_content = json.loads(content) if json_content["status"] == 1: for item in json_content["data"]: title = item["title"] child_url = item["url"] # 获取到链接之后 img_content = self.__res.get_content(child_url,charset="gbk") pattern = re.compile('"pic_url_1920_b":"(.*?)"') imgs_json = pattern.findall(img_content) if len(imgs_json) > 0: if imgs_lock.acquire(): img_list.append({"title":title,"urls":imgs_json}) # 这个地方,我用的是字典+列表的方式,主要是想后面生成文件夹用,你可以进行改造 imgs_lock.release()上面的链接已经生成,下面就是下载图片了,也非常简单 ...

May 26, 2019 · 1 min · jiezi

reactrouter-v4x-源码拾遗2

回顾:上一篇讲了BrowserRouter 和 Router之前的关系,以及Router实现路由跳转切换的原理。这一篇来简短介绍react-router剩余组件的源码,结合官方文档,一起探究实现的的方式。 1. Switch.jsSwitch对props.chidlren做遍历筛选,将第一个与pathname匹配到的Route或者Redirect进行渲染(此处只要包含有path这个属性的子节点都会进行筛选,所以可以直接使用自定义的组件,如果缺省path这个属性,并且当匹配到这个子节点时,那么这个子节点就会被渲染同时筛选结束,即Switch里任何时刻只渲染唯一一个子节点),当循环结束时仍没有匹配到的子节点返回null。Switch接收两个参数分别是: ①:location, 开发者可以填入location参数来替换地址栏中的实际地址进行匹配。②:children,子节点。源码如下:import React from "react";import PropTypes from "prop-types";import warning from "warning";import invariant from "invariant";import matchPath from "./matchPath";class Switch extends React.Component { // 接收Router组件传递的context api,这也是为什么Switch要写在 // Router内部的原因 static contextTypes = { router: PropTypes.shape({ route: PropTypes.object.isRequired }).isRequired }; static propTypes = { children: PropTypes.node, location: PropTypes.object }; componentWillMount() { invariant( this.context.router, "You should not use <Switch> outside a <Router>" ); } componentWillReceiveProps(nextProps) { // 这里的两个警告是说,对于Switch的location这个参数,我们不能做如下两种操作 // 从无到有和从有到无,猜测这样做的原因是Switch作为一个渲染控制容器组件,在每次 // 渲染匹配时要做到前后的统一性,即不能第一次使用了地址栏的路径进行匹配,第二次 // 又使用开发者自定义的pathname就行匹配 warning( !(nextProps.location && !this.props.location), '<Switch> elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.' ); warning( !(!nextProps.location && this.props.location), '<Switch> elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.' ); } render() { // Router提供的api,包括history对象,route对象等。route对象包含两个参数 // 1.location:history.location,即在上一章节里讲到的history这个库 // 根据地址栏的pathname,hash,search,等创建的一个location对象。 // 2.match 就是Router组件内部的state, 即{path: '/', url: '/', params: {}, isEaxct: true/false} const { route } = this.context.router; const { children } = this.props; // 子节点 // 自定义的location或者Router传递的location const location = this.props.location || route.location; // 对所有子节点进行循环操作,定义了mactch对象来接收匹配到 // 的节点{path,url,parmas,isExact}等信息,当子节点没有path这个属性的时候 // 且子节点被匹配到,那么这个match会直接使用Router组件传递的match // child就是匹配到子节点 let match, child; React.Children.forEach(children, element => { // 判断子节点是否是一个有效的React节点 // 只有当match为null的时候才会进入匹配的操作,初看的时候感觉有些奇怪 // 这里主要是matchPath这个方法做了什么?会在下一节讲到,这里只需要知道 // matchPath接收了pathname, options={path, exact...},route.match等参数 // 使用正则库判断path是否匹配pathname,如果匹配则会返回新的macth对象, // 否则返回null,进入下一次的循环匹配,巧妙如斯 if (match == null && React.isValidElement(element)) { const { path: pathProp, exact, strict, sensitive, from } = element.props; // 从子节点中获取props信息,主要是pathProp这个属性 // 当pathProp不存在时,使用替代的from,否则就是undefined // 这里的from参数来自Redirect,即也可以对redirect进行校验,来判断是否渲染redirect const path = pathProp || from; child = element; match = matchPath( location.pathname, { path, exact, strict, sensitive }, route.match ); } }); // 如果match对象匹配到了,则调用cloneElement对匹配到child子节点进行clone // 操作,并传递了两个参数给子节点,location对象,当前的地址信息 // computedMatch对象,匹配到的路由参数信息。 return match ? React.cloneElement(child, { location, computedMatch: match }) : null; }}export default Switch;2. matchPath.jsmathPath是react-router用来将path生成正则对象并对pathname进行匹配的一个功能方法。当path不存在时,会直接返回Router的match结果,即当子组件的path不存在时表示该子组件一定会被选渲染(在Switch中如果子节点没有path,并不一定会被渲染,还需要考虑节点被渲染之前不能匹配到其他子节点)。matchPath依赖一个第三方库path-to-regexp,这个库可以将传递的options:path, exact, strict, sensitive 生成一个正则表达式,然后对传递的pathname进行匹配,并返回匹配的结果,服务于Switch,Route组件。参数如下: ...

May 25, 2019 · 11 min · jiezi

详解如何给背景图片加颜色遮罩

前段时间在开发中,遇到需要给背景层加颜色遮罩的项目,现在特定总结一下给背景图层加颜色遮罩的方法。 方法一:通过定位叠加(注意层级)<div class="wrap1"> <div class="inner"> </div></div>.wrap1 { position: relative; width: 1200px; height: 400px; background: rgba(0, 0, 0, .5);}.wrap1 .inner { position: absolute; left: 0; right: 0; top: 0; bottom: 0; background: url(ban8.jpg) no-repeat center center; background-size: cover; z-index: -1;}方法二:通过伪类元素叠加<div class="wrap2"></div>.wrap2 { position: relative; width: 1200px; height: 400px; background: url(ban8.jpg) no-repeat center center; background-size: cover;}.wrap2::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; top: 0; background-color: rgba(0, 0, 0, .5); z-index: 2;}方法三:CSS3颜色叠加background-blend-mode:multiply;(正片叠底)<div class="wrap3"></div>.wrap3 { position: relative; width: 1200px; height: 400px; background: url(ban8.jpg) rgba(0, 0, 0, .5) no-repeat center center; background-blend-mode: multiply;}拓展:背景模糊加颜色叠加 ...

May 25, 2019 · 1 min · jiezi

用-canvas-制作奥运五环

<canvas id="xxb" width="500" height="500"></canvas> <script type="text/javascript"> var bg = document.getElementById('xxb'); var ctx = bg.getContext('2d'); //第一个圆圈 ctx.beginPath(); ctx.lineWidth=10; //圆圈的边线的大小 ctx.strokeStyle='RGB(43,0,155)'; //圆圈的颜色 ctx.arc(60,60,50,0*Math.PI,2.25*Math.PI,false); // 圆圈的 水平位置 、 垂直位置 、 圆圈的半径、圆圈的弧度 , ctx.stroke(); //第二个圆圈 ctx.beginPath(); ctx.lineWidth=10; ctx.strokeStyle='RGB(35,24,22)'; ctx.arc(180,60,50,0*Math.PI,2*Math.PI,false); ctx.stroke(); //第三个圆圈 ctx.beginPath(); ctx.lineWidth=10; ctx.strokeStyle='RGB(248,3,0)'; ctx.arc(300,60,50,0*Math.PI,2*Math.PI,false); ctx.stroke(); //第四个圆圈 ctx.beginPath(); ctx.lineWidth=10; ctx.strokeStyle='RGB(223,252,22)'; ctx.arc(120,100,50,0*Math.PI,2*Math.PI,false); ctx.stroke(); //第五个圆圈 ctx.beginPath(); ctx.lineWidth=10; ctx.strokeStyle='RGB(37,254,75)'; ctx.arc(240,100,50,0*Math.PI,2*Math.PI,false); ctx.stroke(); </script>

May 25, 2019 · 1 min · jiezi

h5-获取地理位置信息

function success(position){ alert("获取位置成功",position.coords); document.write("维度",position.coords.latitude,"经度",position.coords.longitude,"坐标精度",position.coords.accuracy) } function error(positionError){ alert('获取位置失败:',positionError.code,positionError.Message) document.write(positionError.code,positionError.Message) } var options = { enableHighaccuracy:false, timeout:3000, maximumAge:0 } if(navigator.geolocation){ console.log("支持定位") navigator.geolocation.getCurrentPosition(success,error,options) }else{ alert("不支持定位") }

May 25, 2019 · 1 min · jiezi

收集程序员知识点-持续更新

TCP/IPHTTP和HTTPS有何区别?httpbin 一个简单的HTTP请求和响应服务。TCP的三次握手与四次挥手 通俗易懂版,详细版本MySQLCHAR和VARCHAR存取的差别数据结构算法篇十大经典排序算法希尔排序图解版2018汇总数据结构算法篇 非常不错服务器篇三剑客之 grep、awk、sed其他语义化版本

May 24, 2019 · 1 min · jiezi

我们不背诵-API只实现-API

有不少刚入行的同学跟我说:“JavaScript 很多 API 记不清楚怎么办?数组的这方法、那方法总是傻傻分不清楚,该如何是好?操作 DOM 的方式今天记,明天忘,真让人奔溃!” 甚至有的开发者在讨论面试时,总向我抱怨:“面试官总爱纠结 API 的使用,甚至 jQuery 某些方法的参数顺序都需要让我说清楚!” 我认为,对于反复使用的方法,所有人都要做到“机械记忆”,能够反手写出。一些貌似永远记不清的 API 只是因为用得不够多而已。 在做面试官时,我从来不强求开发者准确无误地“背诵” API。相反,我喜欢从另外一个角度来考察面试者:“既然记不清使用方法,那么我告诉你它的使用方法,你来实现一个吧!”实现一个 API,除了可以考察面试者对这个 API 的理解,更能体现开发者的编程思维和代码能力。对于积极上进的前端工程师,模仿并实现一些经典方法,应该是“家常便饭”,这是比较基本的要求。 本小节,我根据了解的面试题目和作为面试官的经历,挑了几个典型的 API,通过对其不同程度,不同方式的实现,来覆盖 JavaScript 中的部分知识点和编程要领。通过学习本节内容,期待你不仅能领会代码奥义,更应该学习举一反三的方法。 API 主题的相关知识点如下: jQuery offset 实现这个话题演变自今日头条某部门面试题。当时面试官提问:“如何获取文档中任意一个元素距离文档 document 顶部的距离?”熟悉 jQuery 的同学应该对 offset 方法并不陌生,它返回或设置匹配元素相对于文档的偏移(位置)。这个方法返回的对象包含两个整型属性:top 和 left,以像素计。如果可以使用 jQuery, 我们可以直接调取该 API 获得结果。但是,如果用原生 JavaScript 实现,也就是说手动实现 jQuery offset 方法,该如何着手呢? 主要有两种思路: 通过递归实现通过 getBoundingClientRect API 实现递归实现方案我们通过遍历目标元素、目标元素的父节点、父节点的父节点......依次溯源,并累加这些遍历过的节点相对于其最近祖先节点(且 position 属性非 static)的偏移量,向上直到 document,累加即可得到结果。 其中,我们需要使用 JavaScript 的 offsetTop 来访问一个 DOM 节点上边框相对离其本身最近、且 position 值为非 static 的祖先元素的垂直偏移量。具体实现为: ...

May 24, 2019 · 7 min · jiezi

CSS基础入门之float

前几天有小伙伴说对float的学习云里雾里的,下面我就给大家说一下关于float的一些问题。 在css中,是存在流的概念的。在正常情况下,页面总是从左到右,从上到下布局,这种被称为正常的流。但是有很多情况,正常流是没办法实现的,因此我们需要一些手段来破坏流,从而实现一些特殊的布局,而本节的主角float就具备破坏流的特性。 float设计的初衷很多新手在布局的时候,总喜欢用float来实现。例如一个三栏布局,左右固定,中间自适应,有些人会通过float来一列一列把它们砌起来。这样的布局极其容易崩溃,只要高度或者宽度稍微有些变化,整个页面都会错乱。因此float设计的初衷并不是用来布局的,其本意仅仅是实现图片文字环绕效果,即图片左浮动,文字环绕图片,如下图所示: .float { width: 150px;float: left;}.content { width: 400px;} <div> <img src="./card.jpg" alt="" class="float"><p class="content">文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕</p></div> float的特性很多新手一个元素设置了float属性,会表现出如下特性:包裹性 块状格式化上下文破坏文档流没有margin合并 包裹性包裹性包含了包裹和自适应两个特性。包裹指的是一个浮动元素,如果子元素宽度足够小,则浮动元素的宽度就是该子元素的宽度,如下所示:.float { float: left;}<p class="float"> <span>这是浮动元素的子元素</span></p>自适应指的是如果浮动元素的父元素有设置宽度,并且浮动元素的子元素宽度超出了父元素,则浮动元素的宽度最终表现为父元素的宽度,如下所示: .father { width: 100px;} .float { float: left;} <div class="father"> <p class="float"> <span>这是浮动元素的子元素</span></p></div> 块状格式化上下文设定了float的元素,其display的最终值会表现为block或者table,具体转换如下表:设定值计算值inlineblockinline-blockblockinline-tabletabletable-rowblocktable-row-groupblocktable-columnblocktable-column-groupblocktable-cellblocktable-captionblocktable-header-groupblocktable-footer-groupblock因此,设置了float的元素,下面的写法是多余的: .float { float: left: display: block;}.float { float: left; vertical-align: middle; /* 不起作用 */}格式化上下文属于BFC的内容,此处先不展开。 破坏文档流这是float最本质的特性,因此float设计的初衷就是破坏文档流。设置float的元素,会导致父元素高度塌陷,我们来看个例子: .float { float: left;} <div class="father"> <img src="./card.jpg" alt="" class="float"></div><p> 文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕</p>可以看到,父元素的高度为0,但这不是bug,而是float本身就是这样设计的,因此只有让父元素高度塌陷了,后面的元素才有机会浮上来。但是仅仅是这样还是不可以形成图片环绕效果的,不然文字浮上来就只会覆盖在图片上面。这里面还隐藏着一个特性:行框盒子和浮动元素的不可重叠性意思是说行框盒子和浮动元素不会发生重叠,因此,下面的文字浮上去之后才不会覆盖在图片之上。即使我们给文字设置margin负值也不会起作用。 没有margin合并设置了float的元素,由于形成了BFC,因此也就没有了margin合并。 float作用机制我们先来看个例子:.float { float: right;}<div> <span>标题</span><a class="float">链接</a></div>在标准浏览器下,“标题”和“链接”会在同一行展示,并且“链接”会浮动在右边。但是如果“标题”非常长,一行放不下呢,“链接”是浮动在第一行还是第二行呢?答案是第二行,要想解释这个,我们得先理解两个概念,一个是“浮动锚点”,一个是“浮动参考”: 浮动锚点是float元素所在的“流”中的一个点,这个点本身并不浮动,表现得就像是一个没有margin、padding和border的空的内联元素。浮动参考指的是浮动元素对齐参考的实体。float元素的“浮动参考”是行框盒子,也就是float元素在当前“行框盒子”内定位,因此,上面的例子“链接”会在第二行展示。但是也有一种情况是,浮动元素前后并没有内联元素,因此也就不存在行框盒子,这时候就是“浮动锚点”在起作用。因为“浮动锚点”表现得像一个内联元素,有内联元素,自然就有行框盒子,只是这个盒子看不见也摸不着罢了。 float实现流体布局前面文字环绕的例子,只要稍微改造一下就可以实现两栏或多栏的自适应布局,代码如下: .father { overflow: hidden;height: 200px;} .float { float: left;width: 100px;} .content { margin-left: 120px;} ...

May 24, 2019 · 1 min · jiezi

2019-再聊移动端-300ms-延迟及-fastClick-原理解析

前言最近公司新开了一条业务线,有幸和大佬们一起从头开始构建一套适合新业务的框架。俗话说得好呀,适合自己的才是最好的 ????。在新项目的 CodeReview 的时候,被大哥提到有没有添加 fastClick 解决移动端 300ms 延迟的问题。以下就带你追溯移动端延迟的 前世 今生。 介绍前世 - 诞生的因国外有一篇关于 300ms 延迟的文章:What Exactly Is..... The 300ms Click Delay 世间万物皆有因果,网页兴起于桌面端,那时候有谁会想到手机等移动设备的风靡?犹记得上大学那会儿,手机访问学校网站的时候都是通过手指缩放来控制的 ????,心里真的是一万头草泥马奔腾而过,后来为了解决移动端适配的问题,提出了 viewport 的解决方案,基于 无障碍(accessibility)(需要代理)交互设计师为了更好的用户体验,特地提供了 双击缩放 的手势支持。殊不知这正是一切祸乱的根源。 今生 - 消逝的果谷歌有开发者文档: 300ms tap delay, gone away(需要代理) 以下是原文的部分引用 For many years, mobile browsers applied a 300-350ms delay between touchend and click while they waited to see if this was going to be a double-tap or not, since double-tap was a gesture to zoom into text.大致是说,移动浏览器 会在 touchend 和 click 事件之间,等待 300 - 350 ms,判断用户是否会进行双击手势用以缩放文字。 ...

May 24, 2019 · 3 min · jiezi

ES7Decorator装饰者模式

装饰模式仅仅包装现有的模块,使之 “更加华丽” ,并不会影响原有接口的功能 —— 好比你给手机添加一个外壳罢了,并不影响手机原有的通话、充电等功能;使用 ES7 的 decoratorES7 中增加了一个 decorator 属性,它借鉴自 Python 下面我们以 钢铁侠 为例讲解如何使用 ES7 的 decorator。 以钢铁侠为例,钢铁侠本质是一个人,只是“装饰”了很多武器方才变得那么 NB,不过再怎么装饰他还是一个人。 我们的示例场景是这样的 首先创建一个普通的Man类,它的抵御值 2,攻击力为 3,血量为 3;然后我们让其带上钢铁侠的盔甲,这样他的抵御力增加 100,变成 102;让其带上光束手套,攻击力增加 50,变成 53;最后让他增加“飞行”能力【Demo 1】对方法的装饰:装备盔甲创建 Man 类: class Man{ constructor(def = 2,atk = 3,hp = 3){ this.init(def,atk,hp); } init(def,atk,hp){ this.def = def; // 防御值 this.atk = atk; // 攻击力 this.hp = hp; // 血量 } toString(){ return `防御力:${this.def},攻击力:${this.atk},血量:${this.hp}`; }}var tony = new Man();console.log(`当前状态 ===> ${tony}`);// 输出:当前状态 ===> 防御力:2,攻击力:3,血量:3代码直接放在 http://babeljs.io/repl/ 中运行查看结果,记得勾选Setting的Evaluate选项,和 options的选项为legacy创建 decorateArmour 方法,为钢铁侠装配盔甲——注意 decorateArmour 是装饰在方法init上的。 ...

May 24, 2019 · 4 min · jiezi

实用的-Web-布局技巧Flex-主轴上的自动外边距

问题描述先来看一个需求场景: 上图中需要实现在水平方向上子元素之间、子元素和父容器边框之间的间距要相等。 实现的方法有很多,我们这里要讨论的是:如何简洁地使用 Flex 布局来实现?我这里采用的方法是:使用自动的外边距在主轴上对齐。 自动的外边距在主轴上对齐我们先来看一下 MDN 关于这个的解释: ... 自动的外边距会占据全部的多余的空间——在一个块上设置自动的左右外边距可以使它居中。两边尽可能占据多的空间,块就被置于中间位置了。这很好理解:自动外边距将平分全部的剩余空间。下面就来尝试下这个方案吧,代码如下: <div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div></div>.container { display: flex; align-items: center; box-sizing: border-box; border: 2px dashed #7cb305; width: 600px; height: 200px; margin: auto;}.item { display: flex; justify-content: center; align-items: center; margin: 0 auto; width: 100px; height: 100px; background: #722ed1; border-radius: 50%; color: #fff; font-size: 22pt;}然后看一下效果: 貌似有点不对。仔细看看子元素之间的间距比到边框的大,大概是子元素到边框的两倍,跟我们预期的效果有差异。按照 MDN 的解释来看,自动的外边距会等分剩余空间,但为什么会出现上图的情况呢?下面来谈一下我的理解。 主轴剩余空间“分配权重”与子元素自动外边距的关系这个分配权重关系没有在 MDN 上找到相关解释,纯粹是个人见解,我们可以这样来理解: 如果一个子元素在主轴的一个区域(或方向)上声明了 margin-*: auto,那么这个空间的分配权重 + 1如果另外一个子元素也在同样的区域(或方向)上有自动外边距的声明,那么分配权重再 + 1在这些声明了自动外边距的区域上,剩余空间根据分配权重来划分间距大小首先,这个理解显然是可以满足 MDN 上的解释。然后我们再来看看上图的情况怎么解释: ...

May 24, 2019 · 1 min · jiezi

前端每日实战-168-视频演示如何利用-Web-Animation-API-制作一个切换英语单词的交互动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。 https://codepen.io/comehope/pen/byabeG 可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。 请用 chrome, safari, edge 打开观看。 https://scrimba.com/p/pEgDAM/cevPbkfB (因为 scrimba 不支持 web animation api,所以动画效果在视频播放过程中看不到,不过你可以随时暂停视频,手工刷新预览窗口查看动画效果) 源代码下载每日前端实战系列的全部源代码请从 github 下载: https://github.com/comehope/front-end-daily-challenges 代码解读本作品用于展示若干包含字母组合 OO 的单词,每点击一下,OO 就眨眨眼,同时更换一个单词。 整体开发过程分成 4 步,第 1 步用 CSS 实现页面的静态布局,后面 3 步用 JS 实现动画和业务逻辑。第 2 步实现单词中间字母 OO 的眨眼效果,第 3 步实现随机取单词的逻辑,第 4 步实现字符的切换动画。 眨眼动画和字符切换动画都是用 Web Animation API 实现的。虽然用 JS 写动画比用 CSS 要麻烦一些,但 API 提供了一些事件 handler,在字符切换动画中就是利用事件机制来精确控制动画和在动画过程中加入业务逻辑的。 下面开始编码。 一、静态布局:dom,cssdom 结构很简单,一个名为 .word 的 <p> 元素中包含了 4 个 <span> 子元素,每个子元素容纳一个字符: ...

May 23, 2019 · 3 min · jiezi

Hybrid开发

1. 为什么选择Hybrid开发方式Hybrid开发效率高、跨平台(M /58APP/英才APP)维护成本低,功能可复用针对新手友好,学习成本较低功能更加完善,性能和体验要比起web app好太多部分性能要求的页面可用原生实现Hybrid从业务开发上讲,没有版本问题,有BUG能及时修复缺点 相比原生,性能仍然有较大损耗不适用于交互性较强的app2. Hybird 提前掌握那些问题Hybrid中Native与前端各自的工作是什么Hybrid的交互接口如何设计资源缓存策略,白屏问题2-1 Hybrid中Native与前端各自的工作是什么Native与前端的界限,首先Native提供的是一宿主环境,要合理的利用Native提供的能力,要实现通用的Hybrid平台架构nativeUI组件、消息类组件通讯录、系统、设备信息读取接口与Native的互相跳转,比如H5如何跳到一个Native页面,H5如何新开Webview做动画跳到另一个H5页面账号信息管理 Native需要设计良好安全的身份验证机制资源访问机制 Native首先需要考虑如何访问H5资源,做到既能以file的方式访问Native内部资源,又能使用url的方式访问线上资源前端要做的事情就是封装调用Native提供的各种能力-Hybrid开发调试 2-2.webview 生命周期函数// 网页开始加载的时候调用- (void )webViewDidStartLoad:(UIWebView *)webView{}// 网页加载完成的时候调用- (void )webViewDidFinishLoad:(UIWebView *)webView{}// 网页加载错误的时候调用- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{}2-3 Hybrid交互设计-JSBridge1.Native调用前端页面的JS方法2.前端页面通过JS调用Native提供的接口两者之间的桥梁是Webview。app自身可以自定义url schema,并且把自定义的url注册在调度中心1.JS to native在每个版本会提供一些API,前端会有一个对应的框架团队对其进行封装,释放业务接口 /**login*/ CHRJSBridge.call("pagetansNative", { action: "pagetansNative", //type类型是跳转native的 params: { controllername: "to_login" //跳转native的对应页 }, isbacktomain: 0, //跳转后是否关闭当前,默认false callbackFun:(params)=>{this.id=params.id}// 回调函数 });handleConfirm(params) { let jsonStr = JSON.stringify(params); if (this.isIOS()) { window.webkit.messageHandlers.testMethod.postMessage(jsonStr) } else { javascript: chrclient.onJsActionRequest(jsonStr) }}## native to js ...

May 23, 2019 · 1 min · jiezi

记录一下js遍历

记性不好,记录一下。遍历数据,拼接入ul标签中。 <html> <body> <ul id="num"> </ul> </body> <script src="https://code.jquery.com/jquery-3.4.0.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ var arr = [1,2,3,4,5]; for(var i=0;i<arr.length;i++){ var num = '<li>'+arr[i]+'</li>'; $("#num").append(num); } }); </script></html>结果

May 23, 2019 · 1 min · jiezi

CSS阴影效果的比较dropShadow与boxShadow

drop-shadow与box-shadow都是阴影效果(光晕效果)的css属性,二者最大的不同点在于:box-shadow只能制作矩形的阴影,而drop-shadow则可以制作和物件不透明区域完全相同形状的阴影。底下是二个css属性的用法: .drop-shadow { -webkit-filter: drop-shadow(12px 12px 7px rgba(0, 0, 0, 0.7)); filter: drop-shadow(12px 12px 7px rgba(0, 0, 0, 0.7))}.box-shadow { box-shadow: 12px 12px 7px rgba(0, 0, 0, 0.7);}因为都是阴影效果(光晕效果),所以二者可以设定的参数(value)几乎一样:以上面的例子来说,参数的所有数值从左到右代表了:水平偏移,垂直偏移,阴影模糊距离阴影颜色。 接下来将为您进一步比较drop-shadow与box-shadow 边框和变形效果 drop-shadow与box-shadow的阴影都可以反应出边框圆角和变形效果。不同的是:drop-shadow反应出实际边框的形状、实线框有实线的影子、虚线框有虚线的影子;box-shadow则是把边框和里面的内容当成是一个完整的方块、并制造出整个方块的影子,而边框的样式会被忽略,直接当成是实线框。 .box { border: 5px solid #262b57; width: 120px; height: 120px; border-radius: 10px; transform: rotate(15deg); font-size: 40px; text-align: center; line-height: 120px;}.dashed { border-style: dashed;}背景与透明度 如果方块有设定颜色(不是透明的),drop-shadow与box-shadow的阴影效果看来就会差不多。如果方块的背景是半透明的呢?我们可以从图片中发现,影子周围的颜色比较深,中间的颜色比较淡,所以可以推论出透明度对drop-shadow会造成影响、对box-shadow则没有影响。 .bk { background-color: #ffcc66;}.bk-alpha { background-color: rgba(255, 204, 102, 0.3);}图形边框(image border) ...

May 23, 2019 · 1 min · jiezi

优秀博文收藏

工具类nvm: node版本管理nrm: 快速切换npm源shell: zsh+on-my-zsh配置教程指南sourcetree: git可视化工具前端工具集: WEB前端助手(FeHelper)网络封包截取工具 charles(mac)格式化工具 textLab(mac)标注工具 markman模拟请求 postmanCSS类深入浅出CSS布局你所不知道的 CSS 动画技巧与细节CSS常用代码CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅一劳永逸的搞定 flex 布局JavaScript类10分钟理解JS引擎的执行机制前端做模糊搜索数组的遍历你都会用了,那Promise版本的呢javascript 总结(常用工具类的封装)很全很全的前端本地存储讲解ajax跨域,这应该是最全的解决方案了学习路线 学完这些去阿里!GOGOGO浅谈script标签的defer和async面试的信心来源于过硬的基础Vue类详解vue中静态资源的路径问题(深度好文)从1万篇文章中挑出的40篇最棒的 Vue 学习指南(2018版)浅谈使用 Vue 构建前端 10w+ 代码量的单页面应用开发底层如何写一手漂亮的 Vue基于vue-cli的webpack配置优化剖析Vue原理&实现双向绑定MVVMvue 实现 ios 原生picker 效果(实现思路分析)如何理解Vue的render函数Vue 脱坑记 - 查漏补缺VUE使用中踩过的坑移动端HTML5中手势原理分析与数学知识的实践转载一篇关于移动端web常见问题解决方案完善的输入框监听方案:兼容、高效和组合输入友好移动端样式小技巧H5项目常见问题及注意事项工程化package.json的所有配置项浅谈前端测试webpack 教程资源收集ESLint配置参数介绍从网易与淘宝的font-size思考前端设计稿与工作流使用 VSCode + ESLint 实践前端编码规范请练完这16个webpack小例子安全你不曾察觉的隐患:危险的 target="_blank" 与 “opener”浅谈前端安全其他程序员如何优雅的挣零花钱14个你可能不知道的JavaScript调试技巧

May 23, 2019 · 1 min · jiezi

html5调用手机摄像头

曾经做过一个项目,仿照当下最火的军装照页面,做出图片融合效果。当时的整个项目组都动容了,太难了,总共用了三种方案 1、canvas 2、python opencv3、C++ 这些不是重点,重点是在上传照片调取摄像头功能 上传照片 <input type='file'>标签,如果调用摄像头,很多小伙伴就会想到js各种API,但最终一无所获,其实html5就可以解决 <input type="file" accept="image/*" capture="camera"><input type="file" accept="video/*" capture="camcorder"><input type="file" accept="audio/*" capture="microphone">capture表示可以捕获到系统默认的设备accept表示直接打开系统文件目录camera表示摄像头camcorder表示摄像机microphone表示录音 在给大家普及一下multiple属性,表示可以支持多选 <input type="file" accept="image/*" multiple> 加上multiple标签 capture就没什么用了,注意:本人亲测,multiple在ios下好用,android下不好使 虽然javascript是弱类型语言,受限于设备,但是随着技术的逐渐更新,设备机能的逐渐高新,我相信javascript逐渐会越来越强大的。

May 23, 2019 · 1 min · jiezi

微信小程序wepy框架学习和使用心得

一、微信小程序wepy框架简介:微信小程序WePY框架是腾讯官方推出来的框架,类似的框架还有美团的mpvue,京东的Taro等; 目前公司开发小程序主要用到的是微信原生方法和官方的wepy框架; wepy框架在开发过程中参考了 Vue 等现有框架的一些语法风格和功能特性,对原生小程序的开发模式进行了再次封装,更贴近于 MVVM 架构模式, 并支持ES6/7的一些新特性。相对更容易上手,提高开发效率; 二、WePY项目的创建与目录结构WePY的安装或更新都通过npm进行,全局安装或更新WePY命令行工具npm install wepy-cli -g在开发目录中生成Demo开发项目wepy new myproject切换至项目目录cd myproject 安装依赖npm install开启实时编译wepy build --watchWePY项目的目录结构如下 ├── dist 小程序运行代码目录(该目录由WePY的build指令自动编译生成,请不要直接修改该目录下的文件) ├── node_modules ├── src 代码编写的目录(该目录为使用WePY后的开发目录) | ├── components WePY组件目录(组件不属于完整页面,仅供完整页面或其他组件引用) | | ├── com_a.wpy 可复用的WePY组件a | | └── com_b.wpy 可复用的WePY组件b | ├── pages WePY页面目录(属于完整页面) | | ├── index.wpy index页面(经build后,会在dist目录下的pages目录生成index.js、index.json、index.wxml和index.wxss文件) | | └── other.wpy other页面(经build后,会在dist目录下的pages目录生成other.js、other.json、other.wxml和other.wxss文件) | └── app.wpy 小程序配置项(全局数据、样式、声明钩子等;经build后,会在dist目录下生成app.js、app.json和app.wxss文件) └ ── package.json 项目的package配置搭建好项目后,IDE需配置代码高亮,文件后缀为.wpy,可共用Vue的高亮规则,但需要手动设置,具体配置大家可参考wepy官方文档三、wepy使用心得总结:wepy代码风格类似Vue,如computed,data,methods等用法差不多,熟悉vue开发的同学看看文档可以轻松上手,不过还是有很多地方写法容易混淆,我工作中遇到的总结几个,如列表循环,条件渲染,父子组件值传递等,下面举例说明: 1). wepy和vue列表循环对比: // wepy 列表循环,外面可套一层repeat标签,注意和vue写法的区别 <repeat for="{{list}}" key="index> <view>{{item}}</view> </repeat> // vue 列表循环,外面可套一层template标签 <template v-for="(item,index) in list" :key="index"> // 不推荐key直接用索引index <div>{{item}}<div> </template> 2). wepy和vue条件渲染中,wepy需要加{{}},vue不需要,里面都可以写表达式进行判断: <view wx:if="{{show}}"></view> <div v-if="show"></div> 3). 父子组件值传递两者都在子组件中用props接收, props中可以定义能接收的数据类型,如果不符合会报错, wepy可以通过使用.sync修饰符来达到父组件数据绑定至子组件的效果,也可以通过设置子组件props的 twoWay:true来达到子组件数据绑定至父组件的效果。那如果既使用.sync修饰符,同时子组件props中 添加的twoWay: true时,就可以实现数据的双向绑定了; // parent.wpy <child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child> data = { parentTitle: 'p-title' }; // child.wpy props = { // 静态传值 title: String, // 父向子单向动态传值 syncTitle: { type: String, default: 'null' }, twoWayTitle: { type: String, default: 'nothing', twoWay: true } }; onLoad () { console.log(this.title); // p-title console.log(this.syncTitle); // p-title console.log(this.twoWayTitle); // p-title this.title = 'c-title'; console.log(this.$parent.parentTitle); // p-title. this.twoWayTitle = 'two-way-title'; this.$apply(); console.log(this.$parent.parentTitle); // two-way-title. --- twoWay为true时,子组件props中的属性值改变时,会同时改变父组件对应的值 this.$parent.parentTitle = 'p-title-changed'; this.$parent.$apply(); console.log(this.title); // 'c-title'; console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修饰符的props属性值,当在父组件中改变时,会同时改变子组件对应的值。2.wepy支持自定义组件开发,实现组件复用,减少代码冗余,提高开发效率; ...

May 23, 2019 · 2 min · jiezi

CSS3-filter滤镜属性

css3的滤镜filter属性,可以对网页中的图片进行类似Photoshop图片处理的效果,例如背景的毛玻璃效果、老照片(黑白照片)、火焰效果等。 一、blur(px)高斯模糊 二、brightness(%)亮度 三、contrast(%)对比度 四、drop-shadow()阴影 注意: 这个 drop-shadow 与 box-shadow 都是在说阴影,但还是有区别的,看下图 图中火焰的图片,是一张png图片,除了火焰以外,其他部分是透明的,我们能看见,box-shadow 是给整个图片加阴影,而 drop-shadow 只是给不透明的部分加阴影,这是他们最重要的区别了。 五、grayscale(%)灰度 六、hue-rotate(deg)色相旋转 七、invert(%)反转 八、opacity(%)透明度 九、saturate(%)饱和度 十、sapia(%)深褐色 上面都只是把每种滤镜单独拿出来,展示效果,但是其实他们是可以一起使用的,比如这样 .all img{ filter: brightness(120%) contrast(110%) saturate(120%) hue-rotate(-25deg) drop-shadow(0 0 5px #000);}

May 23, 2019 · 1 min · jiezi