从浏览器渲染原理,浅谈回流重绘与性能优化

目录
  • 前言
  • 浏览器的渲染引擎
    • 渲染流程
    • 渲染树与渲染对象
  • 回流
    • 全局布局和增量布局
    • "回流"还是"重排"?
  • 重绘
  • 何时触发回流和重绘
  • 渲染性能优化
    • 合并多次布局操作
    • 减少或避免强制同步布局
    • 使用 transformopacity 来实现动画
    • 简化绘制的复杂度、减小绘制区域
    • 让复杂的布局“离线”
    • 其他
  • 参考文献

前言

“回流(重排)”和“重绘”基本上算是前端的高频词之一,你可以在各个文章及面试题中见到,我们在讨论这个词的时候,其实讨论的是浏览器的渲染流程。
所以在讨论“回流重绘”之前,我们还需要掌握一些知识;在它之中,我们还需要更深入一点;在这之后,我们还要懂得怎么去把理论结合到项目实践中去。

通过这篇文章,你可以学习到的知识:
1、追本溯源,“回流”和“重绘”这个词是如何引出的,在了解这两个词之前我们还需要了解什么
2、浏览器的渲染流程,“回流”和“重绘”的原理
3、优化浏览器渲染性能,减少“回流”和“重绘”,动手将这些优化应用到实际开发中

浏览器的渲染引擎

浏览器的主要组件有:用户界面、浏览器引擎、渲染引擎、网络、用户界面后端、JavaScript解释器、数据存储。

浏览器的主要功能就是向服务器发出请求,在浏览器窗口中展示您选择的网络资源。浏览器在解析HTML文档,将网页内容展示到浏览器上的流程,其实就是渲染引擎完成的。

渲染流程

我们在这里讨论Gecko和Webkit这两种渲染引擎,其中Firefox 使用的是 Gecko,这是 Mozilla 公司“自制”的呈现引擎。而 Safari 和 Chrome 浏览器使用的都是 WebKit。

WebKit 渲染引擎的主流程:

Mozilla 的 Gecko渲染引擎的主流程:

从图 3 和图 4 可以看出,虽然 WebKit 和 Gecko 使用的术语略有不同,但整体的渲染流程是基本相同的,这里我们参照Webkit引擎来概况一下:

  1. 解析HTML Source,生成DOM树
  2. 解析CSS,生成CSSOM树
  3. 将DOM树和CSSOM树结合,去除不可见元素,生成渲染树(Render Tree)
  4. Layout(布局):根据生成的渲染树,进行布局(Layout),得到节点的几何信息(位置,大小)
  5. Painting(重绘):根据渲染树以及回流得到的几何信息,将 Render Tree 的每个像素渲染到屏幕上

渲染树与渲染对象

渲染树(render tree)是由可视化元素按照其显示顺序而组成的树,也是文档的可视化表示。它的作用是让您按照正确的顺序绘制内容。

生成渲染树

为了构建渲染树,浏览器主要完成了以下工作:

  1. 从DOM树的根节点开始遍历每个可见节点。
  • 某些节点不会被渲染输出,比如scriptlinkmeta等标签节点
  • 通过css隐藏的节点会被忽略,比如“display: none”。但是注意,visibility: hidden是会被渲染的(渲染成一个空框),因为它仍占据布局空间
  1. 对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。
  2. 根据每个可见节点以及其对应的样式,组合生成渲染树。

渲染对象

Firefox 将渲染树中的元素称为“框架”。WebKit 使用的术语是渲染器(renderer)或渲染对象(render object)。

每一个渲染对象都代表了一个矩形区域,通常对应相关节点的css框,包含宽度、高度和位置等几何信息。框的类型受“display”样式属性影响,根据不同的 display 属性,使用不同的渲染对象(如 RenderInlineRenderBlockRenderListItem 等对象)。

WebKits RenderObject 类是所有渲染对象的基类,其定义如下:

