1,将HTML解析成DOM树
2,将CSS解析成CSSOM树
3,将DOM和CSSOM树合并后生产Render树(渲染树);
4,Layout(布局),计算节点的位置;
5,Paint(绘制),将布局绘制在屏幕上;
注意:
重排即回流(reflow)和重绘(repaint)是不同的,只要改变元素的位置的操作就会触发重排(例如:元素尺寸改变——边距、填充、边框、宽度和高度),位置不变只是样式改变则只是触发重绘(例如:改变元素的color、background、box-shadow等属性)
特别地:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。
JavaScript 的加载、解析与执行会阻塞文档的解析, 等 JavaScript 引擎运行完毕,浏览器再从中断的地方恢复继续解析文档。
如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这就是建议将 script 标签放在 body 标签底部的原因。当然并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer 或者 async 属性。
比如:article,footer,header,nav,section
1,提高了代码的可读性,便于维护和开发
2,更便于搜索引擎优化(SEO)
音频
<audio controls="controls">
<source src="demo.mp3" type="audio/mp3">
audio>
视频
<video width="320" height="240" controls="controls">
<source src="demo.mp4" type="video/mp4">
video>
<label>日期label><input type="date"><br>
<label>时间label><input type="time"><br>
<label>邮箱label><input type="email"><br>
<label>搜索label><input type="search"><br>
<label>网址urllabel><input type="url"><br>
<label>颜色label><input type="color"><br>
<label>范围label><input type="range">
铺垫:
(1)对于Chrome浏览器内部至少有6个线程负责向服务器发起请求获取资源,此处称之为:请求线程
;另外还有一个线程负责绘制
所有资源并且执行js程序,此处称之为:UI主线程
;问题就在于这个UI主线程既要绘制又要执行JS程序,因此当执行JS代码的过程中会阻塞UI的绘制;
代码示例:
正常运行UI主线程
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<button>按钮1button>
<script src="js/demo.js">script>
<button>按钮2button>
body>
html>
效果是:先出现【按钮1】五秒后出现【按钮2】并且输出console.log()打印语句
通过Webworker创建一个线程帮助UI主线程执行JS代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<button>按钮1button>
<script>
let worker = new Worker("js/demo.js")
script>
<button>按钮2button>
body>
html>
效果是:同时出现【按钮1】【按钮2】然后输出console.log()打印语句
js/demo.js
let startTime = new Date().getTime()
let endTime = null;
do {
endTime = new Date().getTime()
}while (endTime - startTime < 5000)
console.log("执行demo.js的5秒后")
注意:不同浏览器的渲染机制会有所不同,此处实验使用的是chrome浏览器
(1)Websoket传输数据的方式是全双工的。通讯拥有更强的实时性
(2)由于低延迟,高及时的特性,多应用于多人协同的场景。
本地离线存储,localStorage长期存储数据,浏览器关闭后数据不会丢失;与sessionStorage相比,sessionStorage的数据在浏览器关闭后会自动删除。
(1)标准盒模型:(box-sizing:content-box) width,height只包含content内容,因此padding进而boder不受height和width控制,所以当padding值>0时候会增大盒子大小。
(2)怪异盒模型:(box-sizing:border-box) width,height包含了content,padding,border,因此padding和border纳入height,width控制的。
(1)从属关系的区别: @import是CSS提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,它不仅可以加载CSS文件还可以定义RSS、rel连接属性,引入网站图标等。
(2)加载机制的区别:加载页面时候,link标签引入的CSS被同时加载;@import 引入的CSS需要在页面加载完毕后再被加载。
(3)兼容性的区别,link标签没有兼容性问题,@import是CSS2.1才支持的语法,因此需要IE5+才能够支持;
(4)DOM可控性区别可以通过JS操作DOM插入link标签进而改变样式;而@import导入CSS样式的方式无法通过DOM进行操作。
ID 选择器:如 #id{}
类选择器:如 .class{}
属性选择器: 如 a[href="segmentfault.com"]{}
伪类选择器: 如 :hover{}
伪元素选择器: 如 ::before{}
标签选择器: 如 span{}
通配选择器:如 *{}
!important (权重最高)>内联样式 (权重为:1000)> ID 选择器(权重为:100)> 类选择器= 属性选择器= 伪类选择器(权重为:10)> 标签选择器 = 伪元素选择器(权重为1)
(1)伪元素用来创建一些不在文档树中的元素,并为七天假对应的样式。使用::进行表示,但是由于在旧版的W3C标准规范并为对其进行特别区分,因此目前大多数浏览器都支持这儿两种方式(:: 或者:)表示伪元素。常见::before、::after
(2)伪类用于为元素处于某种状态下,对其添加对应样式。常见 :hover、:focus
box-shadow: offset-x offset-y [blur [spread]] [color] [inset]
(1)elem:nth-child(n)选择父元素下n个子元素,并且这个元素的标签名称为elem,n可以接受具体的数字、值(odd和even)、公式(作为公司的时候n是从0开始的)。
(2)elem:nth-last-child(n)作用同上,区别在于该伪类从后开始查找
(3)elem:last-child选父元素中饭中最后一个子元素
(4)elem:first-child选中父元素中第一个子元素
(5)elem:only-child如果elem是父元素下唯一的子元素,则选中之
(7)elem:nth-of-type(n)选择父元素下第n个elem
类型元素,n可以接受具体的数值,也可以接受函数
(8)elem:first-of-type选择父元素下第一个elem
类型元素
(9)elem:last-of-type择父元素下最后一个elem
类型元素
(10)elem:only-of-type选择父元素下只有一个elem
类型元素
(11)elem:empty选中不包含子元素和内容的elem
类型元素
(12)not(elem)选择非 elem 元素的每个元素
(13)checked 单选框或复选框被选中
(1)::before 在元素内部前面插入内容
(2)::after 在元素内部后面插入内容
注意
border-radius:8px
(1) 2D 移动: transform: translate(x,y); 单位px
(2)2D 旋转: transform:rotate(0deg)l
(3)转换中心点(缩放与旋转都有影响):transform-origin: x y;
重点:
(1)动画基本使用步骤:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div class="animation-box">div>
body>
<style>
/*定义动画*/
@keyframes move {
0%{
transform: translate(0px,0px);
}
100%{
transform: translate(1000px,0px);
}
}
.animation-box{
height: 100px;
width: 100px;
background-color: pink;
/*使用动画*/
animation-name: move;
animation-duration: 2s;
animation-direction: alternate;
animation-iteration-count: infinite;
}
style>
html>
(2)动画常用属性:
(3)暂停动画:animation-paly-state:paused
(4)动画简写属性:
animation:动画名称 持续事件 运动曲线 何时开始 播放次数 是否反方向 动画起始或者结束的状态;
animation:name 5s linear 2s infinite alternate;
(1)转换
(2)透视:perspective: 100px;
注意:
(3)3d旋转
左手螺旋法则,拇指指向旋转轴的正方向,手指方向为旋转方向。
x轴正方向:→
y轴正方向:↓
z轴正方向:垂直屏幕向外
三角形的原理:
相邻边框连接处是均分的。将其他边颜色值设置为transparent透明即可实现三角形的效果;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
以下的实现方式不是最优的,但是这里通过CSS最大限度的对其进行实现,剩余的自动播放与交互还是用回了JS,因此做复杂了。建议主要使用JS进行实现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="swiper">
<ul class="sliders" onmouseover="handleMouseover()" onmouseout="handleMouseout()">
<input type="radio" id="control-1" name="slider-radio" checked>
<input type="radio" id="control-2" name="slider-radio">
<input type="radio" id="control-3" name="slider-radio">
<div class="label-box">
<label for="control-1" index="1"></label>
<label for="control-2" index="2"></label>
<label for="control-3" index="3"></label>
</div>
<li class="slider">1</li>
<li class="slider">2</li>
<li class="slider">3</li>
</ul>
</div>
<style>
input[type="radio"]{
position: relative;
z-index: 100;
display: none;
}
.swiper{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.sliders{
position: relative;
height: 300px;
width: 400px;
background-color: gray;
padding: 0;
margin: 0;
overflow: hidden;
}
.slider{
position: absolute;
list-style: none;
padding:0;
margin: 0;
height: inherit;
width: inherit;
display: flex;
justify-content: center;
align-items: center;
color: aliceblue;
font-size: 100px;
transition: all 0.5s;
}
.slider:nth-of-type(1){
background-color: #ffb700;
}
.slider:nth-of-type(2){
left:100%;
background-color: #ff0073;
}
.slider:nth-of-type(3){
left: 200%;
background-color: #0066ff;
}
.label-box{
position: absolute;
bottom: 10px;
width: 100%;
text-align: center;
z-index: 100;
}
.label-box>label{
display: inline-block;
height: 10px;
width: 10px;
border:2px solid #ffffff;
border-radius: 50%;
background-color: aliceblue;
cursor: pointer;
}
input[type="radio"]:nth-child(1):checked ~ .label-box label:nth-child(1){
background-color: #232323;
}
input[type="radio"]:nth-child(2):checked ~ .label-box label:nth-child(2){
background-color: #232323;
}
input[type="radio"]:nth-child(3):checked ~ .label-box label:nth-child(3){
background-color: #232323;
}
input[type="radio"]:nth-child(1):checked ~ .slider{
transform: translateX(0)
}
input[type="radio"]:nth-child(2):checked ~ .slider {
transform: translateX(-100%)
}
input[type="radio"]:nth-child(3):checked ~ .slider {
transform: translateX(-200%)
}
</style>
<script>
let slides = document.getElementsByTagName("input")
let i = 1
let timer
function startTimeout(){
timer = setInterval(function () {
if (i>=slides.length){
i = 0
}
slides[i].checked = true
i++
},2000)
}
startTimeout()
function handleMouseover(){
clearTimeout(timer)
}
function handleMouseout (){
startTimeout()
}
//这里是为了使得点击按钮后,使得i的值与轮播图此时轮播到第几张进行对应。
function setCurrentIndex(e){
i = parseInt(e.target.getAttribute("index"))
}
let labels = document.getElementsByTagName("label")
for (let k = 0 ;k<labels.length;k++){
labels[k].addEventListener("click",setCurrentIndex)
}
</script>
</body>
</html>
Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。
JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。
JS通过事件循环机制已达到非阻塞的效果,当遇到异步任务我们现将其挂起,直到同步代码执行完毕后,再去任务队列中去执行异步任务(先执行微任务,后指向宏任务)
微任务:promise …
宏任务:setTimeout、setInterval …
this的指向是动态进行绑定的。不受作用域的限制。
方法中的this指向问题可以通过call,apply,bind指向。call和apply的区别在于传参的形式不同。bind则是绑定了不执行罢了。
凡是通过 obj.func()进行调用的,func中的this指向的就是调用者obj如果被调用的函数为箭头函数则另当别论,箭头函数没有this,因此箭头函数中的this静态的,它指向它的词法作用域中的this
嵌套函数和普通函数,仅仅作为函数进行调用,而非通过对象进行调用时候,通常指向的是全局对象,严格模式下为undefined
词法作用域指的是声明时所在作用域,而非运行时。
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。
闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。
在循环中创建闭包是常见第一种错误使用方式,解决这个问题可以通过使用更多的闭包或者使用let进行声明循环变量。
new 关键字做了什么动作
let obj
obj.__proto__ = constructor.prototype
constructor.apply(obj,arg)
function myNew (constructor,...arg){
let obj = {
}//创建一个对象
obj.__proto__ = constructor.prototype //将新创建的对象的原型指向构造函数的原型
constructor.apply(obj,arg)//调用构造函数初始化对象
return obj//将对象返回
}
每个对象都有一个私有属性(proto)指向它的构造函数的原型对象(prototype)该(prototype)原型对象也有自己私有属性(proto)指向它的构造函数的原型对象(prototype),层层向上知道一个对象的原型对象为null。根据定义null没有原型。
基于原型链的继承,对象可以访问到原型链上的方法和属性。
Function.prototype.myCall = function(){
let caller = this//这里相当于fun.call(obj,...arg)中fun
let targetObj = arguments[0]//这里相当于fun.call(obj,...arg)中的第一个参数obj
let otherArgs = []//这里相当于fun.call(obj,...arg)中的除了第一个参数的所有参数的集合...arg
for (let i = 1 ;i<arguments.length;i++){
otherArgs.push(arguments[i])
}
targetObj.caller = caller
let res = targetObj.caller(...otherArgs)//这里完成了this的动态绑定
delete caller
return res
}
console.log([].filter.myCall([1,2,6,2,3,5],function (item){
return item >3
}))
/*防抖函数*/
//事件连续触发多次,只执行最后一次触发,并且停止触发事件后的timing秒才会执行
function debounce(fun,timing){
let timer//用于记录定时
return function (){
clearTimeout(timer)//清除定时
timer = setTimeout(function (){
fun()
},timing)
}
}
/*节流函数*/
//事件触发多次,只在一定时间内执行一次
function throttle(fn,timing){
let trigger//是否触发的判断值
return function (){
if (trigger) return //如果已经触发过了直接返回,不再往下执行
trigger = true //如果没有触发过,往下执行触发,并且把该状态改为触发
fn()
//并且通过定时器,设置timing秒后才将状态变为未触发,即timing秒后才可以再次触发
setTimeout(function (){
trigger = false
},timing)
}
}
let arr = [4,9,10,22,7,3,2]
//冒泡排序法
function bubbleSort(arr){
let temp
for (let i = 0;i<arr.length;i++){
for(let j=0;j<arr.length-1-i;j++){
if (arr[j+1]<arr[j]){
temp = arr[j+1]
arr[j+1] = arr[j]
arr[j] = temp
}
}
console.log(arr.join("-"))
}
return arr
}
bubbleSort(arr)
v-model其实是v-on和input事件监听的一个语法糖。
v-model原理:通过v-on实现了对数据对象data的监听,通过input事件监听,把输入框中的值更新到数据对象data,这样一来就实现了双向数据绑定。
通过Object.defineProperty来实现监听数据的改变和读取(属性中的getter和setter方法) 实现数据劫持。
//此处title为传递给子组件的值
....
<Demo v-bind:title="title" @myEvent="listenSun"></Demo>
....
....
//定义的是传递过来的数值类型
props:{
title: String
}
....
<template>
<div class="demo-layout">
<h1 v-on:click="handleClick">点击这里触发/h1>
</div>
</template>
....
methods:{
handleClick: function (){
this.$emit("myEvent","message")//这个message就是传递给父组件的值
}
}
....
<template
<div id="app">
<Demo v-bind:title="title" @myEvent="listenSun"></Demo>
</div>
</template>
....
methods: {
listenSun: function (message){
//这里的message就是子组件传递过来的值
....
}
}
}
....
npm install vuex --save
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
export default new Vuex.Store({
//用于存放全局的数据
state:{
num:0
},
//相当于组件中计算属性,省去在每个组件使用计算属性的操作。
getters:{
getNum(state){
return state.num
}
},
//vuex推荐改变sate中的数据在此处进行.触发需要使用$store.commit("mutationsName")
mutations:{
increaseNum(state){
state.num++
}
},
//相当于可以处理异步的mutation.触发需要使用$store.dispatch("mutationsName")
actions:{
asyncIncreaseNum(context){
setTimeout(()=>{
context.commit('increaseNum')
},1000)
}
},
modules:{
}
})
import Vue from 'vue'
import App from './App.vue'
import store from '@/store'
Vue.config.productionTip = false
Vue.prototype.bus = new Vue()
new Vue({
store,//全局注册
render: h => h(App),
}).$mount('#app')
<template>
<div class="count-layout">
<h1>{
{
this.$store.getters.getNum}}</h1>
<h1>{
{
this.$store.state.num}}</h1>
<input type="button" value="+1" @click="handleClickAdd">
<input type="button" value="async+1" @click="handleAsyncClickAdd">
</div>
</template>
<script>
export default {
name: "Count",
methods: {
handleClickAdd() {
this.$store.commit("increaseNum")
},
handleAsyncClickAdd(){
this.$store.dispatch("asyncIncreaseNum")
}
}
}
</script>
<style scoped>
</style>
文件:main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.prototype.bus = new Vue()
new Vue({
render: h => h(App),
}).$mount('#app')
<template>
<div class="demo-layout">
<h1 v-on:click="handleClickSendBus">点击此处触发</h1>
</div>
</template>
....
methods:{
handleClickSendBus: function (){
this.bus.$emit("busEvent","busMessage")
}
}
....
....
created() {
this.bus.$on("busEvent",message => {
//此处的message就是其他组件传递过来的值
....
})
}
....
beforeCreate:data和method还没有创建,在这个声明周期钩子函数上不能使用data;
created:可以访问里面的数据对象data和方法对象methods;
beforeMount:el实力和data都初始化了,但未挂载到DOM;
mounted:vue实例挂载到DOM了,此时可以对DOM进行操作;
beforeupdated:响应式数据更新时调用,此时并未完成DOM重新渲染;
updated:虚拟DOM重新渲染和打补丁之后调用,组成新的DOM已经更新,避免在这个钩子函数中操作数据,防止死循环;
beforeDestroy:实例销毁前调用,实例还可以用,this能获取到实例,常用于销毁定时器,解绑事件;
destroyed:实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁;
在Vue中数据发生改变,Dom不是立即更新的,为了准确的获取到最新的Dom我们可以使用$nextTick
(1)Cookie:客户端访问服务器,服务器为了识别用户创建Session,将SessionId保存到Cookie中发送给客户端,客户端将其存储在浏览器中,当再次访问服务器的时候会自动将Cookie加入到请求,随着请求一并传递到服务器端。
(2)Session是存储在服务器端的,服务器端通过解析Cookie获取到对应的SessionId来找到对应的Session,Session是依赖Cookie的
(3)Token由三部分组成:uid(用户唯一标识)、time(时间戳)、sign(签名),相当于一个令牌,用户信息存储到Token中,服务器接收到Token解密后才识别到用户信息,与Cookie不同的,发送需要开发者手动添加。
(1)IE浏览器内核:Trident内核俗称IE内核;
(2)Chrome浏览器内核:以前是Webkit内核现在是Blink内核。
(3)Safari浏览器内核:Webkit内核
(4)Firefox浏览器内核:Gecko内核,俗称Firefox内核
(5)Opera浏览器内核:起初是自己的Presto内核,后再加入了谷歌大军,从Webkit又到了Blink;
(6)360浏览器,猎豹浏览器内核:IE+Chrome双内核
(7)搜狗,遨游,QQ浏览器内核:Trident(兼容模式)+Webkit(高速模式)
(8)百度浏览器、世界之窗内核:IE内核
(9)2345浏览器内核:IE+Chrome双内核
(10)UC浏览器内核:众口不一,UC自称自己研发U3内核,但是还是基于Webkit和Trident,还有说是基于火狐内核的。
程序的概念:通俗的讲,程序是存储在磁盘中运行在cpu的代码,例如c:/demo.js
进程的概念:通俗的讲,将程序调入内存中并分配一定的空间,在内存中的程序为内存。
线程:通俗的讲,进程中包含多个线程。线程就好比如一个工厂中的其中一条流水线。
(1)单工通讯:收发端口固定,一个固定为发送端口,一个固定为接受端口。例如遥控器。
(2)半双工通讯:两端都具备发送器和接收器,但同一时刻只能发送或只能接收数据的传输方式。由于这种方式要频繁变换信道方向,故效率低,但可以节约传输线路。例如无线对讲机
(3)全双工通讯:发送数据的同时也能够接收数据,两者同步进行。例如:打电话,说话的同时依然能够听到对方的声音。