😀HTML && CSS
1. BFC(块级格式化上下文)
BFC的概念
BFC是Block Formatting Context的简写,可以直译成块级格式化上下文。它会创建一个特殊的区域,在这个区域中,只有block box参与布局;规定了在这个区域中如何进行布局,如何进行定位,区域内元素的相互关系和相互作用。这个区域不受外界影响。
如何形成BFC
- 根元素
<html>或其他包含根元素的元素 - 浮动元素(
元素的float不是none) - 绝对定位元素(
元素的position为absolute或fixed) display的值为inline-block、table-cell、table-captionoverflow的值不为visible的块元素- 弹性元素(
display为flex或inline-flex元素的直接子元素) - 网格元素(
display为grid或inline-grid元素的直接子元素)
BFC的特点
- 内部的box会独占宽度,且在垂直方向上一个接一个排列
- box在垂直方向的间距由margin属性决定,但是同一个BFC的两个相邻box的margin会重叠
- 每个box在水平方向上的左边缘与BFC的左边缘相对齐,即使存在浮动也是如此
- BFC区域不会与浮动元素重叠,而是会依次排列
- BFC区域是一个独立的渲染容器,容器内的元素和BFC区域外的元素不会有任何干扰
- 浮动元素的高度也参与BFC的高度计算
根据以上特点,可以用于实现
边距重叠,清除浮动,自适应多栏布局
2. 如何实现水平垂直居中
居中元素固定宽高(width: 100px; height: 100px;)
// 1. [absolute] + [-margin]
// 父元素设置
position: relative;
// 子元素设置
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -50px;
// 2. [absolute] + [margin auto]
// 父元素设置
position: relative;
// 子元素设置
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
// 3. [absolute] + [calc]
// 父元素设置
position: relative;
// 子元素设置
position: absolute;
left: calc(50% - 50px);
top: calc(50% - 50px);
居中元素不固定宽高
// 1. [absolute] + [transform]
// 父元素设置
position: relative;
// 子元素设置
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%); // transform的translate的属性可以基于自身的宽高设置百分比
// 2. [lineheight]
// 父元素设置
line-height: 200px;
text-align: center;
// 子元素设置
display: inline-block;
vertical-align: middle;
line-height: inherit;
// 3. [css-table]
// 父元素设置
display: table-cell;
text-align: center;
vertical-align: middle;
// 子元素设置
display: inline-block;
// 4. [flex]
// 父元素设置
display: flex;
justify-content: center;
align-items: center;
// 5. [grid]
// 父元素设置
display: grid;
// 子元素设置
justify-self: center;
align-self: center;
3. 实现主题切换
// 1. 使用css变量实现主题切换(ie兼容问题可以使用插件解决)
<template>
<button @click="handleToggleTheme">toggle-theme</button>
<p>努力奋斗!</p>
</template>
<script setup>
import { onMounted } from "vue";
onMounted(() => {
if (localStorage.getItem("blackTheme")) {
document.body.classList.add("black-theme");
}
});
function handleToggleTheme() {
if (document.body.classList.contains("black-theme")) {
document.body.classList.remove("black-theme");
localStorage.removeItem("blackTheme");
} else {
document.body.classList.add("black-theme");
localStorage.setItem("blackTheme", true);
}
}
</script>
<style>
body {
color: var(--text-color);
background: var(--bg-color);
}
:root {
--bg-color: white;
--text-color: black;
}
.black-theme {
--bg-color: black;
--text-color: white;
}
</style>
😁JavaScript
1. JavaScript数据类型及其判断
JavaScript中具有7种数据类型,分别是number、string、boolean、undefined、null、object、symbol(ES6)。前5种为基本类型。object类型包含了function、array、data等。常用的类型判断方法有:typeof、instanceof、Array.isArray、Object.prototype.toString、constructor。
使用typeof判断数据类型
typeof 1 // number
typeof 'string' // string
typeof true // boolean
typeof undefined // undefined
typeof null // object
typeof function() {} // function
typeof [] // object
typeof {} // object
typeof Symbol(1) // symbol
使用instanceof判断数据类型
instanceof用于检测实例对象的原型链上是否存在构造函数的prototype属性
function Person() {}
const people = new Person()
people instanceof Person // true
5 instanceof Number // false
new Number(5) instanceof Number // true
Array.isArray只能判断是否为数组
Array.isArray([]) // true
Array.isArray(1) // false
使用Object.prototype.toString判断数据类型(万能方法,任何类型都能判断出来)
Object.prototype.toString.call(1) // [object Number]
Object.prototype.toString.call('string') // [object String]
Object.prototype.toString.call(true) // [object Boolean]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(function() {}) // [object Function]
Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call({}) // [object Object]
Object.prototype.toString.call(Symbol(1)) // [object Symbol]
// 封装getType方法
function getType(data) {
return Object.prototype.toString.call(data).slice(8, -1).toLowerCase()
}
constructor返回的是构造函数本身
1.constructor // ƒ Number() { [native code] }
'string'.constructor // ƒ String() { [native code] }
true.constructor // ƒ Boolean() { [native code] }
function() {}.constructor // ƒ Function() { [native code] }
[].constructor // ƒ Array() { [native code] }
{}.constructor // ƒ Object() { [native code] }
Symbol(1).constructor // ƒ Symbol() { [native code] }
undefined.constructor // TypeError
null.constructor // TypeError
// undefined、null 读取constructor属性会报错!!!
2. 实现New
new关键字到底做了什么
- 创建一个空对象,这个对象将作为执行构造函数之后返回的对象实例
- 空对象的
__proto__指向构造函数的prototype属性 - 空对象赋值给构造函数内部的
this,并执行构造函数逻辑 - 返回创建的对象或构造函数的显示返回值
function myNew(fn, ...args) {
// 不是函数报错
if (typeof fn !== "function") {
throw TypeError(`Expected a function, but get a ${typeof fn}`);
}
// let obj = {}; // 创建空对象
// obj.__proto__ = fn.prototype; // 将对象的__proto__指向构造函数的prototype属性
let obj = Object.create(fn.prototype); // 创建空对象,并将对象的__proto__指向构造函数的prototype属性
// const result = fn.call(obj, ...args)
const result = fn.apply(obj, args); // 对象作为this调用构造函数
return typeof result === "object" ? result : obj;
}
3. Object.create 的实现原理
function myCreate(obj) {
// __proto__在IE下已被禁用,兼容性不好,不建议使用
// let emptyObj = {};
// emptyObj .__proto__ = obj;
// return emptyObj ;
// 推荐方法
// 使用空方法原型挂在目标对象,做实例化
// 空方法实例化可以创建空对象
// 方法的原型等价于实例化后的对象的原型链,即 (方法).prototype = (实例对象).__proto__
function Fun() {};
Fun.prototype = obj;
return new Fun();
}
4. 实现多维数组扁平化
const array = [1, [2, [3, [4, [5, 6]]], 7, 8], 9, 10];
/**
* 1. Array.prototype.flat(depth)
* flat()方法会按照一个可指定的深度[depth]递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
* flat()方法会移除数组中的空项
*/
array.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 2. reduce
function flatten(array) {
return array.reduce((res, cur) => {
return Array.isArray(cur) ? res.concat(flatten(cur)) : res.concat(cur);
}, []);
}
flatten(array) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 3. forEach
function flatten(array, res = []) {
array.forEach((item) => {
Array.isArray(item) ? flatten(item, res) : res.push(item);
});
return res;
}
flatten(array) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
/**
* 4. while + Array.prototype.some()
* some()方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值
*/
function flatten(array) {
while (array.some((item) => Array.isArray(item))) {
array = [].concat(...array);
}
return array;
}
flatten(array) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 5. 需要数组所有元素类型相同
function flatten(array) {
return array
.toString()
.split(",")
.map((x) => Number(x));
}
flatten(array) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
5. 扁平化数组变成树
const array = [
{ name: "中国", id: "1", parentId: "0" },
{ name: "辽宁", id: "1-1", parentId: "1" },
{ name: "大连", id: "1-1-1", parentId: "1-1" },
{ name: "沈阳", id: "1-1-2", parentId: "1-1" },
{ name: "山东", id: "1-2", parentId: "1" },
{ name: "青岛", id: "1-1-3", parentId: "1-2" },
];
// 1. forEach
function getTree(arr, parentId = "0") {
let array = [];
arr.forEach((item) => {
if (item.parentId === parentId) {
let child = getTree(arr, item.id);
if (child.length > 0) {
item.child = child;
}
array.push(item);
}
});
return array;
}
6. 实现 add(1)(2)(3)(4) = 10
// 1. 函数柯里化
// 柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
const add = w => x => y => z => w + x + y + z
add(1)(2)(3)(4) // 10
// 2
function add() {
const args = [...arguments];
function fn() {
args.push(...arguments);
return fn;
};
fn.valueOf = function () {
return args.reduce((sum, cur) => {
return sum + cur;
}, 0);
};
return fn;
}
add(1)(2)(3)(4).valueOf() // 10
add(1)(2, 3)(4).valueOf() // 10