HTML/CSS基础
1、盒模型
每个HTML元素都可看作盒模型,有标准盒模型(W3C)和IE盒模型。
标准盒模型:width=content的width,可以通过box-sizing:content-box设置
IE盒模型:width=content+padding+border,可以通过box-sizing:border-box设置
2、BFC
就是“块级格式化上下文”,是一个独立容器,容器里边和外边元素互不影响。
如何让所属box产生BFC:
-overflow:auto/hidden;
-position:定位如absolute/fixed;
-float:浮动元素如left/right;
-display:inline-block/table-cell/flex;
BFC使用场景:
-float实现两栏布局,左侧float:left,右侧overflow:auto,原理是BFC不和float元素重叠;
-overflow:auto在父元素上可以清除子元素的浮动;
-overflow:hidden在父元素可以解决垂直子元素上下margin重叠的问题;
3、元素居中
1)、 translate
center
.box {
position: relative;
border: 1px solid red;
height: 60px;
}
.container {
width: 100px;
height: 20px;
border: 1px solid red;
}
.box-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
2)、 flex
flex
.box-flex {
display: flex;
align-items: center;
justify-content: center;
height: 80px;
border: 1px solid gray;
}
.container {
width: 100px;
height: 20px;
border: 1px solid red;
}
4、实现3行3列布局
1)flex
原理:容器flex布局,flex-wrap:wrap换行显示。
flex:合并属性,flex-basic,flex-grow,flex-shrink
flex-basic:定义元素初始宽或高,根据flex-direction确定是设置宽还是高,默认值main-size | width;
flex-grow:定义每一个子元素在盒子内的弹性,元素扩展剩余空间的能力,默认值:0
剩余空间的分配规则 : flex-basis + flow-grow/sum(flow-grow)remain remain 表示多余的空间
flex-shrink:定义元素收缩的能力(空间不足时),默认: 1
不足空间收缩的规则 : flex-basis + flow-grow/sum(flow-grow)remain remain 表示不足的空间 (负值)
可参考:https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
111
111
111
111
111
.flex-multi-col {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.flex-multi-col .cont {
flex: 0 0 30%; //3列,所以是30%,4列为25%或以下等
height: 30px;
margin-right: calc(10% / 2);
margin-bottom: calc(10% / 2);
background-color: aqua;
box-sizing: border-box;
}
/* last column remove margin right */
.flex-multi-col .cont:nth-child(3n) {
margin-right: 0;
}
/* last child margin right occupy the remaining space */
.flex-multi-col .cont:last-child {
margin-right: auto;
}
/* last line remove the margin bottom */
.flex-multi-col .cont:nth-last-child(-n+3) {
margin-bottom: 0;
}
2)grid
原理:容器grid布局,grid-template-columns: 1fr 1fr 1fr等比例分配空间;
可参考:https://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html
111
111
111
111
111
.grid-multi-col {
display: grid;
justify-content: space-between;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
}
.grid-multi-col .cont {
background-color: aquamarine;
}
Javascript
1、9*9乘法表
for (let i = 0; i <= 9; i++) {
document.write("");
for (let j = 1; j <= i; j++) {
document.write(" ");
document.write("" + i + "*" + j + "=" + i * j + " ");
document.write(" ");
}
document.write("
");
}
2、根据对象的一个属性将对象排序
// 当 a>b 时,
// a - b > 0 ,排序结果 ===> b,a (升序)
// b - a < 0 ,排序结果 ===> a,b (降序)
// 当 b>a 时,
// a - b < 0 ,排序结果 ===> a,b (升序)
// b - a > 0 ,排序结果 ===> b,a (降序)
// 当 a=b 时,
// a - b = b - a =0 , 排序结果 ===> 保持不变
// 由此看出,
// 无论a>b还是b>a,return a-b 总能得到升序的结果,而 return b-a 总能得到降序的结果。
let arr = [{id: 1, name: "aaa" },{ id: 3},{id: 2},{id: 6}];
function compare(property) {
return function (a, b) {
var value1 = a[property];
var value2 = b[property];
console.log(value1)
return value1 - value2; //升序
};
}
console.log(arr.sort(compare("id"))); //[0: {id: 1, name: "aaa"},1: {id: 2},2: {id: 3},3: {id: 6}]
//根据上述原理,可实现数组排序
var arrSort = [1, 22, 15, 32, 4, 5, "11"]
arrSort.sort((a, b) => {
if (a > b) return 1;
else if (a < b) return -1;
else return 0;
});
console.log(arrSort)
// [1,4,5,15,22,32] //升序
3、this,js中 call()、apply()、bind() 的用法
var name = "this.window";
var obj = {
name: "my object",
getNameFunc: function () {
console.log(this); //{name: "my object", getNameFunc: ƒ}
return function () {
console.log(this); //Window {window: Window, self: Window, document: …}
console.log(this.name); //this.window
};
},
};
obj.getNameFunc()();
-call()、apply()、bind() 都是用来重定义 this 这个对象的
-bind 返回的是一个新的函数,你必须调用它才会被执行
区别:
call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,'成都', ... ,'string' )。
apply 的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['成都', ..., 'string' ])。
bind 除了返回是函数以外,它 的参数和 call 一样。
可参考:https://www.runoob.com/w3cnote/js-call-apply-bind.html
4、闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常用方式:在一个函数内部创建另一个函数
使用场景:创建私有变量、延长变量的生命周期、计数器、延迟调用(这里会考查到防抖和节流)、回调
for (var i = 0; i < 3; i++) {
setTimeout(() => { console.log(i) }, 1)
}
// 3 3 3
for (let i = 0; i < 3; i++) {
setTimeout(() => { console.log(i) }, 1)
}
// 0 1 2
考察:必包;js事件循环机制;var定义的i为全局变量,let定义的i为块变量
可参考:https://segmentfault.com/a/1190000023356598
5、js实现树形菜单
let source = [
{ id: 1, pid: 0, name: 'body' },
{ id: 2, pid: 1, name: 'title' },
{ id: 3, pid: 2, name: 'div' },
]
console.log(source)
//将每项的id作为对象的key,每一项作为对象的value,保存到新对象map
let map = [] //所有的父节点
source.map(item => {
return map[item.id] = item
})
let val = []
source.map(item => {
let parent = map[item.pid] //查找是否存在该项的父节点
if (parent) {
//该项的父节点存在,将该项push到父节点的children中
parent.children = [];
parent.children.push(item)
} else {
//该项的父节点不存在,那么该项是根节点,其他项目都是该项的子节点,val为根节点
val.push(item)
}
return val
})
console.log(val)
6、手写一个通用方法实现下边的转换
“23214237835782937532500.00”转为:"232#1423#7835#7829#3753#2500.00"
let str = "23214237835782937532500.00"
let conStr = str.split("").reverse().join("")
conStr = conStr.split(".")[1]
let res = ''
for (let i = 0; i < conStr.length; i++) {
if (i % 4 === 0) {
res += '#' + conStr[i]
}
else {
res += conStr[i]
}
}
res = res.split("")
res.splice(0, 1, '');
res = res.reverse().join("")
res = res + '.00'
console.log(res);
7、数组去重,方法有很多
1)利用Set不重复
2)利用对象key不重复的特点
3)利用新数组中是否包含数组项indexOf()
...
let arr = [1, 2, 3, 5, 6, 3, 1, 7, 9, 10, "2"]
// 对纯数字数组有效
console.log("Set去重:" + [...new Set(arr)]) //Set去重:1,2,3,5,6,7,9,10,2
//对有字符串数组也有效
let obj = {}
arr.map((item, i) => {
obj[arr[i]] = 1
})
let newArr = Object.keys(obj).map(o => Number(o))
console.log("利用对象key不重复:" + newArr) //利用对象key不能重复来去重数组:1,2,3,5,6,7,9,10
//indexOf()
let resArr = []
arr.forEach((item, i) => {
let flag = resArr.indexOf(item) > -1
if (!flag) {
resArr.push(item)
}
})
console.log(resArr) //[1, 2, 3, 5, 6, 7, 9, 10, "2"]
可参考:https://segmentfault.com/a/1190000016418021
8、for in 遍历对象
//for in 遍历对象,且会遍历对象原型上的属性
Object.prototype.z = 1
let obj = { x: 1, y: 2 }
for (let k in obj) {
console.log(k) //x,y,z
if (obj.hasOwnProperty(k)) {
console.log("obj的属性:" + k) //x,y
}
}
9、for of 遍历数组
//for of 遍历数组,对象不能使用
// let arr = ['1','2','3']
let arr = [{ name: 'zcc', age: 18 }, { name: 'z', sex: 'nv' }]
// let obj = {'name':'zcc','age':18}
for (let k of arr) {
console.log("for of arr :" + k['name']) //for of arr :zcc ,for of arr :z
}
10、forEach 和 map
forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。
let arr = [1, 3, 5, 6];
let map = arr.map(item => item * item)
console.log(map) //map不修改原始数组 //[1, 9, 25, 36]
let res = []
arr.forEach((item) => {
res.push(item + 2)
});
arr.forEach((item,index) => {
return arr[index] = item+2
});
console.log(arr) //[1, 3, 5, 6]
console.log(res) //[3, 5, 7, 8]
11、includes(),数组和字符串都适用
let arr = [1, 2, 5]
arr.includes(2) //true
let str = 'fdfdfd';
str.includes('fd') // true
12、深拷贝数组或对象
//slice()不改变原始数组,分割数组,可以深拷贝
//concat 方法实现数组的深拷贝
//es6中...展开运算符实现深拷贝数组 [...arr]
//for 循环实现数组的深拷贝
//深拷贝数组
let arr = [1, 3, 5, 6]
let arr2 = [...arr]
let res = arr.slice() //类似于arr.concat(),一维数组
res.push(9)
let slice = res.slice(0, 3)
console.log(arr) //[1, 3, 5, 6]
console.log(res) //[1, 3, 5, 6, 9]
console.log(slice) //[1, 3, 5]
//多维数组,for循环结合js递归实现
//万能的for循环实现对象的深拷贝
//JSON.parse(JSON.stringify(obj))
// 扩展运算符实现对象的深拷贝
//将数组转换为对象 {...arr}
let arr = [1, 3, 5, 6]
const obj = { ...arr }
console.log(obj) //{0: 1, 1: 3, 2: 5, 3: 6}
13、数组扁平化,第二种可以手动删除undefined
function flatArr(arr, d = 1) {
return d > 0 ? arr.reduce((prev, next) => prev.concat(Array.isArray(next)
? flatArr(next, d - 1) : next), []) : arr.slice()
}
let arrFlat = [1, 4, 5, [5, 6, undefined, , [3, 4, [4]], 8], 6];
console.log(flatArr(arrFlat, Infinity))
//[1, 4, 5, 5, 6, undefined, 3, 4, 4, 8, 6]
const flatArrForOfFunc = (arr = [], d = 1) => {
let result = [];
(function flat(arr, d) {
for (let item of arr) {
if (Array.isArray(item) && d > 0) {
flat(item, d - 1)
} else {
item !== void 0 && result.push(item)
}
}
})(arr, d)
return result
}
let arrFlat = [1, 4, 5, [5, 6, undefined, , [3, 4, [4]], 8], 6];
console.log(flatArrForOfFunc(arrFlat, Infinity))
//[1, 4, 5, 5, 6, 3, 4, 4, 8, 6]
14、splice()
//splice 接受3个参数,要插入元素的位置,从该位置删除的元素个数,插入的元素
let arr = [1, 3, 5, 6, 7]
// arr.splice(2,0,9) //0表示不删除元素个数,从第二位添加一个9
arr.splice(2, 1, 9) //从第二位删除一个元素,再添加一个9
console.log(arr)
Vue
1、vue组件传值
父传子:
父组件通过属性的方式向子组件传值,子组件通过 props 来接收
子传父:
子组件绑定一个事件,通过 this.$emit() 来触发
通过 $parent / $children 或 $refs 访问组件实例
$attrs/$listeners
兄弟组件:
子传父,父再传子,通过props,this.$emit()
EventBus,$emit和$on,发布订阅事件
$attrs/$listeners
vuex
多层级组件:
vue 提供的更高阶的方法:provide/inject
vuex
可参考:https://segmentfault.com/a/1190000022700216
2、vue keep-alive
可以使被包含的组件实现缓存,避免重新渲染。不会再次初始化,因此不会走mounted,如果希望重新渲染组件,activated 当 keepalive 包含的组件再次渲染的时候触发。
deactivated 当 keepalive 包含的组件销毁的时候触发
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
可参考:https://juejin.cn/post/6844903919273918477
3、vue双向数据绑定/响应式原理
数据变化更新视图,视图变化自动更新数据。
实现原理:
利用数据劫持和发布订阅者模式。主要涉及 Observer, Watcher , Dep这3个类,数据劫持利用ES5的Object.defineProperty(obj,key,val)为每个属性设置getter/setter,在数据set变动时,发布消息给订阅者,更新视图。
数据更改->通知Watcher->更新DOM
可参考:https://segmentfault.com/a/1190000023824423
https://cn.vuejs.org/v2/guide/reactivity.html
4、vue强制刷新组件
强制刷新也就是重新渲染组件,this.$forceUpdate();
v-if控制子组件移除后,nextTick可实现dom状态变化后,执行传入的方法,重新渲染组件
5、vue nextTick实现原理
异步任务队列里的macrotask,以事件循环的形式进入执行栈;每次事件循环包含一个微任务队列,在循环结束后依次执行队列中的微任务并移除,然后开始下一次事件循环;
调用nextTick时,vue就在更新DOM的那个微任务后追加我们自己的回调函数,确保代码在DOM更新后执行
常见微任务:promise、mutationObserver、node的process.nextTick
总结:vue先用异步队列方式控制DOM更新,nextTick后执行;
microtask优先级高特性,确保队列中的微任务在下一次事件循环开始前执行完毕。
6、修改elementUI样式
1)通过:style,:class 来局部修改样式,提高样式权重;
2)多个组件用到同一个组件需要不同的样式,比如el-table,可以在组件前加入不同的id选择器如#home .el-table; #order .el-table
3)这种 >>> 方式只能用在原生 CSS 语法中,不能在 css 预处理器如 less scss 等直接使用;
4)/deep/
/deep/ .el-cascader {
width: 100%;
}
7、Vue.js 性能优化技巧
https://juejin.cn/post/6922641008106668045
8、vue-router
可参考:https://juejin.cn/post/6844903945530245133
Http
1、webpack打包静态资源使用CDN
静态资源是指在不同请求中访问到的数据都相同的静态文件。例如:图片、视频、网站中的文件(html、css、js)、软件安装包、apk文件、压缩包文件等。
内容分发网络(Content Delivery Network),由分布在不同区域的边缘节点服务器群组成的分布式网络,现有的互联网基础之上的一层智能虚拟网络。
CDN加速的本质是缓存加速。将服务器上存储的静态内容缓存在CDN节点上,当访问这些静态内容时,无需访问服务器源站,就近访问CDN节点即可获取相同内容,从而达到加速的效果,同时减轻服务器源站的压力。
可参考:https://zhuanlan.zhihu.com/p/28940451
2、http缓存
强制缓存,首次向服务器请求资源,从服务器返回的响应头获取过期时间,在过期时间内不会向服务器发送请求,直接读取本地缓存。
协商缓存,会向服务器发送请求,服务器会根据request header标识来判断是否命中协商缓存,是就返回304,浏览器就读取本地缓存中的数据。如果没命中,服务器返回更新的资源和新的标识。
可参考:https://segmentfault.com/a/1190000016199807
3、http状态码
304 Not Modified,请求资源未修改时,服务器返回304,应用本地缓存的资源
4xx表示一般是客户端发生了错误
-400 Bad Request,客户端请求错误。
-401 Unauthorized,用户未经过认证,可以再次请求认证。
-403 Forbidden,禁止访问也就是无权限访问,用户没有权限。
-404 Not Found,资源访问路径错误等,服务器不存在该资源。
5xx表明服务端发生了错误
-500 Internal Server Error
-502 Bad Gateway
-504 Gateway Timeout
可参考:https://segmentfault.com/a/1190000018264501
安全
1、CSRF攻击
https://juejin.cn/post/6844903689702866952