Phenom
Phenom
前些日子在做滴滴的七夕h5的时候,在调试手机适配上花了不少时间,一直没有一个完美的通用的适配算法,都是头疼医头,脚痛医脚,导致状况百出。 由于设计图是以iphone6作为基准的,于是一开始打算用设计图的宽度(750px)作为基准值,将根元素的font-size设为当前屏幕宽度与基准值的比: ```css html { font-size: calc(100vw/7.5) } ``` 设定了根元素的font-size,我就可以根据设计图的尺寸直接转换为rem来布局: ```css .box { width: 20rem; } ``` 但是最后发现效果并不如我想的那样,因为我选的基准值是基于设计图宽度的,所以只有在x轴方向的尺寸可以适配,在y轴方向上的尺寸适配不了。估计这种方法只适用于要横轴适应的SPA,而不是横纵都要适配的h5游戏。最后只能用屏幕高度与设计图高度的比作为基准值,也就是`calc(100vh/6.67)`,x轴方向尺寸用百分百,也算是一直暴力解决方法吧。 后来我就想这个rem布局方式是否可以改进,其实方法无非就两个,一个是xy轴同时拉伸适配,一种是页面等比例缩放适配。但是头疼的是根元素的font-size属性只有一个,不能设置两个基准值。如果用页面缩放的思路,只能用js控制transform,或者动态改变meta的值。 transform方法太简单粗暴,而且估计效果也不会很好,我就放弃了,尝试用js控制meta的content: ```javascript const meta = document.getElementsByTagName('meta')[1], //缩放比例为:当前手机面积/设计图基准面积 scale = document.documentElement.clientHeight*document.documentElement.clientWidth/(375*667); meta.setAttribute('content',...
作为微软忠实用户,Windowsphone,win8,win10一路走来,一直都很喜欢里面的一样东西,就是bing提供的锁屏壁纸,都很唯美。网络上已经有很多很成熟的bing壁纸下载工具了,但是这次我决定自己做一个,以node模块形式的,虽然很简陋,但是这不重要,贵在学到东西。 **首先确保电脑已经安装node和npm环境** 第一步:编写主代码 首先先要把获取bing壁纸的api找出来,我在网上找到一个 http://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1 访问后浏览器返回了如下信息: ```javascript { "images": [{ "startdate":"20170920", "fullstartdate":"201709201600", "enddate":"20170921", "url":"/az/hprichbg/rb/CorricellaMarina_ZH-CN11169480773_1920x1080.jpg", "urlbase":"/az/hprichbg/rb/CorricellaMarina_ZH-CN11169480773", "copyright":"普罗奇达岛,意大利那不勒斯湾 (© Frank Chmura/age fotostock)", "copyrightlink":"http://www.bing.com/search?q=%E6%99%AE%E7%BD%97%E5%A5%87%E8%BE%BE%E5%B2%9B&form=hpcapt&mkt=zh-cn", "quiz":"/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20170920_CorricellaMarina%22&FORM=HPQUIZ", "wp":true, "hsh":"d2bbe5539a47b4d03a5bc541d09a9ecf", "drk":1, "top":1, "bot":1, "hs":[] }], "tooltips":{...
箭头函数`() => ()`是ECMAScript2015中代替`function`的一个语法糖,他增强了JS中Functional programming的能力。箭头函数与传统的`functuon(){}`声明并没有什么区别,但是在表现上,还是有一点微小区别的,而且这微小区别如果处理不好就会出现大bug。 先看看官方对箭头函数与function的区别的定义: > 1、对 this 的关联。函数内置 this 的值,取决于箭头函数在哪儿定义,而非箭头函数执行的上下文环境。 2 、new 不可用。箭头函数不能使用 new 关键字来实例化对象,不然会报错。 3、this 不可变。函数内置 this 不可变,在函数体内整个执行环境中为常量。 4、没有arguments对象。更不能通过arguments对象访问传入参数。只能使用显式命名或其他ES6新特性来完成。 第四点不重要,重要的是前三点,简单来说,就是箭头函数和function对内部的this的处理是不一样的。function内部的this由function决定,而箭头函数的this则由上下文决定。下面来看一个小例子: ```javascript const obj = { a: function() {...
在通常情况下,我们给一组DOM节点添加相同的事件,都是使用循环绑定: ```javascript Array.from(document.querySelectorAll('li')) .map(li => li.addEventListener('click', handler)); ``` 当节点数量比较少的时候,这是最简单直接的方法,没有问题。但是当节点数量达到一定数量级的时候(数千甚至上万,比如表格应用),给这么多个节点都循环绑定相同一个事件,显然会造成资源浪费,而且影响性能。 ## 为什么浪费资源和影响性能 很多人在谈到大量节点的事件绑定的时候,都说浪费资源,但是很少会提到说为什么会浪费资源,下面我就来分析一下。 首先,在初始化页面的时候,我们先要对这些节点进行一次遍历,DOM节点(也就是HTMLElement)是一个很大很庞杂的对象,遍历DOM节点要比遍历普通数组更耗时。 我们来看看一个DOM节点(HTMLElement)究竟包含了什么东西:    很多很恐怖,这只是一个简单的只有文本子节点的`li`,这也说明了为什么使用虚拟DOM会更快。 第二,在我们遍历节点的同时,我们还要给每个节点添加事件,也就是给节点(或者其_proto_)添加二极的DOM事件。 另外,大家都知道,为每个DOM节点绑定事件后都会有一个`event`对象被当做参数传入事件函数里面,`event`对象包含了当前事件发生的信息,这个`event`对象也是一个很庞大的对象:  所以,总结起来,大量DOM节点的事件绑定造成资源浪费和性能损失原因主要有3: - **DOM节点循环的耗时** - **给每个DOM节点添加事件** - **每个`event`对象的创建** ## 使用事件委托...
JS中的深拷贝
**深拷贝(deep copy)** 算是js里面比较久经不衰的话题,论坛爱讨论,面试也爱考。何为深拷贝?其实就是实现对一个**引用类型**的完整复制。 **什么是引用类型?** js中有**值类型**和**引用类型**两种类型,基本类型就是像`number`,`boolean`这些。值类型在定义的时候,会在**栈内存**为其分配一个**固定**的空间。 而引用类型比较特殊,它的大小是**不固定**的,所以在定义引用类型的时候,解析器会在**堆内存**为其分配空间,然后再在栈内存分配一个指向堆内存里该内存空间的指针。 ```javascript const obj = {}, arr = []; ``` 在内存中地址分配如图:  js中的引用类型有三种: - Array - Object - String > 其实严格来说 `String(字符串)` 也算其中一种,但是比较特殊,因为字符串具有可变的大小,所以显然它不能被直接存储在具有固定大小的变量中。由于效率的原因,我们希望JS只复制对字符串的引用,而不是字符串的内容。但是另一方面,字符串在许多方面都和基本类型的表现相似,而字符串是不可变的这一事实(即没法改变一个字符串值的内容),因此可以将字符串看成行为与基本类型相似的不可变引用类型。 > 也就是说,我们平时在引用字符串的时候引用的是地址,而修改字符串的时候得到的是字符串的拷贝。这一篇文章不会讨论字符串的拷贝。...
这篇文章会解开虚拟DOM的神秘面纱,让你对React底层有一个大概的了解,或者对想实现一个虚拟DOM库的同学提供一个大概的思路。 ## 刀耕火种的年代 在jquery盛行的年代(其实现在jquery依旧很盛行),基本都是对DOM结构直接进行操作,但是当代码量一大的时候,要维护起来就要变得很困难,因为数据,逻辑和视图都混淆在了一起。 其实当时前端还没有**分层**的概念,因为大多数业务逻辑都被放在了后端。但是随着时代发展,浏览器端需要承担的责任越来越大,慢慢地前端逻辑也就变得复杂起来,传统的命令式编程思维已经明显不适用于**中大型**项目,前端圈继续一些新的设计模式来革新传统的编码方式。 之后各种MVVM框架应运而生,有AngularJS、avalon、Vue1.等,MVVM使用数据双向绑定,使得我们完全不需要操作DOM了,更新了状态视图会自动更新,更新了视图数据状态也会自动更新,可以说MMVM使得前端的开发效率大幅提升,但是其大量的事件绑定使得其在复杂场景下的执行性能堪忧;有没有一种兼顾开发效率和执行效率的方案呢?React就是一种不错的方案,虽然其将JS代码和HTML代码混合在一起的设计有不少争议(JSX),但是其引入的**虚拟DOM(Virtual DOM)** 却是得到大家的一致认同的。 **虽然React和Vue都是实现了虚拟DOM,但是毕竟React是先驱,所以下面我基本都会用React作为例子。** ## 虚拟DOM的思想 其实我之前已经提到过,DOM操作是很慢的,其元素非常庞大,页面的性能问题鲜有由JS引起的,大部分都是由DOM操作引起的。 但是我们发现,虽然一个DOM节点有N多个属性,但是我们平时在对DOM进行操作时,通常只需要以下3个基本信息: - **标签名:tagName** - **HTML属性:attribute** - **子节点:children** 对于其他属性我们并不关心,于是,我们可以对一段DOM进行以下抽象:  可以看到,一段DOM片段被抽象成了**JS对象**,对应着节点的**tagName**,**attribute**和**children**。 **这就是虚拟DOM的思想:用JS对象表示DOM。** 也就是说,当我们新建一个React组件的时候,在`render`方法中,return的是一个JS对象: ```javascript class NewComponent extends React.Component {...
我们在使用ajax的时候,出于方便,通常使用jquery的`$.ajax()`方法,简单快捷,帮助我们屏蔽了许多底层的细节。久而久之我们很容易就会遗忘掉原生ajax的一些知识点,比如`XMLHttpRequest`。下面我就帮助大家对ajax的工作流程梳理一下。 `XMLHttpRequest`是ajax实现的基础,我们常常用它来对服务器发送一个异步请求: ```javascript //实例化一个XMLHttpRequest对象 const xhr = new XMLHttpRequest(); //onreadystatechange方法:判断当前请求的进度 xhr.onreadystatechange = function() { //当readyState的值为4时获取返回的值 if(xhr.readyState === 4) { console.log(xhr.responseText); } } //指定http方法和目标主机,建立连接 xhr.open('GET', 'localhost:8080'); //发送请求 xhr.send(); ``` 通常,一次http数据请求,要经过 ```html...
Javascript中的继承一直是一个难点,因为js有别于其他面向对象的语言,js是基于 **原型(prototype)** 的。 prototype是一个很难琢磨得透也很难掌握的东西,当然也许有人会跳出来说现在都用ES6,typescript啦,谁还学prototype。这样想就错了,首先,ES6和typescript远远没有你想的这么普及,谁敢把不经过编译的es6和ts直接放到线上跑?编译后还不是一样回到prototype。其次,prototype能干的事情多的去了,不单单只是new或继承几个类,有兴趣可以看看Vue的响应式数组方法是怎么做的。 扯远了,今天写这篇东西是因为刚刚看到了一篇关于js继承的文章,想把一些思考和总结记下来。 ## 如何实现继承 为什么在js中继承很麻烦? - **因为js中没有`extends`关键字(ES6前)** - **因为js既能访问到实例属性也能访问到原型属性** - **js对象是引用类型** 一点一点来分析。 ### 壹 首先在ES6之前,js中是没有又甜又可爱的`extends`语法糖的,那要继承怎么办,只能自己在现有的js语法里面各种找方法实现(而且还不好找)。 ### 貳 其次,在一个js对象中,既有来自构造函数的属性,也能访问到其`_proto_`,也就是构造函数的`prototype`的属性(通常是方法)。这么理解这句话呢?看下面的例子: ```javascript const Foo = function() { this.count = 20;...
最近再做一个类似滑块控件的东西,按道理来说滑块控件应该是挺好做的,没什么难度。但是具体做的时候却遇到了一点点小波折,就是类似下面这种滑块的实现:  主要难点就在于这种滑块的滑动点不是连续的,而是离散的。连续的还比较好做,只要获取鼠标的`clientX`然后转换成控件圆点的`left`就行。 那么,离散的要怎么实现? 先不急,我们先仔细观察一下这个控件,看看有什么规律可循。其实正常人都能看出来,控件小圆点在哪个离散点取决于鼠标的相对离散点的最近距离。 假如控件有A,B,C三个离散断点,离散点之间的距离我们取个中点,以这些中点为分界点,鼠标在中点左侧,则小圆点在左侧离鼠标最近那个离散点,若鼠标在中点右侧,则小圆点在右侧离鼠标最近那个离散点。画个图好理解一点:  假如ABC之间距离都为100,那么鼠标在`< 50`的位置时小圆点在A上,`>= 50 && < 150` 小圆点在B上,`>= 150`小圆点在C上,以此类推。 ## 实现 现在知道了原理,但是怎么用代码实现呢? 当时想了挺久的,一开始打算用简单粗暴`if else`判断鼠标位置: ```javascript /** * x为鼠标横坐标 */ if(x < 50) { //.......
平时在做项目或者造轮子的时候,经常会有这样一个需求: **当页面内容超出屏幕,页脚模块会像正常页面一样,被推到内容下方,需要拖动滚动条才能看到。而当页面内容小于屏幕高度,页脚模块会固定在屏幕底部,就像是底边距为零的固定定位。**  这种特殊的布局方式,就叫**固定底部(Sticky Footer)**。 以前我曾经碰到过类似的需求,当时情况并不允许使用flex,于是一直束手无策,所以Sticky Footer算是我一直存在的CSS的一个知识漏洞,现在掌握了,赶紧记下来。 ## Sticky Footer的主要实现方式 Sticky Footer的实现方式有不少,我这里就只介绍最常用的3种。 很多文章介绍Sticky Footer实现方法的时候,喜欢将flex方法放在最后一位,然而我会放在第一位,原因是他们是按照CSS属性的常用程度来排序的,我这里会按照理解难易程度来排序。 下面所有的例子都会以这样的基础HTML来实现: ```html Content Footer ``` ### 壹:FLEX flex方法应该是最简单方便的实现方式了,只要记住理解每个flex属性,就很容易实现一个Sticky Footer。一个简单地例子: ```css body { padding: 0; margin: 0;...