一、盒模型
标准盒模型:box-sizing: content-box。
外边距+边框+内边距+内容区。
IE盒模型,怪异盒模型:box-sizing: border-box。
外边距+内容区(边框+内边距+内容区)。
二、CSS特性
继承性: 父元素的字体大小,字体颜色,行高,display:none...也会出现在子元素上。
优先级: 谁的权重高就显示谁的样式。
!important 内联 ID class 属性 伪类 元素 继承 通配 (vue中有深度选择器 deep)
层叠性: 多个CSS声明应用在同一个元素时,权重相加,决定最终样式
预处理器 sass less 预处理器 变量 函数 混入,全局颜色,css原子化
1、变量的声明
声明变量的时候,变量名前面要加两根连词线 --。使用变量用var()函数。<style>
body{--foo:red;
}p{color: var(foo);
}
</style>2、变量的继承
<style>
body{--foo: red;
}p{--foo: initial;
}
</style>3、js控制css变量
通过js的dom节点对象,可以获取和修改当前节点的css变量值。获取css变量:getPropertyValue('--name')
设置css变量:setProperty('--name', value)<div id="header">hello world</div><style>
#header {--bgColor: #ffffff;
}
</style><script>let dom = document.getElementById("header");// 获取css变量let color = dom.getPropertyValue("--bgColor").trim();// 设置css变量dom.setProperty("--bgColor", '#f34e25');
</script>
css函数1、var变量函数,作用:引用自定义的变量值。
第一个参数:引用的变量名称,第二个参数:回退值,表示如果第一个参数未定义,
使用回退值代替。body {// 定义变量bgColor--bgColor: #ffffff;// 背景色取变量--bgColor的值,如果未定义,则取redbackground-color: var(--bgColor, red);
}2、calc 主要通过简单的数学计算,进行一些单位的计算,表达式支持加、减、乘、除。3、min(val1... valN):接受任意数量的参数,每个参数也可以是表达式。取出参数中最小的值。
max(val1...valN):同上,取最大的值。4、:where伪类选择器函数
作用::where()函数实际是一个高级的伪类选择器,他的作用是将一系列的选择器列表,
都应用相同的样式,简化多个选择器样式编码的流程。
:where(class1,...classN) { css样式 }- 接受n个参数,参数值为选择器(任意的css选择器)// 传统方式
.main span {font-size: 12px;
}
.line span {font-size: 12px;
}// 如果有大量样式相同,选择:where函数选择器(终极版)
:where(.main, .line) span {font-size: 12px;
}5、:is伪类选择器函数
作用:与:where()函数选择器用法一致。
优先级不同。:where()函数选择器的优先级总是为0(即使他的样式代码在最下面)
而:is()函数选择器的优先级取决于他的参数选择器列表中最高的选择器
.main span {font-size: 12px;
}:is(.main) span {font-size: 13px;
}span {font-size: 14px;
}:where(.main) span {font-size: 15px;
}
:where()优先级最低;其次是span选择器;第一个选择器和:is()函数选择器的优先级都是.main span,
因此他们优先级一致,但是因为is()函数在下面,因此font-size为13px。
sass1、使用变量 $
$aaa: 16px;
.fontSize {font-size: $aaa;
}2、@extend 继承
.success{color:green;
}
.msg{@extend .success;color: #555555;
}3、@if
当 @if 的表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码:
p{$num : 3;@if $num == 1 {color:red;}@else{border:red;}
}4、@for
指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。
@for $i from 1 through 3 {.item-#{$i} {width: 2em * $i;}
}
上面等于
.item-1 { width: 2em; }
.item-2 { width: 4em; }
.item-3 { width: 6em; }
三、隐藏元素的方法
display:none;元素在页面上消失,不占据空间
visibility:hidden; 让元素消失,占据空间位置,一种不可见的状态
opacity:0; 设置了元素的透明度为0,元素不可见,占据空间位置
position:absolute; 使用定位,让元素移到页面之外
四、px、rpx、vw、vh、em、rem
px:绝对长度、固定单位,无法根据页面的大小而改变
rpx: 小程序独自有的
vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%。
vh:viewpoint height,视窗高度,1vh等于视窗高度的1%。
em和rem:相对长度,适用于响应式布局(em的大小相对于父元素大小而改变,rem的大小相对于根元素的大小而改变)
据不同屏幕的宽度,以相同的比例动态修改html的font-size适配,并将px替换成rem,它可以很好的根据根元素的字体大小来进行变化,从而达到各种屏幕基本一直的效果体验
配置rem
window.onload = () => { document.documentElement.style.fontSize = window.innerWidth / 375 * 100 + 'px'; }
window.onresize = () => { document.documentElement.style.fontSize = window.innerWidth / 375 * 100 + 'px'; }
五、重排重绘
重排(回流):布局引擎会根据所有的样式计算出盒模型在页面上的位置和大小,对DOM的大小、位置进行修改后,浏览器需要重新计算元素的这些几何属性,就叫重排。减少重排可以增强浏览器效率。
重绘:计算好盒模型的位置、大小和其他一些属性之后,浏览器就会根据每个盒模型的特性进行绘制,对DOM的样式进行修改,比如color和background-color,浏览器不需要重新计算几何属性的时候,直接绘制了该元素的新样式,那么这里就只触发了重绘
六、元素水平垂直居中
1、定位 + margin
2、定位 + transform
3、flex布局
4、gird布局
5、table布局
七、响应式开发(移动端适配)
1、使用rem、em、vw、vh、百分比、flex、@media媒体查询等布局
2、监听是手机端打开还是PC端打开,配置两套路由或样式
3、监听页面窗口大小,配置多套样式
八、JS三部分
1、ECMAScript:JS的核心内容,描述了语言的基础语法。
2、文档对象模型(DOM):DOM把整个HTML页面规划为元素构成的文档。DOM 文档对象模型,就是一个API,可以通过操作这些API在页面上进行绘制节点,设置节点的属性和内容。
例如:document.getElementById('app');document.createElement('hr');app.appendChild(hr);app.setAttribute('class', 'aaa');
3、浏览器对象模型(BOM):对浏览器窗口进行访问和操作。BOM 浏览器对象模型,可以用来操作浏览器的打开、关闭、重加载等。
例如:location 当前页面的地址;history 浏览器浏览过的历史;navigator 浏览器当前的用户设备信息;window 浏览器的高度、宽度。浏览器的滚动和打印功能......
九、JS部分内置对象
String、Boolean、Number、Array、Object、Function、Math、Date、RegExp...
Math:abs() 函数返回绝对值 sqrt() 接受一个非负正数,返回平方根 max() 最大值 min() 最小值......
Data:new Data() 获取当前时间戳 getYear() 获取年份 ......
十、数组方法
1、改变原数组:push 最后面加一个、pop 最后面删一个、unshift 最前面加一个、shift 最前面删一个、sort 排序、splice 可以删除替换增加元素
2、不改变原数组:reverse 反转顺序、concat 合并数组、join 将元素拼接成字符串、isArray 判断一个值是否为数组、findIndex 返回满足指定条件的第一个元素的索引,如果没有找到则返回 -1。
map:创建一个新数组,其元素是原数组经过指定函数处理后的结果。
const numbers = [1, 2, 3, 4, 5];
const squares = numbers.map(num => num * num);
console.log(squares); // 输出: [1, 4, 9, 16, 25]
filter:创建一个新数组,其中包含原数组中满足指定条件的所有元素。
let arr = [1, 2, 3, 4, 5];
let evenNumbers = arr.filter(item => item % 2 === 0);
console.log(evenNumbers); // 输出 [2, 4]
every:判断数组中所有元素是否都满足指定条件,如果是则返回 true,否则返回 false。
let arr = [2, 4, 6, 8, 10];
let allEven = arr.every(item => item % 2 === 0);
console.log(allEven); // 输出 true
some:判断数组中是否存在满足指定条件的元素,如果有则返回 true,否则返回 false。
let arr = [1, 3, 5, 7, 8];
let hasEven = arr.some(item => item % 2 === 0);
console.log(hasEven); // 输出 true
reduce:将数组中的元素通过指定函数进行累积计算,返回一个最终的结果。
let arr = [1, 2, 3, 4, 5];
let sum = arr.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 输出 15
为什么调用接口时,用 push 而不用 concat?
因为 push 是改变原数组,而 concat 是生成新数组。
for 数组、forEach 数组、for of 数组、for in 数组和对象都能遍历
let arr = [ "a", "b", "c", "d", "e" ];
let obj = { a: 1, b: 2, c: 3 }
for(let i = 0; i < arr.length; i++){ console.log(i, arr[i]) // 下标 值
}
arr.forEach((item, index) => { console.log(item, index) // 值 下标
})
for(let i of arr){ console.log(i) //值
}
for(let i in arr){ console.log(i, arr[i]) // 下标 值
}
for(let i in obj){ console.log(i, obj[i]) // 键 值
}
for、forEach差别:forEach 无法使用 break、return、continue 进行中断操作或跳出循环。只能使用 try、catch 中断,抛出异常。for循环能控制起点,forEach 不能(必须从第一个开始)。运行速度:for > forEach
try {arr.forEach((item, index) => {if (item == 1) {throw new Error("打断施法")}})
} catch (e) {if (e.message !== "打断施法") {throw e}
}
forEach 和 map 的区别
1、forEach()方法没有返回值,会更改原数组。
2、map() 有返回值,返回一个新数组,不会改变原数组,map() 不会对空数组进行检测。
3、map 的速度大于 forEach()
find:用于找出第一个符合条件的数组成员,并且返回该数组元素,如果没有满足条件的数组元素该方法返回undefined。
let arr1 = [1, 2, 3, 4, 5]
let num1 = arr1.find(function(item) {return item > 1;
});
console.log(num1); //2
findIndex:用于找出第一个符合条件的数组成员的索引值,并且返回该数组元素的索引值。如果没有满足条件的数组元素该方法返回-1。
let arr2 = [1, 7, 9, 4, 5]
let num1 = arr2.findIndex(item => item > 9);
console.log(num1); //-1
let num2 = arr2.findIndex(item => item > 3);
console.log(num2); //2
includes:判断数组是否包含指定值—是全等判断,第一个值是包含的指定值,第二个值是指定值的索引。
let arr4 = [2, 3, 4, 7, 5]
let flag = arr4.includes(2);
console.log(flag); //true
let flag1 = arr4.includes(3, 1);
console.log(flag1); //true
十一、字符串方法
charAt() 方法可返回指定位置的字符;
concat() 方法用于连接两个或多个字符串或数组;
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。没有为 -1;
lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索;
replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
slice、substr、substring截取字符串; split 分割成数组; trim 去空格; toLowerCase toUpperCase 转英文大小写
十二、JS对数据类的四种检测方式
typeof() 可以判断除了null以外的基本数据类型,引用数据类型不管用,识别数组等均为 object
instanceof() 只能判断引用类型,不能判断基本数据类型
constructor 几乎可以判断所有。如果声明一个构造函数,并把它的原形指向Array,他就识别不出来了
Object.prototype.toString.call()
十三、闭包
什么是闭包?函数嵌套函数,内层函数访问外层函数的变量。
特点:变量持久化,不会被垃圾回收机制回收;防止变量和参数被外部污染,变量只在闭包内部可访问。
缺点:闭包较多的时候,会消耗内存,导致页面的性能下降,在IE浏览器中才会导致内存泄漏。
解决:在不需要用的时候,设为 null(垃圾回收机制自动回收)。
使用场景:防抖,节流,函数嵌套函数避免全局污染的时候。
防抖和节流区别:操作时不执行,确定不操作了才执行;节流到了时间执行一次。
function makeCounter() {let count = 0;return function() {count++;console.log(count)}
}
const conter = makeCounter()
console.log(makeCounter) // 整体函数
console.log(makeCounter()) // 内部函数
conter() // 1 只执行了内部函数,所以 count 的值增加
conter() // 2 只执行了内部函数,所以 count 的值增加
conter() // 3 只执行了内部函数,所以 count 的值增加
十四、内存泄漏
JS里已经分配内存地址的对象,但是由于长时间没有释放或者没办法清除,造成长期占用内存的现象,会让内存资源大幅浪费,最终导致运行速度慢,甚至崩溃的情况。
垃圾回收机制:js具有的回收机制,将不再使用的变量和对象进行回收,进行空间的释放。
因素:1 意外的全局变量泄露 2 console.log 使用 3 闭包泄露,赋值给全局变量后,对函数的引用一直存在 4 dom 泄露,remove dom 节点之后,但是remove 的 dom 节点对子节点的引用一直存在 5 一些未清空的定时器 6 监听事件没被销毁
小技巧:把功能写在函数里面能解决大部分内存泄漏问题问题,还有记得用let 和 const 声明变量别用var了
十五、基本数据类型(栈)和引用数据类型(堆)
基本数据类型:基本数据类型保存在栈内存当中,保存的就是一个具体的值。
String Number Boolean undefined null Symbol
引用数据类型:保存在堆内存当中,声明一个引用类型的变量,它保存的是引用类型数据的地址。假如声明两个引用类型同时指向了一个地址的时候,修改其中一个那么另外一个也会改变。
Object Function Array
十六、undefined 和 null
undefined 表示一个变量自然的、最原始的状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。当需要释放一个对象时,直接赋值为 null 即可。
两个表示 无 的值,一个null,一个undefined。undefined 表示无的原始值,转化为数字时为 NAN;null表示为无对象,转化为数字时为 0。
十七、事件委托(事件代理)
利用事件冒泡的机制来实现,也就是说把子元素的事件绑定到了父元素的身上。
好处:提高性能,减少事件的绑定,也就减少了内存的占用。
如果子元素阻止了事件冒泡,那么委托也就不成立,阻止事件冒泡event.stopPropagation()
在 DOM 中,事件捕获发生在事件冒泡之前,并且是事件处理的第一个阶段。在这个阶段,事件从文档的根节点向下传播到达目标元素。调用 event.stopPropagation() 只能阻止事件在捕获阶段或冒泡阶段中的继续传播,但它不能阻止事件捕获阶段的执行。
要完全阻止事件捕获阶段的执行,可以考虑在捕获阶段的事件处理函数中使用 event.stopImmediatePropagation() 方法,它会立即阻止事件继续传播,包括捕获和冒泡阶段。
addEventListener('click', 函数, true/false) 默认是false(事件冒泡),true(事件捕获)
三个参数( 指定事件名 指定要事件触发时执行的函数 可选,默认false。布尔值,指定事件是否在捕获或冒泡阶段执行)
事件捕获速度高于事件冒泡
十八、原型链
当我们访问一个对象的属性或方法时,如果该对象本身没有该属性或方法,JavaScript 就会通过__proto__属性向上查找,直到找到对应的属性或方法,或者到达原型链的尽头 null。
原型链的顶端是 null,这表示原型链的终点。在 JavaScript 中,对象的原型链最终会追溯到 null。
实例对象的隐式原型__proto__全等于构造函数的原型prototype
for in可遍历原型链上扩展的属性,Object.keys() 只遍历自身属性
// 定义一个构造函数 Person
function Person(name) {this.name = name;
}
// 在 Person 的原型上定义一个方法 sayHello
Person.prototype.sayHello = function() {console.log("Hello, " + this.name);
};
// 创建一个 Person 的实例
var person = new Person("John");
// 实例对象的隐式原型__proto__全等于构造函数的原型prototype
console.log(person.__proto__ === Person.prototype); // 输出:true// for in可遍历原型链上扩展的属性,Object.keys() 只遍历自身属性
Object.prototype.say="123";
var person ={ age: 18 };
for (var key in person) {console.log(key, person[key]);
}
// age 18
// say 123
console.log(Object.keys(person));
// ["age"]
十九、new操作
1、先创建一个空对象
2、把空对象和构造函数通过原型链进行链接
3、把构造函数的this绑定到新的空对象身上
4、返回结果 res,如果 返回结果res 是一个对象则返回 res,否则返回 obj
function _new(aFn, ...args) {let obj = {};obj.__proto__ = aFn.prototype;const res = aFn.apply(obj, args);// 返回结果 res,如果 res 是一个对象则返回 res,否则返回 objreturn res instanceof Object ? res : obj;
}
二十、Js创建对象的3种方式和Js继承5种方式
// 1 对象字面量方式 var obj = {}; obj.name = "张三";// 2 工厂模式(利用函数创建对象) function createFactory(name) {var obj = new Object;obj.name = name;return obj; } var obj = new createFactory("王五");// 3 构造函数模式 function Person(uname) {this.uname = uname } Person.prototype.sing = function(songName){console.log(this.uname+"会唱"+songName); } var person1 = new Person("刘德华"); person1.sing("有只小鸟掉下水")1. 原型链继承(子类原型 等于 new 父类) 优点:父类方法可以复用 缺点:父类中所有的引用类型(对象、数组)会被子类共享,更改一个子类的数据,其他数据会受到影响,一直变化。(基本数据类型不会);子类实例不能给父类构造函数传参。2. 构造函数继承(在子类里,将父类的构造函数的this指向子类里的this) 优点:父类的引用类型不会被子类共享,不会互相影响。 缺点:子类不能访问父类原型属性(Person.prototype)上的方法和参数3. 组合式继承(将1和2结合起来) 优点:父类可以复用;父类构造函数中的引用属性数据不会共享 缺点:会调用两次父类的构造函数,会有两份一样的属性和方法,影响性能。4. 寄生组合继承(目前最优的继承方案,创建第三个构造函数,将第三构造函数的原型和父类的构造函数连接,再将子类的原型等于 new 一个第三构造函数,再与2结合)5. ES6的class类继承 extends class Student extends Person{}
二十一、this指向的问题
1 全局对象中的this指向(指向的是window)
2 全局作用域或者普通函数中的this(指向全局window)
3 匿名函数中的this(永远指向了window,匿名函数的执行环境具有全局性,因此this指向window)
4 new 关键词改变了this的指向(指向新的实例对象)
5 call,apply,bind(可以改变this指向,指向第一个参数,不是箭头函数)
6 this永远指向最后调用它的那个对象(在不是箭头函数的情况下,谁调用指向谁)
7 箭头函数中的this,它的指向在定义的时候就已经确定了。(箭头函数它没有this,看外层是否有函数,有就是外层函数的this,没有就是window,因为箭头函数没有自己的this,也无法用call等进行更改this指向)
call, apply 第二个参数是数组, bind 有返回值的
function fun() {console.log(this.name)
}
let name = "window name"
let cat = {name: "喵喵"
}
fun() // window name
// call 可以改变函数中的 this 指向
fun.call(cat) // 喵喵
let dog = {name: "旺财",sayName() {console.log("我是" + this.name)},eat(foot1, foot2) {console.log("我喜欢吃" + foot1 + foot2)}
}
dog.sayName() // 我是旺财
dog.sayName.call(cat) // 我是喵喵
dog.eat("骨头", "饲料") // 我喜欢吃骨头饲料
dog.eat.call(cat, "鱼", "饼干") // 我喜欢吃鱼饼干
dog.eat.apply(cat, ["鱼", "饼干"]) // 我喜欢吃鱼饼干
let aaa = dog.eat.bind(cat, "鱼", "饼干")
aaa() // 我喜欢吃鱼饼干
二十二、setTimeout、setInterval、requestAnimationFrame
定时器(setTimeout 延时调用、setInterval 定时调用)和requestAnimationFrame定时器 实现的动画在某些低端机上会出现卡顿、抖动的现象,任务被放进了异步队列中,只有当主程上的任务执行完之后,才会去检查该队列里的任务是否需要执行,因此setTimeout的实际执行时间一般要比其设定的时间晚一些。
requestAnimationFrame H5新增 在下一次重绘之前会更新动画帧所调用的函数。在隐藏元素中和页面不激活的状态下,requestAnimationFrame 不进行工作,减少CPU、GPU、内存的使用量。
23 事件循环(EventLoop)
JS是一个单线程的脚本语言,执行栈、宿主环境、任务队列、同步、异步(微任务、宏任务【定时器、点击事件】)
先同后异,先微后宏,先进先出。同步任务放在执行栈优先执行,异步任务放在宿主环境等待。异步任务的时间到了,或被触发(类似点击事件等),将异步任务推送到任务队列。
当执行栈执行完,执行栈就回去执行任务队列里面的任务。
promise 是同步任务,直接执行里面的代码,.then 才是异步任务,resolve 是调用成功,把值传递到 .then 里面。.then 是微任务
DOM 操作在原生JS中是同步操作,在VUE中是异步操作(在 Vue.js 中,DOM 操作本身并不是异步的。就像在原生 JavaScript 中一样,直接的 DOM 操作(例如通过 ref 或 this.$refs 访问元素并修改其属性)是同步执行的。但是,Vue.js 的响应式系统和虚拟 DOM 机制确实会引入一些异步的特性.this.$nextTick 可以确保回调函数在 DOM 更新完成后执行,用于获取更新后的 DOM 状态或执行其他操作)。
二十四、页面渲染过程
1 浏览器会获取HTML和CSS的资源,然后把HTML解析成DOM树
2 再把CSS解析成CSSOM
3 把DOM和CSSOM合并为渲染树
4 计算和布局、把渲染树的每个节点渲染到屏幕上(绘制)
DOM树是和HTML标签一一对应的,包括head和隐藏元素;渲染树是不包含head和隐藏元素,渲染树包含CSSOM
二十五、浏览器的存储方式
1 Cookies
优点: Cookies 是最早引入的本地存储技术,具有广泛的浏览器兼容性,并支持跨域存储。Cookies可以存储较小的数据量(通常限制为4KB),可以设置过期时间,支持持久化保存和定时清除。
缺点:Cookies 在每个 HTTP 请求中都会被发送到服务器端,造成额外的网络流量。受到浏览器限制,每个域名下的 Cookies 数量和总大小都有限制。同时,Cookies 中的数据可以被读取和算改,安全性有限。
2 Web Storage (Localstorage 和 SessionStorage)
Localstorage 本地存储(永久存在) SessionStorage 会话存储(页面关闭就没了,多个页面不共享)
优点: web storage 提供了更大的存储容量(通常限制为5MB) 且只在客户端存储,不会在每个请求中发送到服务器。Localstorage 和 SessionStorage 提供简单的键值对存储,并且在同一浏览器窗口下共享数据。
缺点: Localstorage 在浏览器中是永久性的,除非手动删除,否则数据会一直保留。由于浏览器限制,数据在不同的浏览器窗口和标签页之间无法共享。同时,对于较旧的浏览器版本,对 Webstorage 的支持可能不完整。
3 IndexedDB
IndexedDB 是一种通用的浏览器本地微型数据库,它不依赖于特定的应用或服务,而是作为现代 Web 应用程序的一部分,提供了一种持久化存储数据的机制。
VUE项目每次打包的版本号是可以配置不同编码的。这样的话不用线上强制刷新。