class RenderObject{
  virtual void layout();
  virtual void paint(PaintInfo);
  virtual void rect repaintRect();
  Node* node;  //the DOM node
  RenderStyle* style;  // the computed style
  RenderLayer* containgLayer; //the containing z-index layer}

我们可以看到,每个渲染对象都有 layoutpaint方法,分别对应了回流和重绘的方法。

回流

渲染对象在创建完成并添加到渲染树时,是将DOM节点和它对应的样式结合起来,并不包含位置和大小信息。

我们还需要通过 Layout 布局阶段,来计算它们在设备视口(viewport)内的确切位置和大小,计算这些值的过程称为回流布局重排

HTML 采用基于流的布局模型,从根渲染对象(即<html>)开始,递归遍历部分或所有的框架层次结构,为每一个需要计算的渲染对象计算几何信息,大多数情况下只要一次遍历就能计算出几何信息。但是也有例外,比如<table>的计算就需要不止一次的遍历。

全局布局和增量布局

全局布局指触发了整个render tree范围的布局,一般是同步触发的,触发原因可能包括:

  1. 影响所有渲染元素的全局样式更改,例如字体大小更改。
  2. 屏幕大小调整。

增量布局是指对标记为“dirty”的渲染对象进行布局。它一般是异步执行的,浏览器将增量布局的“reflow 命令”加入队列,而调度程序会触发这些命令的批量执行。

但是请求样式信息(例如offsetHeight,
getBoundingClientRect等)的脚本可同步触发增量布局。

Note: dirty bit
为避免对所有细小更改都进行整体布局,浏览器采用了一种“dirty bit”的系统。如果某个渲染对象发生了更改,或者将自身及其子代标注为“dirty”,则需要进行布局。

"回流"还是"重排"?

本质上它们是同样的流程,只是在不同浏览器引擎下的“说法”有所差异。

  • Gecko 将视觉格式化元素组成的树称为 "Frame tree" 框架树。每个元素都是一个框架;
    对于元素的放置,将其称为 "Reflow" 回流

