htmlcssjavascript
Posted freeman_Tian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了htmlcssjavascript相关的知识,希望对你有一定的参考价值。
html css
css的盒模型:
CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:外边距(margin)、边框(border)、内边距(padding)、实际内容(content)四个属性。
CSS盒模型:标准模型 + IE模型
标准盒模型 :width/height 只是内容高度,不包含 padding 和 border 值。
IE盒子模型(怪异盒模型) :width/height 包含了 padding 和 border 值 。
css
box-sizing: content-box; ( 浏览器默认设置 )
box-sizing: border-box;
JS如何获取盒模型对应的宽和高
(1)dom.style.width/height 只能取到行内样式的宽和高,style 标签中和 link 外链的样式取不到。
(2)dom.currentStyle.width/height (只有IE兼容)取到的是最终渲染后的宽和高
(3)window.getComputedStyle(dom).width/height 同(2)但是多浏览器支持,IE9 以上支持。
(4)dom.getBoundingClientRect().width/height 也是得到渲染后的宽和高,大多浏览器支持。IE9 以上支持,除此外还可以取到相对于视窗的上下左右的距离。
(6)dom.offsetWidth/offsetHeight 包括高度(宽度)、内边距和边框,不包括外边距。最常用,兼容性最好。
BFC(边距重叠解决方案)
BFC: 块级格式化上下文
BFC基本概念:BFC 是 CSS 布局的一个概念,是一块独立的渲染区域,是一个环境,里面的元素不会影响到外部的元素 。父子元素和兄弟元素边距重叠,重叠原则取最大值。空元素的边距重叠是取 margin 与 padding 的最大值。
BFC原理(渲染规则|布局规则):
(1)内部的 Box 会在垂直方向,从顶部开始一个接着一个地放置;
(2)Box 垂直方向的距离由 margin (外边距)决定,属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠;
(3)每个元素的 margin Box 的左边, 与包含块 border Box 的左边相接触,(对于从左到右的格式化,否则相反)。即使存在浮动也是如此;
(4)BFC 在页面上是一个隔离的独立容器,外面的元素不会影响里面的元素,反之亦然。文字环绕效果,设置 float;
(5)BFC 的区域不会与 float Box 重叠(清浮动);
(6)计算 BFC 的高度时,浮动元素也参与计算。
CSS在什么情况下会创建出BFC(即脱离文档流)
0、根元素,即 HTML 元素(最大的一个 BFC)
1、浮动( float 的值不为 none )
2、绝对定位元素( position 的值为 absolute 或 fixed )
3、行内块( display 为 inline-block )
4、表格单元( display 为 table、table-cell、table-caption、inline-block 等 HTML 表格相关的属性 )
5、弹性盒( display 为 flex 或 inline-flex )
6、默认值。内容不会被修剪,会呈现在元素框之外(overflow 不为 visible)
BFC作用(使用场景)
1、自适应两(三)栏布局(避免多列布局由于宽度计算四舍五入而自动换行)
2、避免元素被浮动元素覆盖3、可以让父元素的高度包含子浮动元素,清除内部浮动(原理:触发父 div 的 BFC 属性,使下面的子 div 都处在父 div的同一个 BFC 区域之内)
4、去除边距重叠现象,分属于不同的 BFC 时,可以阻止 margin 重叠
IFC基本概念IFC:
行内格式化上下文IFC
IFC原理(渲染规则|布局规则):
(1)内部的 Box 会在水平方向,从含块的顶部开始一个接着一个地放置;
(2)这些 Box 之间的水平方向的 margin,border 和padding 都有效;
(3)Box 垂直对齐方式:以它们的底部、顶部对齐,或以它们里面的文本的基线(baseline)对齐(默认,文本与图片对其),例:line-heigth 与 vertical-align。
标签语义化理解,和h5新特性,storage/cookie
标签语义化
- 搜索引擎友好。
- 更容易让屏幕阅读器读出网页内容。
- 去掉或样式丢失的时候能让页面呈现清晰的结构。
- 便于团队开发和维护。
h5新特性
css边框 border-radious,border-image text-shadow box-shadowcss
背景 background-clip,background-origin,background-sizecss
蒙版 -webkit-mask:url("04.png") 40px 55px no-repeat;
css transform属性
transform: translate,
transform: rotate,transform: scale,
transform: skewcss
过渡 transition: all 0.5s ease-in 0.1s ;
css 动画 -webkit-animation: changeText 0.3s ease-out;
css flex布局
storage/cookie
cookie:只能存储4KB每次操作会随着HTTP请求发送给服务器 操作数据很繁琐,没有方便的API 有可能被用户禁用
Flash: 需要安装Flash插件
移动端无法普及HTML5 本地存储的优点: 最小5MB,可以申请更大的空间 不会随HTTP请求发送给服务器 有方便的API操作 移动端普及高
有localStorage与sessionStorage两种
localStorage为永久性保存数据,不会随着浏览器的关闭而消失,可以在同域名跨页访问,无法跨域。按域名进行存储,不会和其他域名冲突 键值对存储:key/value .添加键值对:window.localStorage.setItem(key , value)获取键值:window.localStorage.getItem(key);删除键值对: window.localStorage.removeItem(key);清除键值对: window.localStorage.clear();属性 length
sessionStoragesessionStorage为临时性保存数据,当页面关闭就会消失。
其他设置基本与localStorage一样 sessionStorage不能跨页面访问,也不会触发跨标签页的storage事件。它只局限在当前的标签页,如果希望存储在本地,可以直接调用 JSON.stringify() 将json对象转为json字符串 ,读取出来后调用 JSON.parse() 将json字符串转为json对象格式 。
离线存储离线浏览 - 用户可在应用离线时使用它们 速度 - 已缓存资源加载得更快 减少服务器压力 - 浏览器只从服务器下载更改的资源支持度:IE不支持 使用方法页面头部像下面一样加入一个manifest的属性就可以了。
多线程单线程
JS运行在浏览器中,是单线程的,每个window一个JS线程,浏览器是事件驱动的,浏览器中很多行为是异步的,例如:鼠标点击、进入、移出事件、定时器触发事件、ajax请求完成回调等。当一个异步事件发生的时候,它就进入事件队列。
浏览器有一个内部大消息循环,Event Loop(事件循环),会轮询大的事件队列并处理事件,当线程中没有执行任何同步代码的前提下才会执行异步代码。
通过使用Web Worker, 我们可以在浏览器后台运行javascript, 而不占用浏览器自身线程。Web Worker可以提高应用的总体性能,并且提升用户体验 创建后台进程,这些进程不会卡死用户界面,更适合用来进行纯数据、与UI无关、较耗费CPU的计算。 支持性检测 if(typeof(Worker)!=="undefined"){ alert(\'支持多线程\'); }else{ alert(\'不支持多线程\'); }
DOM和css如何解析,如何渲染出元素?
DOM和CSSOM的渲染过程是并行的。
通过DOM树和CSS规则树,浏览器就可以通过它两构建渲染树了。
浏览器会先从DOM树的根节点开始遍历每个可见节点,然后对每个可见节点找到适配的CSS样式规则并应用。渲染树生成后,还是没有办法渲染到屏幕上,渲染到屏幕需要得到各个节点的位置信息,这就需要布局的处理了。
布局阶段会从渲染树的根节点开始遍历,由于渲染树的每个节点都是一个Render Object对象,包含宽高,位置,背景色等样式信息。所以浏览器就可以通过这些样式信息来确定每个节点对象在页面上的确切大小和位置,布局阶段的输出就是我们常说的盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。
当浏览器通过网络或者本地文件系统加载一个 HTML 文件,并对它进行解析完毕后,内核就会生成它最重要的数据结构 - DOM 树。
DOM 树上每一个节点都对应着网页里面的每一个元素,并且网页也可以通过 JavaScript 操作这棵 DOM 树,动态改变它的结构。但是 DOM 树本身并不能直接用于排版和渲染,内核还会生成另外一棵树 - Render 树,Render 树上的每一个节点 - RenderObject,跟 DOM 树上的节点几乎是一一对应的,当一个可见的 DOM 节点被添加到 DOM 树上时,内核就会为它生成对应的 RenderOject 添加到 Render 树上。
回流和重排怎么优化?
reflow(回流)
当浏览器发现布局发生了变化,这个时候就需要倒回去重新渲染,这个回退的过程叫reflow。reflow会从html这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置,以确认是渲染树的一部分发生变化还是整个渲染树。reflow几乎是无法避免的,因为只要用户进行交互操作,就势必会发生页面的一部分的重新渲染,且通常我们也无法预估浏览器到底会reflow哪一部分的代码,因为他们会相互影响。
repaint(重绘)
repaint则是当我们改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸和位置没有发生改变。
需要注意的是,display:none会触发reflow,而visibility: hidden属性则并不算是不可见属性,它的语义是隐藏元素,但元素仍然占据着布局空间,它会被渲染成一个空框。所以visibility:hidden只会触发repaint,因为没有发生位置变化。
另外有些情况下,比如修改了元素的样式,浏览器并不会立刻reflow或repaint一次,而是会把这样的操作积攒一批,然后做一次reflow,这又叫异步reflow或增量异步reflow。但是在有些情况下,比如resize窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行reflow。
优化:
用transform做形变和位移可以减少reflow
避免逐个修改节点样式,尽量一次性修改
使用DocumentFragment将需要多次修改的DOM元素缓存,最后一次性append到真实DOM中渲染
可以将需要多次修改的DOM元素设置display:none,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘)
避免多次读取某些属性
通过绝对位移将复杂的节点元素脱离文档流,形成新的Render Layer,降低回流成本
js为什么需要放在body(更好的回答其实是浏览器的渲染引擎和js解析引擎的冲突,当然回答js是单线程执行也没问题,如何优化)?
浏览器解析网页时会同时进行dom tree和style tree的解析工作,只有dom tree和style tree解析完成时,才会构建render tree,网页才会被painting。而js在没有在defer或者sync属性时浏览器会阻塞当前dom构建等待js加载和执行完毕之后才继续。但浏览器的painting不是只有一次的,当style tree解析完成时,如果遇到阻塞(js加载或者执行)则浏览器会painting已构建完的dom tree。所以当js放在头部时js的加载和执行会阻塞js脚本加载位置之后的dom的painting,而放body最后时即使加载很慢,浏览器也会渲染body的内容。所以放head和放body的区别是放body可以更快的渲染出脚本加载位置之前的dom tree。
操作DOM为什么是昂贵的?
reflow(回流)
重排属于一项用户阻塞操作,它意味着如果在执行重排时有太多工作执行,那么你的UI可能会降低帧速率、出现冻结,最差的情况甚至是crash
js如何执行(even Loop/宏任务、微任务,事件队列,promise,async/await)?
JS 的主要用途是与用户互动,以及操作 DOM 。这决定了它只能是单线程,否则会带来很复杂的同步问题。
主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。这就有了之后的同步任务和异步任务于是,所有任务可以分成两种,一种是同步任务( synchronous ),另一种是异步任务( asynchronous )。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
单线程的出现,才引发了同步和异步的出现
同步任务就是按顺序执行,从上往下。那么,异步任务也是有它的执行顺序的,它也是从上往下,但是,异步任务里,对于异步类型还有进一步的划分,那就是接下来我们要讲的微任务和宏任务,切记微任务比宏任务先执行
微任务(micro-task) process.nextTick、Promise、MutationObserver等
宏任务(macro-task) setTimeout、setInterval、 setImmediate、script(整体代码)、I/O 操作等
Promise 是有一点特殊性的,因为Promise构造函数中函数体的代码都是立即执行的 , 而 Promise.then() 和 Promise.catch() 属于微任务,也就是 resolve() 和 reject()
new Promise(function (resolve) {
console.log(1)
})
上面这段实例代码的 1 ,是直接输出的,属于同步任务,虽然它确实在 Promise 中
调用栈这是最后要介绍的一个角色,也就是真正执行代码,执行任务的地方
Event Loop
初始状态下,调用栈空。微任务队列空,宏任务队列里有且只有一个 script 脚本(整体代码)。这时首先执行并出队的就是 整体代码 整体代码作为宏任务进入调用栈,进行同步任务和异步任务的区分 同步任务直接执行并且在执行完之后出栈,异步任务进行微任务与宏任务的划分,分别被推入进入微任务队列和宏任务队列 等同步任务执行完了(调用栈为空)以后,再处理微任务队列,将微任务队列压入调用栈 当调用栈中的微任务队列被处理完了(调用栈为空)之后,再将宏任务队列压入调用栈,直至调用栈再一次为空,一次轮回结束 整体的运行流程可以查看下图,红色箭头为主要的执行流程,整体代码(宏任务) => 同步任务 => 微任务队列 => 宏任务队列虽然整体代码确实是一开始作为宏任务执行的,但是,希望大家还是要切记,微任务队列比宏任务队列先执行(方便记忆)
macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver
执行顺序:函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列,执行完之后再执行所有的micro-task,就这样一直循环。
浏览器缓存也就是HTTP缓存机制
浏览器缓存也就是HTTP缓存机制,其机制是根据HTTP报文的缓存标识进行的,缓存分为两种:强制缓存协商缓存「强制缓存」当浏览器向服务器发送请求的时候,服务器会将缓存规则放入HTTP响应的报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Conctrol的优先级比Expires高。「协商缓存」协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程强制缓存优先于协商缓存进行,若强制缓存生效则直接使用缓存,若不生效则进行协商缓存,协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存.
js的作用域?
1.全局作用域
(1) 全局作用域在页面打开时被创建,页面关闭时被销毁
(2) 编写在script标签中的变量和函数,作用域为全局,在页面的任意位置都可以访问到
(3) 在全局作用域中有全局对象window,代表一个浏览器窗口,由浏览器创建,可以直接调用
(4) 全局作用域中声明的变量和函数会作为window对象的属性和方法保存
(1) 调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁
(1) 调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁
(2) 每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的
2.函数作用域:
(3) 在函数作用域中可以访问到全局作用域的变量,在函数外无法访问到函数作用域内的变量
(4) 在函数作用域中访问变量、函数时,会先在自身作用域中寻找,若没有找到,则会到函数的上一级作用域中寻找,一直到全局作用域
(5) 在函数作用域中也有声明提前的特性,对于变量和函数都起作用,此时函数作用域相当于一个小的全局作用域,详细声明提前请看声明提前部分
(6) 在函数作用域中,不使用变量关键字声明的变量,在赋值时会往上一级作用域寻找已经声明的同名变量,直到全局作用域时还没找到,则会成为window的属性
闭包的理解(防抖和节流)?
指的是一个函数,一个什么样的函数呢?有权访问另一个函数作用域中的变量的函数
JavaScript的闭包就是函数中嵌套函数
闭包的优缺点如下:
优点:1、保护函数内部的变量安全,实现封装
2、可以把这个变量当作缓存来使用
弊端:无法销毁变量,使用不当,容易造成内存泄漏
防抖,从字面上来理解,便是防止抖动。输入完的时候,肯定会停顿一下,而这时候再去触发一次输入事件
function debounce(fn,wait) {
var timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout); //清除定时器
//创建新的 setTimeout
timeout = setTimeout(function(){
fn();
}, wait);
};
}
打开一个网页,往下滚动的时候,会出现滚动条,当滚动到一定的程度时,会出现一个返回顶部的按钮,点击一下,便会返回到顶部。在这里,便会用到节流。
所谓的节流呢,其思想指的就是某些代码不可以在没有间断的情况下连续重复执行。类似的还有onresize等事件。
function throttle(fn,delay){
var canRun=true;//通过闭包保存该变量
return function(){
if(!canRun) return;//立刻返回
canRun=false;
setTimeout(function(){
fn();
canRun=true;
},delay);
};
}
function handle(){
console.log(123);
}
window.addEventListener("scroll",throttle(handle,2000));
防抖跟节流都用到了闭包,
使用的都是计时器setTimeout,
防抖是某个事件触发后几秒后执行相应的方法,
而节流是某个事件触发后周期性执行相应的方法。
(通过一些题进行考察),基础类型以及如何判断类型?
js数据类型:Undefined,Null,Boolean,Number,String(5种基本数据类型),Object(引用类型:Date,Fuction,Array)
es6新增数据类型:Symbol Symbol意思是符号,有一个特性—每次创建一个Symbol值都是不一样的
比较少见且易忽略的类型:BigInt
typeof instance === "bigint"
Object.prototype.toString.call(undefined)
事件机制以及如何实现一个事件队列?
oop编程和原型链?
万物皆对象(js作为一个弱类型的脚本语言,在语言设计之处就定下万物皆对象来支撑js的一系列特性,也方便了低级语言来解释运行js(null除外)。在js的世界里也不例外,一切皆对象。面向对象的程序(OOP)的基本思想是:用虚拟对象去构建现实世界的模型,简化对象的概念,提供出对象的功能(api),以供人们去使用访问。
对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
在其他面向对象语言如java, 用class的概念去描述一个对象,但是在js中,class并不完全是一个对象,跟像是一个对象的模板。
当一个对象需要从class中创建出来时,class的构造函数就会运行创建这个实例,这种创建对象的过程就是实例化对象。
js常被描述成一种基于原型的语言,即每一个对象拥有一个原型方法。对象以其为原型为模板、从原型继承方法和属性。原型对象也可能有原型,并从中继承方法和属性,一层层以此类推。这种关系被称为原型链。
实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是自己本地的,另一种继承原型(prototype)的。所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样
原型的作用是共享数据节省空间,大多数情况下,proto可以理解为“构造器的原型”,即proto===constructor.prototype,但是通过 Object.create()创建的对象有可能不是.
原型对象/构造函数/实例
- 原型对象:构造函数的prototype属性指向的对象
- 构造函数: 创建对象的一种方式(函数对象)
- 实例:构造函数创建出来的一个对象
- constructor: 一个属性,仅对象独有,指向构造函数
- _ proto_: 一个隐式属性,函数和对象都有,指向该函数/对象的原型对象
原型链
属性查找:从实例本身一层层向上查找,直到访问到对象的原型。
属性修改:只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改该原型的属性时,则可以用例如 Vue.prototype.xxx = xxx; 但是这样会造成所有继承Vue的实例属性发生改变。
JavaScript的原型继承的本质:将构造函数的原型对象指向由另外一个构造函数创建的实例
mployee.prototype = new Person()
每个对象都有constructor属性,constructor属性应该指向对象的构造函数。
,constructor是Person.prototype的自有属性。
当对象被创建时,对象本身没有constructor属性,而是来源于创建对象的构造函数的原型对象
构造函数是妈,原型对象是爸,实例对象是孩子。妈让每个孩子拥有私有能力,爸让它们拥有共有能力(这个共有能力其实都是爸代劳的/(ㄒoㄒ)/~~);没有构造函数的情况下,可以直接理解为克隆哦~怎么样,这样应该能理解三者之间的关系了吧。
原型链
原型链是JavaScript中非常重要的概念,理解它有助于理解JavaScript面向对象编程的本质。
属性查找:从实例本身一层层向上查找,直到访问到对象的原型。
属性修改:只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改该原型的属性时,则可以用例如 Vue.prototype.xxx = xxx; 但是这样会造成所有继承Vue的实例属性发生改变。
__proto__属性
定义函数时,函数就有了prototype属性,该属性指向一个对象。
js继承
构造函数继承
这一种方法最为简单,直接利用call或者apply方法将父类构造函数的this绑定为子类构造函数的this就可以
原型实例继承这是比较常用的一种实现继承的方式。
student.prototype=new person();
student.prototype.construct=student;
var martin=new student("martin");
martin.eat("apple"); //martin is eating apple
console.log(martin.kind);//person
student.prototype=new person();
原型直接继承
这一种方法是通过直接将子类构造函数的原型对象直接赋值为父类构造函数的原型对象,从而达到继承的目的。
ES6中Class继承
class继承是ES6中新出的语法糖,通过class我们可以很简洁的实现继承,实现代码如下:
class person {
constructor(){
this.kind="person"
}
eat(food){
console.log(this.name+" "+food);
}
}
class student extends person{
constructor(name){
super();
this.name=name;
}
}
var martin=new student("martin");
console.log(martin.kind); //person
martin.eat("apple"); //martin apple
深拷贝继承
function deepCopy(parent,child) {
var child=child||{};
for(var i in parent){
if(typeof parent[i]==="object"){
child[i]=parent[i].constructor==="Array"?[]:{};
deepCopy(parent[i],child[i]); //递归
}else{
child[i]=parent[i];
}
}
return child
}
var parent={
name:"martin",
say(){
console.log("say"+this.name);
}
};
var child={
name:"lucy",
kind:"person",
eat(){
console.log("eating"+this.name);
}
};
deepCopy(parent,child);
console.log(child);
最优的继承方式,es6 super的作用(进阶),this指向问题和new的过程(bind函数&&new函数手写)?
js深拷贝?(JSON方法实现拷贝有什么问题?)
拷贝对象包含正则表达式,函数,或者undefined等值,JSON方法实现拷贝就会出现问题
RegExp、Error对象,则序列化的结果将只得到空对象
obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
如果对象中存在循环引用的情况也无法正确实现深拷贝
掌握如上基本可以横行了,如何霸道呢,那就是框架和打包工具的使用和原理知识了~~~后续详解
以上是关于htmlcssjavascript的主要内容,如果未能解决你的问题,请参考以下文章