header :头部
nav:导航
article:内容
section:块级
aside:侧边栏
footer:尾部
好处:
1.去掉或者丢失样式的时候能够让页面呈现出清晰结构
2.有利于SEO
3.方便其他设备解析
伪元素和伪类的根据区别就是:前者是创建出了一个新元素,而后者是一个已存在但你不能直接看到的元素。
::before ::after
伪类用于定义元素的特殊状态
例如。它可以有以下作用
那些方式可以脱离文档流
animation 的子属性有:
复杂数据类型(Object、[数组、对象])创建的时候 开辟的 堆内存
基本数据类型(number、string等6种)创建的时候 开辟的 栈内容
虚拟DOM其实就是用一个原生的JS对象去描述一个DOM节点,实际上它只是对真实 DOM 的一层抽象。最终可以通过一系列操作使这棵树映射到真实环境上。
相当于在js与DOM之间做了一个缓存,利用patch(diff算法)对比新旧虚拟DOM记录到一个对象中按需更新, 最后创建真实的DOM。
let声明的变量可以改变,值和类型都可以改变;而const声明的常量不可以改变
const保证的是内存地址不能被修改,所以能够修改对象
instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。
var声明一个变量时,该变量会被提升到作用域的顶端,但是赋值的部分并不会被提升。
原理:
JS引擎的工作方式是 :
1、先解析代码,获取所有被声明的变量;
2、然后在运行。也就是专业来说是分为预处理和执行两个阶段。
console.log(a); //undefined
var a = "9";
// 实际运行表示变量a已声明未赋值,在js引擎中的运行过程是:
var a;
console.log(a);
a = "9"
作用域分为全局作用域,局部作用域和块级作用域
在访问一个变量的时候,首先在当前作用域中寻找,如果找不到再从外层作用域寻找。这样一层一层查找,就形成了作用域链
闭包 函数和声明该函数的词法环境的组合(两个嵌套关系的函数,内部函数可以访问外部函数定义的变量)
闭包的优点:1、形成私有空间,避免全局变量的污染
2、持久化内存,保存数据
闭包的缺点:1、持久化内存,导致内存泄露
解决内存泄漏:在退出函数之前,将使变量赋值为null;
es6-es10新增常用方法
es6:
1、let、const
2、解构赋值 let { a, b } = { a: 1, b: 2 }
3、箭头函数 ()=>{}
4、字符串模板 ``
5、扩展运算符 ...arr
6、数组方法:map、filter、some等等
7、类:class关键字
8、promise 主要用于异步计算
9、函数参数默认值 fn(a = 1) {}
10、对象属性简写 let a = 1; let obj = {a}
11、模块化:import--引入、exprot default--导出
es7:
1、includes()方法,用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true,否则返回false。
es8:
1、async/await
es9:
1、Promise.finally() 允许你指定最终的逻辑
es10:
1、数组Array的flat()和flatmap()
flat:方法最基本的作用就是数组降维
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
flatmap:方法首先使用映射函数映射(遍历)每个元素,然后将结果压缩成一个新数组
***8、let、const和var的区别
1、var声明变量存在提升(提升当前作用域最顶端),let和const是不存在变量提升的情况
2、var没有块级作用,let和const存在块级作用域
3、var允许重复声明,let和const在同一作用域不允许重复声明
4、var和let声明变量可以修改,const是常量不能改变
防抖: 就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。商品搜索 延时器
节流: 就是指连续触发事件但是在设定的一段时间内中只执行一次函数。(登录按钮)
<body>
<input type="text" class="ipt" />
<script>
var timerId = null
document.querySelector('.ipt').onkeyup = function () {
// 防抖
if (timerId !== null) {
//延时器
clearTimeout(timerId)
}
timerId = setTimeout(() => {
console.log('我是防抖')
}, 1000)
}
document.querySelector('.ipt').onkeyup = function () {
// 节流
console.log(2)
if (timerId !== null) {
return
}
timerId = setTimeout(() => {
console.log('我是节流')
timerId = null
}, 1000)
}
</script>
</body>
js是单线程执行的,页面加载时,会自上而下执行主线程上的同步任务,当主线程代码执行完毕时,才开始执行在任务队列中的异步任务。具体如下 :
1.所有同步任务都在主线程上执行,形成一个执行栈。
2.主线程之外,还存在一个"任务队列(eventloop队列或者消息队列)“。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
3.一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列”,看看里面有哪些事件。哪些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
4.主线程不断重复上面的第三步。
1、外形不同:箭头函数使用箭头定义,普通函数中没有。
2、 箭头函数全都是匿名函数:普通函数可以有匿名函数,也可以有具名函数
3、箭头函数不能用于构造函数:普通函数可以用于构造函数,以此创建对象实例。
4、箭头函数中 this 的指向不同:在普通函数中,this 总是指向调用它的对象,如果用作构造函数,它指向创建的对象实例。
5、箭头函数不具有 arguments 对象:每一个普通函数调用后都具有一个arguments 对象,用来存储实际传递的参数。但是箭头函数并没有此对象。
6、其他区别:箭头函数不具有 prototype 原型对象。
浅拷贝: 拷贝对象的一层属性,如果对象里面还有对象,拷贝的是地址, 两者之间修改会有影响,适用于对象里面属性的值是简单数据类型的.
深拷贝: 拷贝对象的多层属性,如果对象里面还有对象,会继续拷贝,使用递归去实现.
Object.assign({}, obj)
展开运算符
const obj = {
name: 'Tricia',
age: 26,
love: {
friuts : 'apple',
meat: 'beef'
}
}
function getObj(obj) {
const newObj = {}
for (let k in obj) {
// 如果对象的属性还是对象,那么就递归调用这个函数,如果不是,就赋值
newObj[k] = typeof obj[k] === 'object' ? getObj(obj[k]) : obj[k]
}
return newObj
}
var obj2 = getObj(obj)
console.log(obj2)
JSON.parse JSON.stringfy
forEach map区别?
用forEach、map函数对引用类型的数组元素的属性值进行了修改,原数组也会跟着改变。
对操作数组进行深拷贝。用拷贝的对象调用数组处理方法,原数组就不会改变了
1、forEach:遍历开始以后无法停止,如果要遍历整个数组,那就使用这个方法;
2、map:根据当前数组映射出一个新的数组;
3、some:遍历整个数组,返回值true就停止循环(返回false继续循环)
返回值:如果数组中的有一项回调函数返回true,那么结果为true,否则为false;(或者这样理解:数组别遍历完,那么结果为false,否则为true)
4、every:与some相反,返回false就停止循环(返回true就继续循环)
5、filter:过滤数组,返回一个新的数组
6、reduce:实现数据的累加
scrollTop
判断图片滚动的距离, innerHeight
求当前视口高度,offsetTop
得到图片相对于父元素的位置,然后 scrollTop + clientH - elementTop - 图片自身的高度
得到元素当前的位置。
如果>=0
说明该元素在视口内,给元素的url赋值
let imgs = document.querySelectorAll('img')
console.log(imgs);
scrollFn()
// 监听滚动事件
window.onscroll = scrollFn
function scrollFn() {
let clientH = window.innerHeight // 可视区高度
let scrollTop = document.documentElement.scrollTop // 滚动的高度
console.log(clientH, scrollTop)
Array.from(imgs).forEach(item => {
let elementTop = item.offsetTop // 元素相对于父元素的位置
// console.log('eleTop', elementTop)
let count = scrollTop + clientH - elementTop - item.height // 元素的位置
console.log('count',count)
if(count >= 0) {
// 如果大于等于0,说明在可视区内,给图片赋值
item.setAttribute('src', item.getAttribute('data-url'))
}
})
}
js的内存分配和回收都是自动完成的,内存不使用时,会被垃圾及回收机制自动回收
性能: for > for-of > forEach > map > for-in
因为JS的数据都是保存在浏览器的堆栈内存⾥⾯的,当⻚⾯刷新时,⻚⾯会重新加载vue实例,vuex⾥⾯的数据就会被重新赋值。
解决:存入本地缓存
父组件通过属性的方式向子组件传值,子组件通过props来接受。
子组件接受的父组件的值分为引用数据类型和普通数据类型两种。
基于vue的单向数据流原则,组件之间的数据是单向流通的,子组件不允许直接对父组件的值进行修改,所以要避免直接修改父组件传过来的值得情况。
子组件绑定一事件,并通过$emit来触发这个事件
$store.state.模块名.属性名
直接模块名.属性名
provide/inject
简单来说就是在父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量,不管组件层级有多深,在父组件生效的生命周期内,这个变量就一直有效。
注意:
provide和inject的绑定不是响应式的
解决办法:
Vue.observable 优化响应式 provide
用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个comment目录,views目录中放页面级的组件,comment中放公共组件
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
我们一般用脚手架开发项目,每个 .vue
单文件就是一个组件。在另一组件import
导入,并在components
中注册(install
函数注册组件),子组件需要数据,在props
中接受。而子组件修改好数据后采用$emit
方法将数据传递给父组件。
什么是插槽
1.1 插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
1.2 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
插槽使用
2.1 默认插槽 在子组件中写入slot,slot所在的位置就是父组件要显示的内容
2.2 具名插槽 在子组件中定义了三个slot标签,其中有两个分别添加了name属性header和footer
在父组件中使用template并写入对应的slot名字来指定该内容在子组件中现实的位置
2.3 作用域插槽 在子组件的slot标签上绑定需要的值
在父组件上使用slot-scope=“user”来接收子组件传过来的值
keep-alive是vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM
keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
对应两个钩子函数 activated和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated
Vue 的响应式原理是核心是通过 ES5 的Object.defindeProperty 进行数据劫持,然后利用 get 和 set 方法进行获取和设置,data 中声明的属性都被添加到了get和set中,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发,重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。
通过Proxy(代理): 拦截对data任意属性的任意操作, 包括属性值的增删改查
通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
defineProperty:
setup() : 开始创建组件之前,在beforeCreate 和 created 之前执行,创建的是data 和 method
一方面model层通过defineProperty来劫持每个属性,一旦监听到变化通过相关的页面元素更新。
另一方面通过编译模板文件,为控件的v-model绑定input事件,从而页面输入能实时更新相关data属性值。
Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
1)加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
2)子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
3)父组件更新过程
父 beforeUpdate -> 父 updated
4)销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
computed:
watch:
params
和query
params刷新页面,路由信息丢失
配合localStorage sessionStorage实现刷新页面后数据不丢失.
作用:
1.key的作用主要是为了高效的更新虚拟DOM,提高渲染性能。
2.key属性可以避免数据混乱的情况出现。
原理:diff算法
1.vue实现了一套虚拟DOM,使我们可以不直接操作DOM元素只操作数据,就可以重新渲染页面,而隐藏在背后的原理是高效的Diff算法
2.当页面数据发生变化时,Diff算法只会比较同一层级的节点;
3.如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点后面的子节点;
如果节点类型相同,则会重新设置该节点属性,从而实现节点更新
4.使用key给每个节点做一个唯一标识,Diff算法就可以正确失败此节点,"就地更新"找到正确的位置插入新的节点。
key的作用主要是为了高效的更新虚拟DOM。
如果key绑定的是index的话,index是会变化的。当插入数组的时候,原来的下标是2,现在可能变成3了,就达不到一一对应的关系,就提高不了性能,所以key一定要绑定的是唯一性的。
promise对应的有一个.then方法,可以将内部成功或者失败的结果给传出来
function getdata() {
return new Promise((resove, reject) => {
setTimeout(() => {
resove("获取数据");
}, 2000);
});
}
function setdata() {
return new Promise((resove, reject) => {
setTimeout(() => {
resove("使用数据");
}, 1000);
});
}
getdata()
.then(function (value) {
console.log(value);
return setdata();
})
.then(function (value) {
console.log(value);
});
//promise对应的有一个then方法,可以将内部成功或者失败的结果给传出来
//1 在这里我们首先调用了getdata函数,因为getdata函数内部返回的是一个promise对象,那么就应该有.then方法,.then使用的话内部会有一个函数函数的形参就是上面promise返回的成功和失败的结果.
//在我们的.then方法里面我们又返回了使用数据的函数,因为使用数据函数内部封装的也是一个promise对象,所有也会对应有一个promise对应的方法,接着我们再用一个函数形参去接受返回的结果
//这样就解决了我们遇到的回调地狱问题,但是写多了,还是会发现一些问题.
第一种 catch 方法可以捕获到 catch 之前整条 promise 链路上所有抛出的异常。
第二种 then 方法的第二个参数捕获的异常依赖于上一个 Promise 对象的执行结果。
是通过promise实现对ajax技术的一种封装,
如何封装axios
if (process.env.NODE_ENV === 'development') {
axios.defaults.baseURL = 'http://dev.xxx.com'
} else if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = 'http://prod.xxx.com'
}
是什么?
ts是js的超集,支持ES6语法,支持面向对象的编程概念,如类,接口,继承,泛型等
它是一种静态类型的检查语言,提供了类型注解,在代码编译阶段就能检查出数据类型的错误
特性?
ts的主要特性:
ts常见复杂类型有object、数组、元组、枚举、普通对象
相同点:
都可以描述一个对象或者函数
不同点:
type 可以声明基本类型别名,联合类型,元组等类型
type 语句中还可以使用 typeof 获取实例的 类型进行赋值
interface 能够声明合并
泛型允许我们在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型 在typescript
中,定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性
history.pushState,可以添加浏览器的历史记录,你在进入页面的时候先pushState一个新页面(#hash),然后监听popstate事件。
页面修改了history,会触发popstate事件。触发时检测到url地址为刚进页面时的地址,就再pushState那个#hash。
浏览历史记录中会始终留下一个页面,后退按钮失效。
不同浏览器的默认样式不同,可以使用Normalize.css
解决。
Normalize.css
是一个可以定制的CSS文件,它让不同的浏览器在渲染网页元素的时候形式更统一。
Normalize.css
只是一个很小的css文件,但它在磨人的HTML元素样式上提供了跨浏览器的高度一致性。 相比于传统的CSS reset
,Normalize.css
是一种现代的、为HTML5准备的优质替代方案。总之,Normalize.css
是一种CSS reset
的替代方案。
不同浏览器的标签默认的margin
和padding
不同
*{margin:0;padding:0;}
解决。reset.css
样式重置css3新属性,加浏览器前缀
兼容早期浏览器
css hack
解决浏览器兼容性
background-color:yellow0; 0 是留给ie8的
+background-color:pink; + ie7定了;
_background-color:orange; _专门留给ie6;
先加载index.html,查询依赖的css文件、js文件,再加载js import的文件
由于瀑布流在下拉很久后会页面上的数据和dom越来越多,以至内存暴增、应用卡顿或闪退,所以需要对已经划过去的dom节点做释放,方法有两种:
将文件的静态资源移存到不同区域的CDN节点服务器上,当用户访问网络的时候,会去距离用户最近的CDN服务器上获取,避免网络拥塞,提高访问速度。
具体原理
1.用 户 输 入 要 访 问 的url
,浏 览 器 通 过 域名解析(本地DNS系统和CDN专用DNS服务器)得到CDN负载均衡设备的IP地址。
2.浏览器向CDN负载均衡发出访问,CDN负载均衡根据用户IP地址及URL,判断距离、有无内容、负载情况后返回用户所属区域的最佳cdn缓存服务器IP。
3.用户向cdn缓存服务器发起请求,服务器响应用户请求。
4.如果这台缓存服务器上没有用户想要的内容,再由缓存服务器向源服务器请求。
5.缓存服务器从源服务器得到内容后,一方面在本地进行缓存,另一方面将获取的数据返回给客户端
懒加载
css精灵图
base64
格式来节约请求canvas
来代替图片cookie
和域名CDN
service workers
进行资源的离线缓存,用户再次访问时,可以利用离线缓存迅速打开应用。link预加载标签
来实现预先加载H5元素
来创建语义化的结构postcss-pxtorem
用于将px单位转化为remamfe-flexible
用于设置 rem 基准值 根据设置屏幕的宽度去调整rem的值(html标签上font-size的大小)document.body.clientWidth
步骤:
postcss.config.js
配置 postcss
插件rem
是基于html
定义的字体大小而决定,而em
则根据使用它的元素的大小决定。
现有的em
后有rem
, 因为em
是相对于父级元素的,使用起来比较麻烦。
存储在indexDB
IndexedDB
就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB
允许储存大量数据,提供查找接口,还能建立索引。
步骤:
分页:
采用延迟加载的策略
出错、呆滞、损坏、假死、崩溃
try...catch...
: 只能捕获到同步运行时错误,对语法和异步错误却无能为力,捕获不到。 window.onerror
: 当 JS 运行时错误发生时,window
会触发一个 ErrorEvent
接口的 error
事件,并执行 window.onerror()
。
js
报错不能被 全局的window.onerror
监听到,我们需要给相关的 js 文件上加上 Access-Control-Allow-Origin:*
的 response header
,并且引用相关的js
文件时加上 crossorigin
属性window.addEventListener
: 资源加载失败,加载资源的元素会触发Event
接口中的error
事件,并执行该元素上的onerror()
处理函数。这些error
事件不会向上冒泡到window
,不过能被单一的window.addEventListener
捕获Promise
的catch
处理抛出的异常axios
中,错误请求放到请求拦截器中vue
中的 errorHandler
将图片转为base64存在localStorage中。
1、url可见性:
get,参数url可见;
post,url参数不可见
2、数据传输上:
get,通过拼接url进行传递参数;
post,通过请求体传输参数
3、缓存性:
get请求是可以缓存的
post请求不可以缓存
4、后退页面的反应
get请求页面后退时,不产生影响
post请求页面后退时,会重新提交请求
5、传输数据的大小
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。
6、安全性
原则上post肯定要比get安全,毕竟传输参数时url不可见
分为两种:强缓存和协商缓存
1、udp是无连接的,tcp是面向连接的;
2、udp是不可靠传输,tcp是可靠传输;
3、udp是面向报文传输,tcp是面向字节流传输
HTTP1.0:
HTTP1.1:
HTTP2.0:
方法一:flex布局,左侧flex-grow: 0, flex-shrink: 0,flex-basis: 固定宽度数值;右侧flex-grow: 1, flex-shrink: 1,flex-basis: 0px(或者不设置);
方法二:float+margin, 左侧元素float:left;给一个固定宽度,右侧元素margin-left: 左侧元素的宽度;
方法三:float+float,左侧元素float:left;给一个固定宽度,右侧元素float:right;宽度设为calc(100% - 左侧元素的宽度);
方法四:父级元素的display: table, 左侧元素display:table-cell且给一个固定宽度,右侧元素display: table-cell,不设置宽度即可;
方法五:absolute+margin, 左侧元素设置一个绝对定位定位在左侧且给一个固定宽度, 右侧元素,充满空间且给一个margin-left为左侧元素的宽度