  • WebKit 使用的术语是 "Render Tree" 渲染树,它由"Render Objects"组成。对于元素的放置,WebKit 使用的术语是 "Layout" 布局(或Relayout重排

重绘

在计算出节点可见性、它们的计算样式以及几何信息后,我们还需要将渲染树中的每个节点,转换成屏幕上的实际像素。这一步通常称为“重绘”。

重绘是填充像素的过程。它涉及绘出文本、颜色、图像、边框和阴影,基本上包括元素的每个可视部分。在重绘阶段,系统会遍历渲染树,并调用渲染对象的“paint”方法,将渲染对象的内容显示在屏幕上。

和布局一样,重绘也分为全局(绘制整个render tree)和增量两种。

绘制顺序

绘制的顺序其实就是元素进入堆栈样式上下文的顺序。这些堆栈会从后往前绘制,因此这样的顺序会影响绘制。块渲染对象的堆栈顺序如下:
1、背景颜色
2、背景图片
3、边框
4、子代
5、轮廓

何时触发回流和重绘

触发回流(reflow):

回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流.

改变这些属性会触发回流:

  • 盒模型相关的属性: widthheightmargindisplayborder
  • 定位属性及浮动相关的属性: top,position,float
  • 改变节点内部文字结构也会触发回流: text-align, overflow, font-size, line-height, vertival-align

以及进行以下流程或操作:

  • 页面一开始渲染的时候
  • 添加或删除可见的DOM元素,进行DOM操作等
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
  • css伪类激活
  • 进行获取布局信息的操作,比如offsetWidthoffsetHeightclientWidthclientHeightwidthheightscrollTopscrollHeight, getComputedStyle, getBoundingClientRect

Note: 具体属性及操作可以访问这个网站:What forces layout / reflow

触发重绘:

重绘是一个元素外观的改变所触发的浏览器行为,例如改变visibilityoutlinebackground-color等属性,这些属性只是影响元素的外观,风格,而不会影响布局的。

浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。

Note: 如果想知道更改任何指定 CSS 属性将触发回流还是重绘,请查看 CSS 触发器

我们根据渲染的流程可知,回流一定会触发重绘,而重绘不一定会回流

渲染性能优化

回流和重绘的代价是比较昂贵的,渲染性能优化,就是要尽可能减少Layout回流和Paint重绘发生的次数,将回流和重绘的影响范围限制在单独的图层之内

合并多次布局操作

我们可以合并多次对DOM和样式的修改,然后一次处理掉,以此来最小化回流和重绘操作,比如:

// bad
const el = document.getElementById('test');
el.style.margin = '5px';
el.style.width = '100px';
el.style.borderRight = '2px';

例子中,有三个样式属性被修改了,每一个都会影响元素的几何结构,引起回流。(当然,大部分现代浏览器都对其做了优化,只会触发一次。但是如果在旧版的浏览器或者在上面代码执行的时候,有其他代码访问了布局信息,那么就会导致三次回流)

我们合并所有的布局操作,然后统一处理,比如这样:

// good
const el = document.getElementById('test');
el.style.cssText += 'margin: 5px;width: 100px;border-right: 2px; '

减少或避免强制同步布局

上面我们提到,访问一些属性(就是offsetWidth那一堆属性)会导致浏览器强制清空队列,进行强制同步布局。实际使用中可以尽量避免,如果不能避免,也应该减少。

比如我们想批量将一些标签的宽度设为某个box的宽度,我们可能会写成下面这样:

// bad
   for (let i = 0; i < elment.length; i++) {
        elment[i].style.width = box.offsetWidth + 'px';
    }

这段代码看上去问题不大,但是在每次循环的时候,都会去读取box的offsetWidth,导致浏览器每次都会因强制同步布局而触发回流,造成了很大的性能问题。

类似这这情况,我们可以把读取到的offsetWidth进行缓存:

// good
const width = box.offsetWidth;
for (let i = 0; i < element.length; i++) {
    element[i].style.width = width + 'px';
}

使用 transformopacity 来实现动画

最佳的性能渲染流程,就是直接避开回流和重绘,只运行Composite合成这一操作。

目前可以有合成器单独处理的属性有两个:
transforms 和 opacity

比如我们可以使用translate代替lefttop
使用opacity代替visibility

简化绘制的复杂度、减小绘制区域

除 transform 或 opacity 属性之外,更改任何属性始终都会触发绘制。

绘制通常是像素管道中开销最大的部分;应尽可能避免绘制。

通过层的提升来减少绘制区域

绘制并非总是绘制到内存中的单个图像。事实上,在必要时浏览器可以绘制到多个图像或合成器层,各个层可以在彼此的上面处理并合成,以创建最终图像。

创建新层的最佳方式是使用 will-change CSS 属性。
此方法在 Chrome、Opera 和 Firefox 上有效,并且通过 transform 的值将创建一个新的合成器层:

.moving-element { 
    will-change: transform;
}

对于不支持 will-change 但受益于层创建的浏览器,例如 Safari 和 Mobile Safari,需要开启GPU加速来强制创建一个新层:

.moving-element { 
    transform: translateZ(0);
}

优化或减少动画编排

减少绘制区域往往是编排您的动画和变换,使其不过多重叠,或设法减少动画编排,避免对页面的某些部分设置动画。

降低绘制的复杂性

一些css属性的绘制比其他绘制的开销更大。例如,绘制任何涉及模糊(例如shadow)的元素所花的时间将比绘制一个border的时间要长。

实际开发中,我们要确定可否使用一组开销更小的样式,或者替代方式来实现最终结果。

让复杂的布局“离线”

对于复杂的动画,或者频繁触发回流的元素,我们
创建一个documentFragmentdiv,在它上面应用所有DOM操作,最后再把它添加到window.document

也可以在一个display:none的元素上进行操作,最终把它显示出来。因为display:none上的DOM操作不会引发回流和重绘。

也可以使用绝对定位,让它脱离文档流,从而避免引起父元素以及后续元素的频繁回流。

其他

避免使用table布局

我们已经在上面说过,<table>的计算需要不止一次的遍历,table是可以影响之前已经进入的DOM元素的显示的元素。即使一些小的变化和会导致table中所有其他节点回流。

参考文献

浏览器的工作原理:新式网络浏览器幕后揭秘

Google Developers:渲染树构建、布局及绘制

本文转载于网络 如有侵权请联系删除

相关文章

  • 爆肝之我在html学表格

    一个页面就是一个html文档,大家不要学傻了。css/js通过标签以元素的属性寄生在在html文档中元素和标签在HTML中,标签(tag)通常又被称作元素(element)。例如<a>标签又叫做<a>元素,<p>标签也叫作<p>元素。HTML元素根据其表现形式可以分为2种:块级元素,行内元素;任何HTML元素都属于这两者中的任意一种。块级元素(blockelement)在浏览器中占据整行,并排斥其它元素与其位于同一行。也就是说,块级元素的宽度是100%。常见的块级元素如下表:块级元素说明div最典型的块元素p表示段落h1-h6表示1-6级标题(默认加粗)br表示换行ol有序列表ul无序列表行内元素又称内联元素(inlineblock)。在浏览器中可以与其它行内元素共占一行,只有当多个元素的总宽度大于浏览器的宽度时,才会换行显示。常见的行内元素如下表:行内元素说明a超链接span常用行级strong加粗,强调b加粗,不强调em斜体,强调i斜体,不强调img图片input输入框select下拉列表HTML中的各个元素之间是可以互相嵌套的块元素

  • 在 SwiftUI 下使用 NSUbiquitousKeyValueStore 同步数据

    在SwiftUI下使用NSUbiquitousKeyValueStore同步数据可以访问我的博客www.fatbobman.com[1],获得更好的阅读体验NSUbiquitousKeyValueStore是苹果官方提供的用于在设备间共享键值数据的解决方案。本文将对其用法做以简单介绍,着重探讨如何便捷地在SwiftUI中使用NSUbiquitousKeyValueStore。什么是NSUbiquitousKeyValueStoreNSUbiquitousKeyValueStore可以理解为UserDefaults的网络同步版本。它是CloudKit服务项目中的一员,只需简单的配置,就可以实现在不同的设备上共享数据(同一个iCloud账户)。NSUbiquitousKeyValueStore在大多数场合下表现的同UserDefaults十分类似:•都是基于键值存储•只能使用字符串作为键•可以使用任意属性列表对象(Propertylistobjecttypes)作为值•使用类似的读取和写入方法•都是率先将数据保存在内存中,系统会择机对内存数据进行持久化(此过程开发者通常无需干预)即使你没有

  • matlab画折线图

    大家好,又见面了,我是你们的朋友全栈君。p=‘plot_scale.xlsx’; a=xlsread§; x=a(1,:);%x轴上的数据,第一个值代表数据开始,第二个值代表间隔,第三个值代表终止 susan=a(2,:);%a数据y值 HarrisLaplace=a(3,:); MSCP=a(4,:); CPDA=a(5,:); HeYung=a(6,:); FastCPDA=a(7,:); DOG=a(8,:); GCM=a(9,:); ANDD=a(10,:); MSRJ=a(11,:); ZhangSun=a(12,:); WEAE=a(13,:); New_Curvature=a(14,:); ASJ=a(15,:); Superpoint=a(16,:); SOGGDD=a(17,:); %figure(1);subplot(2,2,1); %plot(x,susan,x,HarrisLaplace,x,MSCP,x,CPDA,x,HeYung,x,FastCPDA,x,DOG,x,GCM,x,ANDD,x,MSRJ,‘linewidth’,3);%线性,颜色,标记 sus

  • 应用接入ES(二)-数据同步ES

    一、背景上一篇文章《应用接入ES(一)-Springboot集成ES》我们讲述了应用集成ES的方式,以及实现各种查询和更新操作,那么问题就来了,既然是查询和更新,肯定要有数据,数据哪里来?怎么来?本篇文章我们将主要针对业务数据同步到ES展开分析和描述。二、目标我们将应用集成ES并不是单纯为了学习技术或者说积累经验,最终的目的是支撑业务,那么我们就需要做以下几件事情:历史数据导入ES增量数据实时同步DB和ES数据追平ES数据检索以及DB兜底当然前边三步做的所有工作,都是为了最后一步查询服务,但是如果前边的数据准备工作没处理好,那么就会出现ES数据和DB数据不一致问题,如果仅仅是为了引入ES、为了提高检索能力和性能而牺牲数据的准确性,那么也就失去了接入ES的本质意义。对于第4点,一般业务上会使用开关主动降级和业务自动降级结合使用,主动降级是在配置平台手动操作开关闭合状态,从而实时控制业务中数据检索的数据来源,业务自动降级是基于主动降级的基础上,对ES检索进行兜底处理,如果ES检索失败或者出现异常,自动降级到DB检索。业务数据同步到ES,主要通过前边3点来实现,接下来我们将逐步展开分析和讲述

  • python 微信机器人-如何调用机器人的api,调用图灵机器人接口演示。调用机器人原理,图灵机器人注册。

    这是一个把接收的消息传给图灵机器人,再把图灵机器人回复的消息传回来的函数.defget_response(msg): apiUrl='http://www.tuling123.com/openapi/api' data={ 'key':'bd0a1aafaafd418bbdb6aa0a40f73859', 'info':msg, 'userid':'小爱', } try: r=requests.post(apiUrl,data=data).json() returnr.get("text") except: return复制我们调用的是图灵机器人,这个apiUrl就是图灵机器人提供给我们的api接口。 接下来给大家演示一下怎么来调用自己的机器人。首先我们来注册一个属于我们自己的自己人图灵机器人官网 登陆进来后我们创建一个机器人,定制你想要的类型。 创建完选择服务版的免费版就好了,每天限量1000次。 然

  • 图解选择排序算法

    一、说在前面一直想写一些简单易懂的文章,因为平时看的很多的书籍或者文章都是看着很难受的感觉,当然,这并不是说书籍写的不好,只是说对于一些没有太多基础或者基础不是很好的来说,相对来说还是比较难以理解的。这个系列主要是写一些简单易懂的数据结构与算法的文章,同时也是帮助自己再理解理解这方面的知识。作为数据结构与算法的开篇,还是以排序算法作为第一部分的内容,需要注意的是,这一系列的文章并不是涉及到很多理论性质的知识,因为前面说了,主要还是希望文章是简单易懂的,希望能达到读故事的感觉。如果需要去学习理论性质的知识,可以去查看相关的数据结构与算法的书籍。二、选择排序算法今天早上,老师又叫我们去操场上做早操,做早操之前呢,今天也需要排队,到操场的同学有5个人,今天的排序方法还是按照身高由低到高排列。图片1.png但是,今天老师说换一种方法排队,我来给你们排队,昨天你们排队太慢了。于是,老师说:第一个同学站在原地不要动。图片2.png然后,我从后面4个同学当中挑一个最矮的同学,这个同学站在第一个同学后面,你们两个站在原地不要动。图片3.png图片4.png之后,老师再从后面3个同学里面挑一个最矮的同学

  • 看到明星吸毒后,我的一点感想

    下午看到明星吸毒后,我的一点感想我们的公众号是技术类,从来没有写过这类话题,略感不安。因为实在想写一些,故放到次条,纯碎是个人的见解,也欢迎大家留言区发表自己的看法。1明星明星的物质生活条件极大丰富,这是毋庸置疑的,这也是很多人想成为明星的原因。有钱啊,谁不想有钱啊,有钱意味着想买啥就买啥,不必太关注价格,每年可以买最新款的Iphone。明星的这个有钱属性可以说是人类群体中的一个极端。从很多角度观察,我们都会觉得这个属性是梦寐以求的。不过,任何事物都是有两面性的,这个属性也绝不例外,今天star吸毒被抓,被无限放大到聚光灯下,就是另一个极大。可以归类为:个人错误容易被紧盯后被媒体曝光性,这又是另一个极端。因为你是明星,所以很多人会盯着你,你一旦犯错,尤其是这类错误,媒体是不会放过你的,这是流量的保证。所以,作为明星需要极为谨慎。问题在于,明星难道不懂吗?能成为明星一定有强于平常人的地方,不管是哪方面。既然这样,为什么不定期还会有明星趟一趟这条河呢?背后的原因我觉得主要是物质条件的极大丰富使得他们放纵了自己,忘记了之前的理想,或者因为现在成名了,忘乎所以,缺失了再奋斗的目标;外部条件自然

  • CentOS7安装维护nginx从入门到精通

    Nginx是一款面向性能设计的HTTP服务器,能反向代理HTTP,HTTPS和邮件相关(SMTP,POP3,IMAP)的协议链接。并且提供了负载均衡以及HTTP缓存。它的设计充分使用异步事件模型,削减上下文调度的开销,提高服务器并发能力。采用了模块化设计,提供了丰富模块的第三方模块。所以关于Nginx,有这些标签:「异步」「事件」「模块化」「高性能」「高并发」「反向代理」「负载均衡」Linux系统:Centos7x64Nginx版本:1.11.5安装安装依赖prce(重定向支持)和openssl(https支持,如果不需要https可以不安装。)yuminstall-ypcre-devel yum-yinstallgccmakegcc-c++wget yum-yinstallopensslopenssl-devel复制CentOS6.5我安装的时候是选择的“基本服务器”,默认这两个包都没安装全,所以这两个都运行安装即可。下载nginx的所有版本在这里wgethttp://nginx.org/download/nginx-1.13.3.tar.gz wgethttp://nginx.or

  • C# 自定义类型通过实现IFormattable接口,来输出指定的格式和语言文化的字符串(例:DateTime)

    常规的调用ToString()方法,存在两个问题.(1)、调用者无法控制字符串的格式(2)、调用者不能方便的选择一种特定的语言文化来格式化字符串.在开发一些国际化的应用时,应用程序需要调用与当前线程不同的语言文化来格式化字符串.so,为了对字符串进行更多的控制,你重写的的ToString()方法应该允许指定具体的格式和语言文化信息.为了能使调用者在调用对象实例的ToString()方法的时候,选择格式和语言文化,该对象应该实现System.IFormattable接口,接口代码如下:// //摘要: //提供一种功能,用以将对象的值格式化为字符串表示形式。 [ComVisible(true)] publicinterfaceIFormattable { // //摘要: //使用指定格式对当前实例的值设置格式。 // //参数: //format: //要使用的格式。-或-null引用(在VisualBasic中为Nothing),用于使用为System.IFormattable实现的类型定义的默认格式。 // //formatProvider: //要用于对值设置格式的提供程序。-或

  • 2015Q4智能可穿戴市场白皮书 - 腾讯ISUX

    ISUX用户研究中心刚刚发布了《2015Q4智能可穿戴市场白皮书》,针对市场现状、发展趋势等进行了研究和分析,详情如下。感谢你的阅读,本文由 腾讯ISUX 版权所有,转载时请注明出处,违者必究,谢谢你的合作。 注明出处格式:腾讯ISUX(http://isux.tencent.com/2015q4-wearable-market-white-book.html)

  • IIS4\\IIS5 CGI环境块伪造0day漏洞

    大约14年前发现一直到现在的0day是IIS4\IIS5的漏洞,对应操作系统是winnt和win2000系统,微软不再支持这些软件,他们的策略想淘汰这些系统,11年报告后微软决定不再修补。算是很严重的漏洞,只是影响的软件现在使用率相对比较低,但总量也不少。具体漏洞详细信息如下:IIS加载CGI环境块伪造漏洞危害等级:高危危害类型:缓冲区溢出、远程执行代码、信息泄露影响平台:Winnt\win2000影响软件:IIS4、IIS5基本情况:IIS4、IIS5加载CGI,处理环境块的时候,错误的把“\n”字符用“\x00”替换,导致可以伪造任意环境块。IIS加载CGI的时候,把自己的请求加上“HTTP_”前缀加入环境变量和本地环境变量区分,通过利用”\n”替换成”\0”的漏洞就可以把这些前缀去掉,从而任意伪造环境块变量。攻击者可以在http头里提交“a=b\nPATH_TRANSLATED:var”使得IIS加载CGI的时候环境块变量成为”HTTP_a=b”和“PATH_TRANSLATED=var”,成功伪造环境块“PATH_TRANSLATED=var”,让php.exe执行脚本文件“v

  • 关于

    最近学习vue过程中,发现路径当中总是存在一个#号,比如这个: 这种情况是因为在入口js文件中,如果你不更改设置的话,vue会默认使用hash模式,该模式下回将路径格式化为#开头。 如果需要美化路径,可以更改模式为history: router里面的index.js配置里面 importVuefrom'vue' importRouterfrom'vue-router' Vue.use(Router) constroutes=[ { path:'/about', name:'about', meta:{ title:'关于', auth:false }, component:()=>import(/*webpackChunkName:"about"*/'../view/About.vue') } ] constrouter=newRouter({ mode:'history', base:process.env.BASE_URL, routes }) exportdefaultrouter 复制 这样就把路径里的#号去除了,是不是好看了很多呢?

  • Uploadify/uploadifive上传(中文文档)

      Uploadify是一款基于JQuery的优秀的文件/图片上传的插件,有基于Flash和HTML5两种版本。  Uploadify/uploadifive主要特点有: 1.多文件上传 2.个性化设置 3.上传进度条显示  4.拖拽上传(HTML5版本)  官网:http://www.uploadify.com   部署   在部署一个Uploadify实例前,请确保满足最低要求: 1.jQuery1.4.x或更高版本 2.FlashPlayer9.0.24或更高版本 3.支持PHP,ASP.Net,ColdFusion的服务器环境(官方默认支持PHP) 下载最新版本的uploadify,解压到服务器根目录下的uploadify文件夹中,你可以看到以下文件: ChangeLog.txt(uploadify的升级日志,部署时删掉) check-exists.php(用来检查上传目标文件夹里是否存在相同文件) index.php(官方实例) jquery.uploadify.js

  • review——C# (11)结构

    FROMP198 1.什么是结构   结构与类的区别:   □类是引用类型而结构是值类型   □结构是隐式密封的,这意味着它们不能被派生 2.结构是值类型   □结构类型的变量不能为null   □两个结构变量不能引用同一个对象 e.g.下图展示了该代码中的两个变量如何被安排在内存中 1usingSystem; 2usingSystem.Collections.Generic; 3usingSystem.Linq; 4usingSystem.Text; 5usingSystem.Threading.Tasks; 6 7namespacereview 8{ 9classCSimple 10{ 11publicintX; 12publicintY; 13} 14structSimple 15{ 16publicintX; 17publicintY; 18} 19classProgram 20{ 21staticvoidMain(string[]args) 22{ 23CSimplecs=newCSimple(); 24Simpless=newSimple(); 25Console.Rea

  • 如何分析html中的json

    在js逆向的过程中,时常要使用正则表达式去匹配htnl的内容,有时候关键的数据都在json中,这个怎么分析这个json呢 1.使用vscode打开html vscode的js插件会分析html文件,这样就可以理清楚结构关系,找到关键的json 2.去除json中的转移字符 json字符串被dumps会被转义,有两种办法可以去除 使用visualstduo 使用文件流将html加载进来,并赋值给string,调试的时候点击查看就可以看到load后的json字符串 使用https://www.json.cn/ 点击json压缩转义 在下方点击去除转义即可

  • Vue修仙之旅之Vue初尝

    安装环境 1.安装npm npm全称NodePackageManager,是一个基于Node.js的包管理器,也是整个Node.js社区最流行,支持的第三方模块最多的包管理器。 node-v npm-v 2.由于网络原因 可以通过如下操作解决npm下载速度慢的问题(新建空项目先执行第3步) #安装依赖npminstall #建议不要用cnpm安装会有各种诡异的bug可以通过如下操作解决npm下载速度慢的问题 npminstall--registry=https://registry.npm.taobao.org 3.安装vue-cli npmi-g@vue/cli 可视化创建项目命令vueui  4.安装webpack npminstall-gwebpage webpack是JavaScript打包器(modulebundler)  

  • Beta版项目总结

    1、设想与目标   我们的产品名是理财猫,为了解决当今大学生花钱不知道节制以及不知道花的钱都去哪了的痛苦,提醒他们该记录这一天的消费情况,我们有独特的办法那就是将记账软件和闹钟结合起来,每天定时的提醒用户该记账了, 它能给用户带来好处是,用户能清楚的知道自己的钱去哪了,花在了哪方面,以及在哪方面花的钱最多,这样用户就可以有目标的在某一方面省钱了。同时,我们也有高效率的推销我们软件的方法,比如说通过贴吧、微博、QQ、微信等向大家介绍我们的软件。在第二阶段开始之前老师给了我们很好地建议,我们利用剩下的时间详细的做了详细的实施计划,团队如果出现什么问题,大家会以投票方式决定哪个意见更好,或者都将自己的想法阐述出来,综合各方面因素,选取最有利于团队项目的想法。 2、计划   在冲刺阶段内,我们将我们的预定目标按安排完全实现,因为我们的能力有限,实现起来需要比别人多一点的时间,在规定的时间内也是刚刚好完成,没有留下缓冲区,所以我们延长了我们的冲刺时间来查漏补缺。 3、资源   我们虽然实力不高,但可以花费比别人更多的时间来完成,所以时间资源还是很充分的,各项任务的估计时间都是按照难易程

  • P1637 三元上升子序列

    标签+线段树+离散化好题。 题意:给定一个长度为的序列,问满足的三元组的个数。 数据范围: 首先,我们知道求满足且的二元组的个数的线段树做法是什么。 类比P1198[JSOI2008]最大数,假设现在有一个数组。我们扫一遍整个序列,扫到时。此时数组存的是在数列中位置下标中大小为的数字的个数。那么此时便可以得到:对于,在中比小的数字的个数。 那么对于原问题,。这个过程利用线段树即可完成统计。 最后注意:由于的值域过大,所以需先离散化。 Code: #include<cstdio> #include<iostream> #include<algorithm> #defineriregisterint usingnamespacestd; constintMAXN=30020; intn,a[MAXN]; intl[MAXN<<2],r[MAXN<<2],add[MAXN<<2],tot[MAXN]; longlongsum[MAXN<<2],ans; structnode{ intnum,pla; }sh

  • Pycharm 输出中文或打印中文乱码现象的解决办法

    1.确保文件开头加上以下代码:1#-*-coding:utf-8-*-复制 还可以加上 1importsys 2reload(sys) 3sys.setdefaultencoding('utf-8')复制 确保以下。 如果还是没有解决中文乱码,那么进行方法2. 2.进入setting 单击打开,单击 修改完成后,结果如下 单击“ok”。 成功。 “过一个平凡无趣的人生实在太容易了,你可以不读书,不冒险,不运动,不写作,不外出,不折腾……但是,人生最后悔的事情就是:我本可以。”——陈素封。

  • [FJOI2014]最短路径树问题

    题意 Here 思考 吐槽一下这个题,完全就是两个裸题拼一起了,而且两个板子之间毫无联系… 首先我们造一个保证字典序最小的最短路径树,怎么保证字典序呢,先将你存的图按字典序从小到大重新排个序再跑最短路就行了。之后就是:跑\(dijkstra\),\(dfs\)一遍重新建图,如果\(u\)已经被访问过,那么边\(e\{u,v,d\}\)在最短路上的当且仅当:\(dist[u]+d==dist[v]\)。 建完了最短路树之后,问题就是询问一颗树上的经过点数等于\(k\)的路径长度的最大值,以及最长路径的条数(路径必须满足经过的点数等于\(k\))这个就是点分治裸题了。 代码 #include<bits/stdc++.h> usingnamespacestd; intread(){ intx=0,f=1;charch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar(

  • Netty URL路由方案探讨

    最近在用Netty做开发,需要提供一个httpwebserver,供调用方调用。采用Netty本身提供的HttpServerCodechandler进行Http协议的解析,但是需要自己提供路由。 最开始是通过对Httpmethod及uri采用多层ifelse嵌套判断的方法路由到真正的controller类: Stringuri=request.uri(); HttpMethodmethod=request.method(); if(method==HttpMethod.POST){ if(uri.startsWith("/login")){ //url参数解析,调用controller的方法 }elseif(uri.startsWith("/logout")){ //同上 } }elseif(method==HttpMethod.GET){ if(uri.startsWith("/")){ }elseif(uri.startsWith("/status")){ } } 复制 在只需提供login及logoutAPI时,代码可以完成功能,可是随着API的数量越来越多,需要支持的方法

相关推荐

推荐阅读