你不知道的JavaScript(中)读书笔记
你不知道的JavaScript(上)读书笔记
简单实现一个步骤条
代码部分参考ElementUI的步骤条结构,如果作为组件,循环判断每个步骤的状态,加上对应的class即可。这里定义pass、current、future,每个状态都有不同的样式。这里是横版的,竖版的大同小异
特别要注意横线的处理,移位的方法
JavaScript高级程序设计笔记
全局函数isNaN()的问题
isNaN()去执行一个非数字字符串,会返回true,注意。
因为isNaN()的本意是去判断这个参数是否”不是数值”,任何不能被转为数值的值都会导致这个函数返回true,注意,即首先对参数进行一次Number转换,返回为NaN的参数会被判断为NaN
1 | alert(isNaN(NaN)); //true |
解决方案有两种:
利用NaN是唯一一个与自身严格不相等的值:
1 | function myIsNaN(value) { |
在使用isNaN()之前先检查一下这个值是不是数字类型,这样就避免了隐式转换的问题:
1 | function myIsNaN2(value) { |
null进行数值转换为0,undefined进行数值转换为NaN
js将字符串转换为dom元素的方法,利用childNodes
1 | function parseDom(arg) { |
注意:childNodes返回的是一个类似数组的list。所以如果是一个元素,要使用这个dom需要这样使用obj[0]。如果是多个同级的dom转换,可以这样使用obj[0]、obj[1]…
js获取元素的兄弟元素
1 | var siblings = function (el) { |
new原理
使用构造函数,要创建新的实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4
个步骤:
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象。
实现代码:
1 | var Person = function (name, age) { |
JS工作经验总结(2)
本文主要记录工作时JS问题或经验
new Array()的遍历问题
new Array(3)这样得出的稀疏数组不能够进行遍历,需要进行特殊的转义才能够遍历
webkitTransitionEnd监听Transition动画结束事件
css3的过渡属性transition,在动画结束时,也存在结束的事件:webkitTransitionEnd; 注意:transition,也仅仅有这一个事件。
1 | $el.addEventListener('webkitTransitionEnd', handler, false); |
css3的动画animation也能够监听事件,分别在开始和结束时都能够监听到animationstart,animationend
阻止冒泡问题
stopPropagation()
方法既可以阻止事件冒泡,也可以阻止事件捕获
stopImmediatePropagation()
和 stopPropagation()
的区别在,后者只会阻止冒泡或者是捕获。 但是前者除此之外还会阻止该元素的其他事件发生,但是后者就不会阻止其他事件的发生
arguments的问题
arguments
不是一个真正的数组,是一个类数组,无法使用shift
等数组方法,只能使用Array.prototype.slice.apply(arguments)
转换成真正的数组,或者使用[].shift.call(arguments)
之类的方法来调用数组的方法
img作为数据统计的问题
img经常进行用于数据上报,做用户埋点什么的,消息已读什么的,就是将query放在图片的请求地址上就可以了。需要注意在使用img进行http请求时,img对象需要存储在闭包里,避免函数执行后,里面的变量在http请求完成前被销毁,导致发送不成功,会造成请求丢失的问题
例子(使用闭包封装img变量,避免销毁):
1 | var tracker = (function() { |
JS工作经验总结(1)
本文主要记录工作时JS问题或经验
html里自定义属性的赋值和取出问题
给html元素写入data-type
这样的格式,可以使用el.dataset.type
进行相对应的访问;\
在不兼容dataset的情况下,可以使用更原始的el.getAttribute(name)
进行取值,使用el.setAttribute(name, value)
进行赋值
document.activeElement的应用(焦点问题)
document.activeElement.tagName
可获得当前获得焦点的元素,document.activeElement.blur()
使当前获得焦点的元素失焦
关闭webApp中的调起的系统键盘
window.nativeKeyboradCancel()
,在webApp里取消调起系统的键盘,如果有的话
循环遍历父元素的方法
以下可以使用while一直遍历父元素:
1 | function getTagName(ele) { |
Vue工作经验总结(1)
本文主要记录工作时使用Vue时的问题或经验
关于使用v-model传值给组件的语法糖
template:
1 | <currency-input v-model="price"></currentcy-input> |
1 | Vue.component('currency-input', { |
这样使用v-model就可以不用像注释里一样,在组件emit一个自定义事件,在外面接住,这样写在里面修改,外面就能接收到传过来的value,并且将其改写,响应data
事件修饰符.native的使用场景
关于加了native和不加的区别,使用以下代码说明:
定义自定义组件vButton:
1 | <button type="button" @click="clickHandler"></button> |
1 | export default { |
引用自定义组件vButton时事件的触发情况:
1 | <v-button @click="clickHandler" @vclick="vClickHandler">按钮</v-button> |
1 | import vButton from '@/components/Button' |
如果将上面模版改成:
1 | <v-button @click.native="clickHandler" @vclick="vClickHandler">按钮</v-button> |
那么两个事件都会执行,.native
修饰符就是用来注册元素的原生事件而不是组件自定义事件的
意思就是当你给一个vue组件绑定事件时候,要加上.native
,如果是普通的html元素就不需要。
使用v-if、v-else-if、v-else处理显示
注意v-else-if和v-else前一兄弟元素必须有 v-if 或 v-else-if,v-else。链式调用可以更好的处理template显示逻辑
class条件判断绑定问题
:class={ active: isActive }
的时候左边可以不加引号,也可以加上active这个class,右边是props或data或computed的数据
在template使用引用静态文件(img等)
vue,webpack中,template中可以使用~+alias
配置名称,js里可以使用import和require引用静态图片地址
父子组件和非父子组件的传值问题
父子组件:使用@和$emit传值;\
非父子组件:eventBus或vuex。
filter使用技巧
filter可以的到第二,第三,以此类推个参数,在使用filter的时候使用filterA(arg1, agr2, …)传入,第一个参数就是值本身
vux如何通过v-model显示组件的问题
vux是通过v-model传入value作为props,然后value用v-if控制组件的显示与否
对象watch问题
有三种方法,推荐第二、三种方法,可以拿到oldValue,直接检测对象是拿不到oldValue的:
关于table-cell实现的各种布局
display:table-cell
指让标签元素以表格单元格的形式呈现,使元素类似于td标签。IE8+及现代版本的浏览器都支持此属性,IE6/7不支持(可用其他方法实现类似效果)。同样,display:table-cell属性也会被float,position:absolute等属性破坏效果,应避免同时使用。
设置了display:table-cell的元素:
- 对宽度高度敏感
- 对margin值无反应
- 响应padding属性
- 内容溢出时会自动撑开父元素
display:table-cell的几种用法
1.大小不固定元素的垂直居中
1 | <div class="content"> |
1 | .content { |
补充一种多行文本垂直居中的方法:
1 | <div class="wrap"> |
1 | .wrap { |
2.两列自适应布局
1 | <div class="content"> |
1 | .content { |
左边头像部分使用了float左浮动属性,左侧使用 display: table-cell则实现了两列自适应布局。至于.right-box中的width:3000px解释引用别人的:
display:table-cell 元素生成的匿名table默认table-layout:auto。宽度将基于单元格内容自动调整。当内容足够多将宽度完全撑开时,再让某个元素(例如关闭按钮)右侧定位就会有问题。所以设置width:3000px的用途是尽可能的宽的意思。
对于IE6/7,我们可以使用display: inline-block属性代替。
3.等高布局
1 | <div class="content"> |
1 | .content { |
4.和inline-block组合使用
1 | <div class="content"> |
1 | .content { |
代码解释:A和B的父元素均设置了display:table-cell属性,所以
它们均匀占据设置了display:table的div元素。而A和B元素设置display:inline-block是为了让它们相应text-align的属性设置。
inline-block 是宽高margin设定有效,参与行内格式化上下文,在行内对齐时使用它自己的框底边为基线对齐位置
5.列表布局
1 | <div class="content"> |
1 | .content { |
这类布局常用浮动布局(给每个li加上float:left属性)实现,但这样做有明显不足:
- 需要清除浮动
- 不支持不定高列表的浮动
display:table-cell可以代替浮动布局,但是其不是最好的方法。其他方法有待进一步学习!
最后,说说“匿名表格元素创建规则”:
CSS2.1表格模型中的元素,可能不会全部包含在除HTML之外的文档语言中。这时,那些“丢失”的元素会被模拟出来,从而使得表格模型能够正常工作。所有的表格元素将会自动在自身周围生成所需的匿名table对象,使其符合table/inline-table、table-row、table- cell的三层嵌套关系。
简单来讲,我们为一个元素设置了display:table-cell属性,而不将其父元素设置为display:table-row属性,浏览器会默认创建一个表格行。
关于浏览器重排和重绘和一个重绘案例
什么是重排和重绘
浏览器下载完页面中的所有组件——HTML标记、JavaScript、CSS、图片之后会解析生成两个内部数据结构——DOM树
和渲染树
。
DOM树表示页面结构,渲染树表示DOM节点如何显示。DOM树中的每一个需要显示的节点在渲染树种至少存在一个对应的节点(隐藏的DOM元素disply值为none 在渲染树中没有对应的节点)。渲染树中的节点被称为“帧”或“盒”,符合CSS模型的定义,理解页面元素为一个具有填充,边距,边框和位置的盒子。一旦DOM和渲染树构建完成,浏览器就开始显示(绘制)页面元素。
当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。__这个过程称为重排__。完成重排后,浏览器会重新绘制受影响的部分到屏幕,__该过程称为重绘__。由于浏览器的流布局,对渲染树的计算通常只需要遍历一次就可以完成。但table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。
并不是所有的DOM变化都会影响几何属性,比如改变一个元素的背景色并不会影响元素的宽和高,这种情况下只会发生重绘。
重排和重绘的代价究竟多大
1 | var times = 15000; |
重排何时发生
很显然,每次重排,必然会导致重绘,那么,重排会在哪些情况下发生:
- 添加或者删除可见的DOM元素
- 元素位置改变
- 元素尺寸改变
- 元素内容改变(例如:一个文本被另一个不同尺寸的图片替代)
- 页面渲染初始化(这个无法避免)
- 浏览器窗口尺寸改变
这些都是显而易见的,或许你已经有过这样的体会,不间断地改变浏览器窗口大小,导致UI反应迟钝(某些低版本IE下甚至直接挂掉),现在你可能恍然大悟,没错,正是一次次的重排重绘导致的!
渲染树变化的排队和刷新
思考下面代码:
1 | var ele = document.getElementById('myDiv'); |
乍一想,元素的样式改变了三次,每次改变都会引起重排和重绘,所以总共有三次重排重绘过程,但是浏览器并不会这么笨,它会把三次修改“保存”起来(大多数浏览器通过队列化修改并批量执行来优化重排过程),一次完成!但是,有些时候你可能会(经常是不知不觉)强制刷新队列并要求计划任务立即执行。获取布局信息的操作会导致队列刷新,比如:
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop, scrollLeft, scrollWidth, scrollHeight
- clientTop, clientLeft, clientWidth, clientHeight
- getComputedStyle() (currentStyle in IE)
将上面的代码稍加修改:
1 | var ele = document.getElementById('myDiv'); |
因为offsetHeight属性需要返回最新的布局信息,因此浏览器不得不执行渲染队列中的“待处理变化”并触发重排以返回正确的值(即使队列中改变的样式属性和想要获取的属性值并没有什么关系),所以上面的代码,前两次的操作会缓存在渲染队列中待处理,但是一旦offsetHeight属性被请求了,队列就会立即执行,所以总共有两次重排与重绘。所以 尽量不要在布局信息改变时做查询 。