web前端 HTML CSS JavaScript Vue Http
HTML语义化、盒模型、浮动、样式优先级、CSS尺寸单位、BFC、Vue双向绑定原理、Vue-Router、Vuex...
HTML语义化
-
html语义化是指在使用html标签构建页面的时候,避免大篇幅的使用无语义的标签,比如span div,尽可能的使用带有语义的标签,比如header footer aside main h1-16等
-
使用语义化标签的好处
(1)结构清晰,易于用户阅读
(2)增加代码的可读性,有利于开发和维护
(3)有利于搜索引擎的SEO优化,提高网站的排名
(4)有利于屏幕阅读器的解析
CSS盒模型
- CSS盒模型定义了盒子的每一个部分,包括margin border padding content
- 根据盒子大小的计算方式不同可以分为标准盒模型和怪异盒模型
- 标准盒模型:设置width和height实际上设置的时content,border padding和width height一起决定了盒子的大小
- 怪异盒模型:设置width和height包含了border和padding,width和height就是盒子的实际大小
- 设置标准盒模型: box-sizing: content-box
- 设置怪异盒模型: box-sizing: border-box
浮动和清除浮动
-
浮动包括左浮动 float:left 右浮动 float:right
-
给图片设置浮动可以实现文字环绕
给块级元素设置浮动可以使其在一行上排列
对行内元素设置浮动,可以对齐进行宽高的设置 -
给元素设置浮动,元素会脱离标准文档流
给元素设置浮动,会改变元素的display属性,改变为display:block
给元素设置浮动,如果父元素没有设置宽高,会造成父元素的高度塌陷,影响父元素后面的兄弟元素的布局 -
清除浮动的方法:
(1) 伪元素清除浮动
(2) 双伪元素清除浮动
(3) 给父元素添加overflow:hidden
(4) 标签插入法:给父元素的末尾添加一个块级元素,并设置样式clear:both
/* 1. 伪元素清除浮动 */
.clearfix::after{
display: block;
content: '';
height: 0;
clear: both;
}
.clearfix{
*zoom:1;
}
/* 2. 双伪元素清除浮动 */
.clearfix::before, .clearfix::after{
display: table;
content: '';
}
.clearfix::after{
clear:both;
}
.clearfix{
*zoom:1;
}
CSS样式优先级的规则是什么
-
CSS的样式优先级是根据权重来计算的,高位权重的优先级永远大于低位权重的优先级,低位权重无法通过叠加来超过高位权重
-
!important
内联样式
嵌入样式和外链样式
继承样式
浏览器默认样式 -
权重:
!important 10000
内联样式 1000
id选择器 100
类选择器 伪类选择器 属性选择器 10
元素选择器 伪元素选择器 1
子选择器 相邻选择器 通配符选择器 0
CSS尺寸设置的单位
-
CSS尺寸单位有 px em rem vw vh
-
px:绝对长度单位,大小取决于屏幕分辨率
em:相对长度单位,在font-size中使用,相对于父元素的字体大小,在其他属性中使用,取决于父元素的字体大小,由于字体大小可继承,可以逐级向上查找,如果最终找不到,则使用浏览器默认字体大小
rem:相对长度单位,相对于html根元素的字体大小,如果根元素没有设置字体大小,则相对于浏览器默认字体大小
vw:相对长度单位,大小为视窗宽度的1%
vh:相对长度单位,大小为视窗高度的1% -
页面响应式的实现方式有:
rem配合媒体查询或flexible.js
rem配合vw -
rem配合配体查询或者flexible.js的原理:通过媒体查询或flexible.js,当屏幕尺寸发生改变时,重置html根元素的字体大小,页面中的元素都使用rem为单位,当根元素字体大小改变时,其他元素的尺寸也随之改变
-
rem配合vw的原理:使用vw设置根元素的html字体大小,当窗口大小发生改变时,vw代表的尺寸也随之改变,无需使用媒体查询或flexible.js,页面中的其他元素仍使用rem为单位,就可以实现响应式
BFC
-
BFC是什么
BFC是 Block Formatting Context的缩写,意思是块级格式化上下文 -
BFC有哪些特性
(1)BFC是一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素
(2)属于同一个BFC的两个相邻的盒子的margin会发生重叠
(3)BFC区域不会与float-box区域重叠
(4)计算BFC的高度时,浮动元素也参与计算 -
BFC形成的条件
(1)float: left
(2)float: right
(3)position: absolute
(4)position: fixed
(5)overflow: auto
(6)overflow: scroll
(7)overflow: hidden
(8)overflow: flex
(9)display: inline-bolock -
BFC能做什么
(1)清除浮动
(2)解决外边距塌陷的问题
(3)实现自适应两列布局 -
BFC的方式都可以清除浮动,但是常用的只有 overflow-hidden
未知宽高元素水平垂直居中的方法
- 绝对定位 + transform
.parent{
position: relative;
}
.son{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
- table-cell
.parent{
display: table-cell;
vertical-align: middle;
text-align: center;
}
.son{
display: inline-block;
}
- flex布局
.parent{
display: flex;
justify-conent: center;
align-items: center;
}
- grid布局
.parent{
display: grid;
justify-content: center;
align-items: center;
}
三栏布局的实现方案
三栏布局简述
- 三栏布局要求左右定宽,中间宽度自适应,所有盒子的高度随内容撑开
- 一般中间盒子的内容较多,为了页面渲染速度快,中间盒子放在左右盒子的前面
实现三栏布局的实现方案
- 圣杯布局
- 双飞翼布局
圣杯布局的实现方案
- 三个盒子放在同一个父级元素中
- 中间盒子放在左右盒子的前面
- 父级盒子设置左右padding
- 三个盒子全部浮动
- 中间盒子宽度100%
- 左右盒子定宽
- 左边盒子设置margin-left:-100%
- 右边盒子设置margin-right:负的自身宽度
- 父级盒子清除浮动
<html>
<head>
<style>
.header{
height: 100px;
background-color: pink;
}
.footer{
height: 100px;
background-color: green;
clear:both;
}
.container{
height: 200px;
padding-left: 200px;
padding-right: 150px;
}
.container .column{
float: left;
height: 200px;
}
.center{
background-color: red;
width: 100%;
}
.left{
background-color: yellow;
width:200px;
margin-left:-100%;
position: relative;
right:200px;
}
.right{
background-color: blue;
width: 150px;
margin-right: -150px;
}
</style>
</head>
<body>
<div class="header">
</div>
<div class="container">
<div class="center column">
</div>
<div class="left column"></div>
<div class="right column"></div>
</div>
<div class="footer"></div>
<div class="xxx1"></div>
<div class="xxx2"></div>
</body>
</html>
双飞翼布局实现方案
- 三个盒子放在同一个父元素中
- 中间盒子放在左右盒子的前面
- 中间盒子套了两层,中间盒子的内部盒子设置左右margin
- 三个盒子全部浮动
- 中间盒子宽度100%
- 左右盒子定宽
- 左边盒子设置margin-left:-100%
- 右边盒子设置margin-left:负的自身宽度
- 父级盒子清除浮动
<html>
<head>
<style>
.header,.footer{
height: 200px;
width: 100%;
background-color: #0000FF;
}
.content,.left,.right{
float: left;
height: 200px;
}
.content{
width: 100%;
background-color :red;
}
.left{
width: 300px;
background-color: pink;
margin-left:-100%;
}
.right{
width:300px;
background-color: grey;
margin-left: -300px;
}
.center{
height:200px;
margin-left: 300px;
margin-right: 300px;
background-color: green;
}
.container::after{
display: block;
content: '';
height: 0;
clear: both;
}
</style>
</head>
<body>
<div class="header">头部</div>
<div class="container">
<div class="content">
<div class="center">中间</div>
</div>
<div class="left">左边</div>
<div class="right">右边</div>
</div>
<div class="footer">尾部</div>
</body>
</html>
优缺点
- 圣杯布局:优点:比双飞翼布局少了一层dom节点 缺点:当中间部分的宽度小于左边部分的宽度时时就会发生布局混乱。
- 双飞翼布局:优点:不会像圣杯布局那样变形,缺点:多加了一层dom节点
JS数据类型有哪些,区别是什么
JS数据类型一共有8种,分为基本数据类型和引用数据类型
其中基本数据类型有
- Number
- String
- Boolean
- Null
- Undefined
- Symbol
- BigInt
引用数据类型有
- Object:普通对象 数组 正则 日期 Math数学函数都属于Object
它们的区别是
- 基本数据类型和引用数据类型在内存中的存储方式不同
- 基本数据类型是直接存储在栈中的简单数据段,占用空间小
- 引用数据类型是存储在堆内存中,占用空间大
- 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址
- 当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体
加分回答:
Symbol是ES6新出的一种数据类型,这种数据类型的特点是没有重复的数据,可以作为Object的key
Biglnt也是ES6新出的一种数据类型,特点是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题
null和undefined的区别,如何让一个属性变为null
undefined
- undefined是全局对象的一个属性,表示变量的初始状态
- 当一个变量没有被赋值、一个函数没有返回值、访问了不存在的对象属性或者函数定义了形参却没有传递实参,这时候都是undefined
- undefined通过typeof判断类型为undefined
null
- null表示对象的值未设置,相当于对象没有设置指针
- 要让一个对象的属性变为null,直接赋值为null就可以了
- 要释放一个对象,也是直接赋值为null就可以了
- null通过typeof判断类型为object
比较
- null == undefined
- null !== undefined
加分回答
- null的类型为null,而不是object类型,typeof之所以会判定为object类型,是因为JavaScript数据类型在底层都是以二进制的形式表示的,前三位为0就会被判定为object类型,而null的二进制位恰好都是0,所以就被误判断为object类型
- 当一个对象被赋值为null,对象在堆内存中的值就处于游离状态,在适当的时机会被回收释放,因此要释放一个对象,直接赋值为null就可以了
JavaScript有几种方法判断变量的类型
- typeof
- instanceof
- constructor
- Object.prototype.toString.call()
typeof
- 常用于判断基本数据类型
- 对于引用数据类型除了function返回function,其余全部返回object
instanceof:
- 主要用于区分引用数据类型
- 检测方法是检测的类型如果在当前实例的原型链上,用其检测出来的结果就是true,
- 不太适合用于基本数据类型的检测
constructor:
- 检测方法是获取当前实例的构造函数,
- 然后判断和某个类是否相同
Object.prototype.toString.call()
- 适用于所有类型的判断检测,
- 返回的是该数据类型的字符串
数组去重有哪些方法
利用对象的key给数组去重,原理是对象的key不能重复
- 首先定义一个空的对象
- 然后使用filter方法对数组进行过滤
- 在回调函数中使用hasOwnProperty方法来判断对象是否存在该属性,入参是当前遍历的元素
- 如果存在则返回false
- 如果不存在,就把当前遍历元素作为对象的key,设置一个值,并返回true
function unique(arr) {
let obj = {}
return arr.filter((item, index, arr) => {
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
利用Set构造函数给数组去重,原理是Set类型的数据没有重复值
- 首先new一个Set对象,参数为需要去重的数组
- Set会自动删除重复的元素
- 然后将Set转为数组返回
function unique(arr) {
return Array.from(new Set(arr))
}
通过filter+indexOf去重,原理是indexOf方法会返回被查找元素首次出现的位置
- 使用filter方法对数组进行过滤
- 在回调函数中使用indexOf方法查找当前遍历元素的下标
- 然后和当前遍历的index做比较
- 如果相等则返回true,否则返回false
function unique(arr) {
return arr.filter((item,index,arr) => {
return arr.indexOf(item) === index
})
}
利用双重循环去重
- for循环嵌套for循环
- 将外层循环的元素和内层循环的元素进行比较
- 如果值相同,则删除后面的那个元素
function unique(arr) {
for(let i=0; i<arr.length; i++) {
for (let j=i+1; j<arr.length; j++) {
if(arr[i] === arr[j]) {
arr.splice(j,1);
j--;
}
}
}
return arr
}
通过reduce+includes给数组去重
- 使用reduce方法对数组元素进行迭代
- 传入一个空数组作为去重后的新数组
- 在回调函数中通过includes方法判断新数组中是否存在当前遍历的元素
- 如果不存在就插入到新的数组中
function unique(arr) {
return arr.reduce((pre, cur)=>{
return pre.includes(cur) ? pre : [...pre, cur]
},[])
}
伪数组和数组的区别
- 伪数组的类型是Object,数组的类型是Array
- 伪数组可以使用length属性查看长度
- 也可以使用[index]获取某个属性
- 但是不可以使用数组的其他方法,比如push forEach等,也不能改变长度
- 遍历使用for in 方法
伪数组的常见场景
- 函数的arguments
- 原生js获取dom: document.querySelector(‘div’)
- juqery获取dom:$(‘div’)
伪数组转为真数组的方法:
- Arry.prototype.slice.call(伪数组)
- [].slice.call(伪数组)
- Array.from(伪数组)
转换后的数组长度由length属性决定
索引不连续时转换结果是连续的,会自动补位
Vue2.0双向绑定原理与缺陷
Object.defineProperty(object, propName, descript)
Object.defineProperty(object, propName, {
get: function() {
},
set: function(newVal) {
}
})
-
Vue双向绑定指的是组件的data发生改变,会立刻触发视图的更新
-
原理:Vue采用数据劫持结合订阅者-发布者模式的方式实现数据的响应式,通过Object.defineProperty来劫持数据的getter和setter,当数据发生改变时,发送消息给订阅者,订阅者接收到消息之后进行相应的处理。通过原生JS提供的监听数据的API,在回调函数中修改dom
-
核心API: Object.defineProperty
Object.defineProperty用来定义对象的属性
获取属性的时候会触发getter函数,修改属性的时候会触发setter函数,在setter函数中调用修改dom的方法 -
Object.defineProperty的缺点
(1)一次性递归到底开销很大,当数据很大时,大量的递归会导致调用栈溢出
(2)无法监听对象属性的添加和删除
(3)无法监听数组下标的数据变化
讲一下vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
num: 0
},
getters: {
},
mutations: {
UPDATENUM(state, payload) {
state.num = payload
}
},
actions: {
},
modules: {
}
})
// 获取
this.$store.state.num
// 设置
this.$store.commit('UPDATENUM', 0)
vue的data为什么必须使用函数
结论
因为对象是引用数据类型,如果你写成对象,这个组件在多处被引用,只要修改一处的值,那么另一处的引用的值也会变化,这样就乱套了。
而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。
举例
对象方式:
var data = {
x: 1
}
var vm1 = {
data: data
}
var vm2 = {
data: data
}
vm1.data === vm2.data // => true,指向同一个对象
函数方式:
var func = function () {
return {
x: 1
}
}
var vm3 = {
data: func
}
var vm4 = {
data: func
}
vm3.data() === vm4.data() // => false,指向不同对象
函数中data都指向同一个函数,但这个函数每次的返回值都是一个新的对象
{x:1} === {x:1} // => false
new Object({x:1}) === new Object({x:1}) // false
Vue组件生命周期
<template>
<div>
</div>
</template>
<script>
export default {
data() {
return {
}
},
beforeCreate() {
},
created() {
},
beforeMount() {
},
mounted() {
},
beforeUpdate() {
},
updated() {
},
activated() {
},
deactivated() {
},
beforeDestroy() {
},
destroyed() {
},
errorCaptured() {
}
}
</script>
vue组件之间有哪些传值 方式
props和 e m i t 实现父子组件传值, emit实现父子组件传值, emit实现父子组件传值,parent和 c h i l d r e n 获取父组件和子组件 , children获取父组件和子组件, children获取父组件和子组件,refs获取实例组件, e m i t / emit/ emit/on事件总线,vuex状态管理器。
你是如何封装组件的,封装过哪些组件?
vue router的原理
vue router的原理是更新视图但不重新请求页面,主要有两种方式hash模式和history模式。
hash模式和history模式直观的区别是hash模式带#,history模式不带#号
另外,hash模式的hash值虽然在url中,但不会被包括在http请求中,对后端完全没有影响,所以改变hash不会重新加载页面。
history模式则是利用了HTML5 history interface中新增的pushState()和replaceState()方法。history模式下,前端的URL必须和实际向后端发起请求的URL一致,比如http:www.xxx.com/user/id,如果后端缺少对/user/id的路由处理,将返回404错误,所以需要在服务端增加一个覆盖所有情况的候选资源。
vue router有哪些钩子
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) { // 组件内守卫
},
beforeRouteUpdate(to, from, next) { // 组件内守卫
},
beforeRouteLeave(to, from, next) { // 组件内守卫
}
}
export default new Router({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter(to, from, next) { // 路由独享守卫
}
}
],
beforeEach(to, from, next) { // 全局导航守卫
},
beforeResolve(to, from, next) { // 全局导航守卫
},
afterEach(to, from) { // 全局导航守卫
}
})
Vue router路由有几种模式?History模式导致页面请求404如何解决?
前端性能优化
- 图片压缩和文件压缩
- 雪碧图/精灵图
- 节流防抖
- HTTP缓存
- 本地缓存
- keep-alive缓存
- 服务端渲染
- 懒加载
- 对dom查询进行缓存
- 将dom操作合并
vue的性能优化
vue性能优化可以从两方面进行优化,第一就是源码优化,第二就是打包优化。源码优化可以从提高组件的复用性,给for循环设置key值(可以更快的定位到diff),给路由设置懒加载,使用keep-alive对组件进行缓存几个方面进行优化,打包优化可以修改vue.config.js的配置项,把productionSourceMap设置成 false,使用cdn的方式加载一些外部资源,用css3的效果来代替 图片,按需引入几个方面来进行优化。
vue的一些webpack配置
vue3.0的新特性
压缩体积更小,使用es6的proxy代替defineProperty,Virtual DOM重构(虚拟DOM重构),编译时优化(Slot插槽默认编译为函数),更好的支持TypeScript。
从输入rul到浏览器显示页面发生了什么?
Vue项目的权限配置时如何配置的?
v-for为什么要使用key?讲一下deff算法
Vue computed和watch的区别?
闭包和作用域链
变量有两种:全局变量和局部变量。
函数内部可以直接读取全局变量,在函数外部无法读取函数内部的局部变量。
那么如何从外部读取函数内部的变量呢?正常情况下这是办不到的,只有通过变通的方法才能实现:那就是在函数内部再定义一个函数
function f1 () {
var n = 999;
function f2 () {
alert(n); // ==> 999
}
}
在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1是不可见的。这就是Javascript语言特有的“链式作用域”
结构(chain scope),子对象会一级一级的向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的反之则不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!
function f1 () {
var n = 999;
function f2 () {
alert (n);
}
return f2;
}
var result = f1();
result(); // 999
闭包的概念
上一节代码中的f2函数,就是闭包。
简单的理解:闭包就是能够读取其他函数内部变量的函数,由于在JavaScript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单的理解成“定义在一个函数内部的函数”。
闭包和作用域链详解
Javascript原型链
原型:
①所有 引用类型 都有一个 __proto__(隐式原型)属性,属性值是一个普通的对象
②所有 函数 都有一个 prototype(原型)属性,属性值是一个普通的对象
③所有 引用类型的 __proto__ 属性 指向 它的 构造函数的prototype
原型链:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的 __proto__隐式原型上查找,即它的构造函数的 prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
js事件循环
vue重复赋值一个变量,页面渲染几次
浏览器无痕模式(京东)
如何通过CSS制作一个箭头(京东)
真人试穿实现思路(京东)
直播实现思路(京东)
你在做项目的过程中遇到过什么难解决的问题,你是如何解决的?(京东)+ 其他面试也经常问到
更多推荐
所有评论(0)