赞
踩
localStorage.clear()
bool string number obj undefined null
1.var声明变量存在变量提升,let和const不存在变量提升
(在JavaScript中,在方法体外外用var定义的变量其它方法可以共享,在方法中用var定义的变量只有该方法内生效。)
2.let、const都是块级局部变量
(const 的特性和 let 完全一样,不同的只是声明时候const必须赋值,只能进行一次赋值,即声明后不能再修改)
(1)null是一个表示”无”的对象,转数值是为0,undefined是一个表示”无”的原始值,转为数值时为NaN。当声明的变量还未被初始化时,能量的默认值为undefined
(2)Null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象
(3)Undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。典型用法是:
a、变量被声明了,但没有赋值时,就等于undefined
b、调用函数时,应该提供的参数没有提供,该参数等于undefined
c、对象没有赋值属性,该属性的值为undefined
d、函数没有返回值时,默认返回undefined
(4)null表示”没有对象”,即该处不应该有值。典型用法是:
a、作为函数的参数,表示该函数的参数不是对象
b、作为对象原型链的终点
1.使用三点运算符…
eg:let new_obj = { …obj1, …obj2 };
特点:如果对象有相同的属性,后面的覆盖前面的
2.使用Object.assign()
eg:let ret1 = Object.assign({}, obj1, obj2);
特点:如果对象有相同的属性,后面的覆盖前面的
第一个参数会被改变
concat()连接两个或更多的数组,并返回结果。
join()把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
shift()删除并返回数组的第一个元素
pop()删除并返回数组的最后一个元素
unshift()向数组的开头添加一个或更多元素,并返回新的长度。
push()向数组的末尾添加一个或更多元素,并返回新的长度。
splice()删除元素,并向数组添加新元素。
slice()从某个已有的数组返回选定的元素
reverse()颠倒数组中元素的顺序。
sort()对数组的元素进行排序
toSource()返回该对象的源代码
toString()把数组转换为字符串,并返回结果。
toLocaleString()把数组转换为本地数组,并返回结果。
valueOf()返回数组对象的原始值。
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了
一般基本类型不会产生深浅拷贝问题,因为是直接拷贝数据。但是因为引用类型的实际值存储在堆中,而引用地址存储在栈中,所以在进行复制操作时,会产生此问题。
最简单的浅拷贝
var arr1 = new Array(12,23,34)
Var arr2 = arr1;
当进行 arr2[0] = 1;的操作时,arr1[0]的值也进行了改变为1;
深拷贝一般使用循环数组或者对象的方式解决,如果对象的属性都是基本类型,那么直接进行循环即可,如果存在引用类型,则在判断出类型为obj时先new一个空值,再复制
var p2 = {};
for(let key in p){
if(typeof p[key]=='object'){
p2[key]=[];//因为,我上面写的是数组,所以,暂时赋值一个空数组.
for(let i in p[key]){
p2[key][i] = p[key][i]
}
}else{
p2[key] = p[key];
}
}
p2.books[0] ="四国";
console.log(p2);
console.log(p);
如果对象的属性都是json对象,则要用到递归
var p = { "id":"007", "name":"刘德华", "wife":{ "id":"008", "name":"刘德的妻子", "address":{ "city":"北京", "area":"海淀区" } } } //写函数 function copyObj(obj){ let newObj={}; for(let key in obj){ if(typeof obj[key] =='object'){//如:key是wife,引用类型,那就递归 newObj[key] = copyObj(obj[key]) }else{//基本类型,直接赋值 newObj[key] = obj[key]; } } return newObj; } let pNew = copyObj(p); pNew.wife.name="张三疯"; pNew.wife.address.city = "香港"; console.log(pNew); console.log(p);
如果深拷贝_属性是数组等非键值对的对象
就得单独处理:要么给数组增加一个自我复制的函数(建议这样做),要么单独判断。
//给数组对象增加一个方法,用来复制自己 Array.prototype.copyself = function(){ let arr = new Array(); for(let i in this){ arr[i] = this[i] } return arr; } var p = { "id":"007", "name":"刘德华", "books":new Array("三国演义","红楼梦","水浒传")//这是引用类型 } function copyObj(obj){ let newObj={}; for(let key in obj){ if(typeof obj[key] =='object'){//如:key是wife,引用类型,那就递归 newObj[key] = obj[key].copyself(); }else{//基本类型,直接赋值 newObj[key] = obj[key]; } } return newObj; } var pNew = copyObj(p); pNew.books[0] = "四国"; console.log(pNew); console.log(p);
用途
cookie 存token 判断是否登录
localStorage 存储购物车数据 或者 H5游戏的一些本地数据
js实现 :img标签只有在src有有效值的时候才会发起请求。所以先将src写为一个占位图的路径,再给src设置一个data-src属性为真实图片路径,当document.body.scrollTop(被卷进去的高度)刚好为HTMLElement.offsetTop(标签离顶部的距离)把data-src赋值给src;
vue可以使用:vue-lazyload插件
1.解构赋值可以用于交换变量的值
let x = 1,y =2;
[x,y] = [y,x];
x//2
y//1
2.从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将他们放在数组或者对象返回,利用解构赋值,取出这些值就非常方便
function example () {
return [1,2,3];
}
let [a,b,c] = example();
function example() {
return {name:"MGT360124",age:18}
}
let {name,age} =example();
扩展运算符
对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }
上述方法实际上等价于:
let bar = { a: 1, b: 2 };
let baz = Object.assign({}, bar); // { a: 1, b: 2 }
promise
查看此处
promise的出现主要是为了避免页面冻结.
三个状态
pending 待定 初始状态
fulfilled 实现 操作成功
rejected 被否决 操作失败
rem 是当前HTML根元素的font-size
em 会继承父级元素的字体大小
1.static
静态定位的元素不受 top、bottom、left 和 right 属性的影响。
position: static; 的元素不会以任何特殊方式定位;它始终根据页面的正常流进行定位
2.relative
设置相对定位的元素的 top、right、bottom 和 left 属性将导致其偏离其正常位置进行调整。不会对其余内容进行调整来适应元素留下的任何空间。
3.fixed;
元素是相对于视口定位的,这意味着即使滚动页面,它也始终位于同一位置。 top、right、bottom 和 left 属性用于定位此元素。
4.absolute;
position: absolute; 的元素相对于最近的定位祖先元素进行定位。
然而,如果绝对定位的元素没有祖先,它将使用文档主体(body),并随页面滚动一起移动。
注意:“被定位的”元素是其位置除 static 以外的任何元素。
5.position: sticky;
元素根据用户的滚动位置进行定位。
粘性元素根据滚动位置在相对(relative)和固定(fixed)之间切换。起先它会被相对定位,直到在视口中遇到给定的偏移位置为止 - 然后将其“粘贴”在适当的位置(比如 position:fixed)
1.弹性布局
display: flex;
align-items: center;//侧轴居中(默认是纵轴)
justify-content: center;//主轴居中
2.绝对定位+transform: translate(x, y);
3.text-align + line-height实现单行文本水平垂直居中
4.text-align + vertical-align
在父元素设置text-align和vertical-align,并将父元素设置为table-cell元素,子元素设置为inline-block元素
对于需要四边0.5像素边框,可以用以下方式:
方式:定位 + 伪元素 + transfrom缩放(scale); 字体小于12的需求 也可以计算出与12的比例进行缩放 <div class="border">0.5像素边框~~~~</div> <style> .border { width: 200px; height: 200px; margin: 0 auto; position: relative; } .border::before { content: " "; position: absolute; top: 0; left: 0; width: 200%; height: 200%; border: 1px solid red; transform-origin: 0 0; transform: scale(0.5); } </style>
首先我们为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;
然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会;
接着为input会添加监听事件,修改值就等于为该属性赋值,则会触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。(转自此处)
vue 的生命周期是: vue 实例从创建到销毁,也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程。
1.点击验证动画效果
2.this.$router.push({ path:’/user’})
this.$router.push({ //核心语句
path:'/select', //跳转的路径
query:{ //路由传参时push和query搭配使用 ,作用时传递参数
id:this.id ,
},
params: {
id: id
}
})
query拼接在路径后面,刷新不会丢失
1.简单粗暴的方式
this.
f
o
r
c
e
U
p
d
a
t
e
(
)
;
/
/
强制更新
2.
增减元素
s
p
l
i
c
e
(
)
p
u
s
h
(
)
3.
通过
forceUpdate();//强制更新 2.增减元素 splice() push() 3.通过
forceUpdate();//强制更新2.增减元素splice()push()3.通过set进行更新
this.$set(v, ‘edit’, false)
4.异步dom更新
Vue.nextTick()
.then(function () {
// DOM 更新了
})
1.父传子
子组件用props接收
2.子传父
子组件通过事件向父组件传值
先在父组件里面写一个人 fuc1 用@fuc1=fuc1传进子组件,子组件调用this.$emit(‘fuc1’, this.message); this.message就是从子组件里面传递出来的参数
3.组件之间的传值
vue中vuex的五个属性和基本用法
VueX 是一个专门为 Vue.js 应用设计的状态管理构架,统一管理和维护各个vue组件的可变化状态(你可以理解成 vue 组件里的某些 data )。
Vuex有五个核心概念:
state, getters, mutations, actions, modules。
1. state:vuex的基本数据,用来存储变量
2. geeter:从基本数据(state)派生的数据,相当于state的计算属性
3. mutation:提交更新数据的方法,必须是同步的(如果需要异步使用action)。每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。
4. action:和mutation的功能大致相同,不同之处在于 ==》1. Action 提交的是 mutation,而不是直接变更状态。 2. Action 可以包含任意异步操作。
5. modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
onst user = { state:{ self: null, token: '', }, mutations:{ SET_SELF: (state, self) => { state.self = self }, SET_TOKEN: (state, token) => { state.token = token } }, actions:{ login ({ commit }, res) { commit('SET_SELF', res.self) commit('SET_TOKEN', res.token } } export default user dispatch:异步操作,写法: this.$store.dispatch('mutations方法名',值) commit:同步操作,写法:this.$store.commit('mutations方法名',值)
通俗来讲,既能用computed 实现又可以用 watch 监听来实现的功能,推荐用 computed,重点在于 computed 的缓存功能
computed计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量改变时,计算属性也会跟着改变;
watch 监听的是已经在 data 中定义的变量,当该变量变化时,会触发 watch 中的方法
解决办法:
1.修改为全局样式 //去掉scoped
2、全局及组件作用于CSS混用
<style scoped>
...
</style>
<style>
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
</style>
3、深度修改样式
<style scoped>
//方法一
/deep/ .el-table .warning-row {
background: oldlace;
}
//方法二,page_bar为外层类名,是否为直接父级均可
.page_bar >>> .el-table .warning-row {
background: oldlace;
}
</style>
路由钩子主要作用是拦截导航,让他完成跳转或者取消跳转。比如登录界面输入了账号、密码,主界面需要展示账号,但是你没有把 “账号” 这个字段保存到 vuex 或者 session 里面,直接跳转会导致主界面显示空白,这个时候你就需要一个 beforeRouteLeave 路由钩子,还没有数据的情况下,禁止界面跳转,举例子(伪代码):
beforeRouteLeave(to,from,next){
if('account' === ' '){
next(false);
}else{
next();
};
};
//参数 to ——是要跳转到的界面
//from —— 从哪个界面离开
//next() —— 是否允许跳转
1.如果是 next(false) ——禁止跳转
2.next({name:LOGIN}) —— 跳转到登录界面(需要自己手动配置路由)
3.next() 或者 next(true) ——允许跳转
路由钩子的实现方式有三种
1.全局实现 beforeEach
var routes = [{
path:'/route1',
name:'route1',
component:() = > import('./index.vue') //调用的时候再开始加载
}]
const router = new VueRouter({
routes;
})
router.beforeEach((to, from, next) => {
next(false);
})
2.路由独享 配置路由的时候可以直接增加beforeEnter
var routes = [{
path:'/route1',
name:'route1',
component:() = > import('./index.vue') //调用的时候再开始加载
beforeEnter: (to, from, next) => {
next();
}
}]
3.组件内实现的钩子
beforeRouteEnter:在导航确认之前调用,新组件的 beforeCreate 之前调用,所以特别注意它的 this 是 undefined
beforeRouteUpdate:点击更新二级导航时调用。
beforeRouteLeave:离开当前界面之前调用,用法:1. 需要的保存或者删除的数据没有完成当前操作等等原因,禁止界面跳转。
引自这里
1.router-link(声明式路由)
1. 不带参数
<router-link :to="{name:'home'}">
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name
// 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
2.带参数
<router-link :to="{name:'home', params: {id:1}}">
// params传参数 (类似post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id"
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
<router-link :to="{name:'home', query: {id:1}}">
2.router.push(编程式路由)
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
3.this.$router.push()(函数里面调用)
1. 不带参数 this.$router.push('/home') this.$router.push({name:'home'}) this.$router.push({path:'/home'}) 2. query传参 this.$router.push({name:'home',query: {id:'1'}}) this.$router.push({path:'/home',query: {id:'1'}}) // html 取参 $route.query.id // script 取参 this.$route.query.id 3. params传参 this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name // 路由配置 path: "/home/:id" 或者 path: "/home:id" , // 不配置path ,第一次可请求,刷新页面id会消失 // 配置path,刷新页面id会保留 // html 取参 $route.params.id // script 取参 this.$route.params.id 4. query和params区别 query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在 params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
4.replace()(用法同上,push)
5.go(n)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
ps : 区别
this.$router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
————————————————
注意:获取路由上面的参数,用的是$route,后面没有r
params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
params一旦设置在路由,params就是路由的一部分,如果这个路由有params传参,但是在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。
params、query不设置也可以传参,但是params不设置的时候,刷新页面或者返回参数会丢失,
两者都可以传递参数,区别是什么?
query 传参配置的是path,而params传参配置的是name,在params中配置path无效
query在路由配置不需要设置参数,而params必须设置
query传递的参数会显示在地址栏中
params传参刷新会无效,但是query会保存传递过来的值,刷新不变
1、全局安装vue-cli
npm install --global vue-cli
2、进入你的项目目录,创建一个基于 webpack 模板的新项目: vue init webpack 项目名
进入项目:cd vue-demo,安装依赖
摘抄: 点击跳转
1.props / emit
2.emit / on
Var Event=new Vue();//定义一个空的Vue实例
Event.$emit(事件名,数据); 调用自定义事件
Event.$on(事件名,data => {})//mounted里面写监听自定义事件
3.vuex
4.attrs / listeners
attrs表示没有继承数据的对象,格式为{属性名:属性值}。Vue2.4提供了 attrs , listeners 来传递数据与事件,跨级组件之间的通讯变得更简单。
简单来说: attrs与 listeners 是两个对象, attrs 里存放的是父组件中绑定的非 Props 属性, listeners里存放的是父组件中绑定的非原生事件
5.provide/inject
Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
6.parent / children ref
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
parent / children:访问父 / 子实例
总结
常见使用场景可以分为三类:
父子通信: 父向子传递数据是通过 props,子向父是通过 events( emit);通过父链 / 子链也可以通信( parent / children);ref 也可以访问组件实例;provide / inject API; attrs/listeners
兄弟通信: Bus;Vuex
跨级通信: Bus;Vuex;provide / inject API、 attrs/listeners
1.webpack打包原理
把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。
2.webpack 和 gulp 的区别?
webpack是一个模块打包器,强调的是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源都看成是模块,通过loader和plugin对资源进行处理。
gulp是一个前端自动化构建工具,强调的是前端开发的工作流程,可以通过配置一系列的task,第一task处理的事情(如代码压缩,合并,编译以及浏览器实时更新等)。然后定义这些执行顺序,来让glup执行这些task,从而构建项目的整个开发流程。自动化构建工具并不能把所有的模块打包到一起,也不能构建不同模块之间的依赖关系。
微信小程序 调用 wx.saveImageToPhotosAlbum
h5 生成一个a标签
url 本地 全局App对象
小程序官方API
开发者通过在 app.json subpackages 字段声明项目分包结构
小程序分包详解,以及优劣
1.什么是闭包
闭包是指有权访问另外一个函数作用域中的变量的函数.可以理解为(能够读取其他函数内部变量的函数)
2. 闭包的作用
正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉
1.密闭的容器,存储数据的
2.闭包是一个对象,存放数据
3.内部函数引用外部函数的局部变量
4.闭包优缺点:
优点:延长外部函数局部变量生命周期
缺点:长时间占用容易内存泄露
在上面优缺点中写道能延长外部函数局部变量的声明周期,但是长时间占用内存;当闭包不在使用时记得及时释放。
这些模式是依次进化而形成MVC/MVP—>MVVM。在以前传统的开发模式当中即MVC模式,前端人员只负责Model(数据库) View(视图) Controller /Presenter/ViewModel(控制器) 当中的View(视图)部分,写好页面交由后端创建渲染模板并提供数据,随着MVVM模式的出现前端已经可以自己写业务逻辑以及渲染模板,后端只负责提供数据即可,前端所能做的事情越来越多.
canvas
(一)块级元素
div、p、h1-h6、form、ul、ol、dl、dt、dd、li、table、tr、td、th、hr、blockquote、address、table、menu、pre
性质:块级元素独占一行,当没有设置宽高时,它默认设置为100%(其宽度自动填满其父元素宽度)
块级元素允许设置宽高,width、height、margin、padding、border都可控制
注:块级元素设置了width宽度属性后仍然独占一行,块级元素可以包行内元素、块级元素
(二)行内元素(内联函数)及行内块元素
(1)span、img、a、label、code、input、abbr、em、b、big、cite、i、q、textarea、select、small、sub、sup,strong、u
button(display:inline-block)
HTML5:header、section、article、footer等
性质:
1.行内元素不能独占一行,与其他行内元素排成一行,其宽度随元素的内容变化而变化
2.行内元素不能设置width、height、margin、padding
3.行内元素默认宽度为其content宽度
4.行内元素只能包括文字或行内元素、行内块元素,不能包括块级元素
display:inline-block:行内块元素与行内元素属性基本相同即不能独占一行,但是可以设置width及height
5.行内元素的水平方向的padding-left和padding-right都会产生边距效果,但是竖直方向上的padding-top和padding-bottom都不会产生边距效果
(2)有一些特别的行内元素可设置宽高
替换元素:< img>、< input>、< textarea>、< select>、< object>
这些元素与其他行内元素不同的是,它有内在尺寸。因为它像是一个框,比如img元素,它能显示出图片是由于src的值,在审查元素时就不能直接看到图片,而input是输入框或是复选框也是因为其type的不同。
这种需要通过属性值显示的元素,其本身是一个空元素,像一个空的框架。
- <header>:头部标签
- <nav>:导航标签
- <article>:内容标签
- <section>:块级标签
- <aside>:侧边栏标签
- <footer>:尾部标签
可以使用
<template> <div> <p>{{ $t('greeting') }}</p > <p>{{ $t('message', { name: 'John' }) }}</p > </div> </template> <script> export default { data() { return { greeting: 'Hello', message: 'Welcome, {name}!', }; }, }; </script> <!-- 在 i18n 文件中定义国际化文本 --> <i18n> { "en": { "greeting": "Hello", "message": "Welcome, {name}!" }, "zh-CN": { "greeting": "你好", "message": "欢迎,{name}!" } } </i18n>
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。
重排:当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
浏览器解析渲染机制如下:
①.解析HTML,生成DOM树,解析CSS,生成CSSOM树
②.将DOM树和CSSOM树结合,生成渲染树(Render Tree)
③.Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
④.Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
⑤.Display:将像素发送给GPU,展示在页面上
在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变。
当我们对 DOM 的修改引发了 DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来。
常见的引起重绘的属性
color border-style visibility background text-decoration
background-image background-position background-repeat outline-color outline
outline-style border-radius box-shadow background-size outline-width
常见引起重排属性和方法
width height margin padding display
border-width border position overflow font-size
vertical-align min-height clientWidth clientHeight clientTop
clientLeft scrollWidth scrollHeight scrollTop
scrollLeft getComputedStyle() getBoundingClientRect() scrollIntoViewIfNeeded() 伪类:如:hover
什么情况下会触发重绘
触发回流时一定会触发重绘,除此之外,例如颜色修改,设置圆角、文本方向修改,阴影修改等。
什么情况下会触发回流
回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流,如下面情况:
①.添加或删除可见的DOM元素
②.元素的位置发生变化
③.元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
④.内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
⑤.页面一开始渲染的时候(这避免不了)
⑥.浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
提示:重绘不一定导致重排,但重排一定会导致重绘。
1.输入网址,浏览器智能匹配URL。
2.浏览器查找域名的IP地址。
3.浏览器向web服务器发送一个HTTP请求。
4.服务器处理请求。
5.服务器返回一个HTTP响应。
6.浏览器跟踪重定向地址。
7.服务器的永久重定向响应。
8.浏览器显示HTML。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。