Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

网页布局方法入门

发表于 2019-08-10 | 更新于 2023-01-13

使用CSS对网页布局进行设计是前端工程师的重要工作。下面即介绍各种CSS网页布局的方法,以及相应的技术。

居中方法

居中在布局中很常见,假设DOM文档结构如下,子元素要在父元素中居中:

1
2
3
<div class="parent">
<div class="child"></div>
</div>

水平居中

子元素为行内元素还是块状元素,宽度一定还是宽度未定,采取的布局方案不同。以下即根据子元素的类型给出对应水平居中方法:

  • 行内元素:对父元素设置text-align:center;
  • 定宽块状元素: 设置左右margin值为auto;
  • 不定宽块状元素: 设置子元素为display:inline,然后在父元素上设置text-align:center;
  • 通用方案: flex布局,对父元素设置display:flex;justify-content:center;

垂直居中

垂直居中对于子元素是单行内联文本、多行内联文本以及块状元素采用的方案是不同的。具体方法如下:

  • 父元素一定,子元素为单行内联文本:设置父元素的height等于行高line-height
  • 父元素一定,子元素为多行内联文本:设置父元素的display:table-cell或inline-block,再设置vertical-align:middle;
  • 块状元素:设置子元素position:absolute 并设置top、bottom为0,父元素要设置定位为static以外的值,margin:auto;

单列布局

单列布局如图1所示,可分成两种类型,有定宽、水平居中的特点。

  • 一种是header、content、footer宽度都相同,其一般不会占满浏览器的最宽宽度,但当浏览器宽度缩小低于其最大宽度时,宽度会自适应。
  • 一种是header、footer宽度为浏览器宽度,但content以及header和footer里的内容却不会占满浏览器宽度。

单列布局的两种形式

图1 单列布局的两种形式

对于第一种,对header、content、footer统一设置width或max-width,并通过margin:auto实现居中。

1
2
3
4
5
<div class="layout">
<div id="header">头部</div>
<div id="content">内容</div>
<div id="footer">尾部</div>
</div>
1
2
3
4
5
.layout{
/* width: 960px; *//*设置width当浏览器窗口宽度小于960px时,单列布局不会自适应。*/
max-width: 960px;
margin: 0 auto;
}

对于第二种,header、footer的内容宽度为100%,但header、footer的内容区以及content统一设置width 或 max-width,并通过margin:auto实现居中。

1
2
3
4
5
6
7
<div id="header">
<div class="layout">头部</div>
</div>
<div id="content" class="layout">内容</div>
<div id="footer">
<div class="layout">尾部</div>
</div>
1
2
3
4
5
.layout{
/* width: 960px; *//*设置width当浏览器窗口宽度小于960px时,单列布局不会自适应。*/
max-width: 960px;
margin: 0 auto;
}

二列&三列布局

二列布局的特征是侧栏固定宽度,主栏自适应宽度。三列布局的特征是两侧两列固定宽度,中间列自适应宽度。 之所以将二列布局和三列布局写在一起,是因为二列布局可以看做去掉一个侧栏的三列布局,其布局的思想有异曲同工之妙。

对于传统的实现方法,主要讨论上图2中前三种布局,经典的带有侧栏的二栏布局以及带有左右侧栏的三栏布局。使用flex技术,可实现图2的五种布局。

二列&三列布局

图2 二列&三列布局

实现二列&三列布局的CSS技术主要有:

float+margin

原理说明:设置两个侧栏分别向左向右浮动,中间列通过外边距给两个侧栏腾出空间,中间列的宽度根据浏览器窗口自适应。

1
2
3
4
5
<div id="content">
<div class="sub">sub</div>
<div class="extra">extra</div>
<div class="main">main</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
.sub{
width: 100px;
float: left;
}
.extra{
width: 200px;
float: right;
}
.main{
margin-left: 100px;
margin-right: 200px;
}

注意:

  • DOM文档的书写顺序,先写两侧栏,再写主面板,更换后则侧栏会被挤到下一列(圣杯布局和双飞翼布局都会用到)。  
  • 这种布局方式比较简单明了,但缺点是渲染时先渲染了侧边栏,而不是比较重要的主面板。

position+margin

原理说明:通过绝对定位将两个侧栏固定,同样通过外边距给两个侧栏腾出空间,中间列自适应。

1
2
3
<div class="sub">left</div>
<div class="main">main</div>
<div class="extra">right</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.sub, .extra {
position: absolute;
top: 0;
width: 200px;
}
.sub {
left: 0;
}
.extra {
right: 0;
}
.main {
margin: 0 200px;
}

注意:

  • 本方法不限制DOM书写顺序,先写主面板会使主面板部分优先渲染(一般主面板会比侧栏内容重要)。
  • 与上一种方法相比,本种方法是通过定位来实现侧栏的位置固定。
  • 如果中间栏含有最小宽度限制,或是含有宽度的内部元素,则浏览器窗口小到一定程度,主面板与侧栏会发生重叠。

圣杯布局(float + 负margin)

原理说明:

主面板设置宽度为100%,主面板与两个侧栏都设置浮动,常见为左浮动,这时两个侧栏会被主面板挤下去。通过负边距将浮动的侧栏拉上来,左侧栏的负边距为100%,刚好是窗口的宽度,因此会从主面板下面的左边跑到与主面板对齐的左边,右侧栏此时浮动在主面板下面的左边,设置负边距为负的自身宽度刚好浮动到主面板对齐的右边。为了避免侧栏遮挡主面板内容,在外层设置左右padding值为左右侧栏的宽度,给侧栏腾出空间,此时主面板的宽度减小。由于侧栏的负margin都是相对主面板的,两个侧栏并不会像我们理想中的停靠在左右两边,而是跟着缩小的主面板一起向中间靠拢。此时使用相对布局,调整两个侧栏到相应的位置。

双飞翼布局(float + 负margin )

原理说明:

双飞翼布局和圣杯布局的思想有些相似,都利用了浮动和负边距,但双飞翼布局在圣杯布局上做了改进,在main元素上加了一层div, 并设置margin,由于两侧栏的负边距都是相对于main-wrap而言,main的margin值变化便不会影响两个侧栏,因此省掉了对两侧栏设置相对布局的步骤。

flex布局

与之前所讲的几种传统布局方案相比,flex布局的代码可谓异常简洁,而且非常通用,利用简单的三行CSS即实现了常见的五种布局。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="layout">
<aside class="aside">侧边栏宽度固定</aside>
<div class="main">主内容栏宽度自适应</div>
</div>
<div class="layout">
<div class="main">主内容栏宽度自适应</div>
<aside class="aside">侧边栏宽度固定</aside>
</div>
<div class="layout">
<aside class="aside">左侧边栏宽度固定</aside>
<div class="main">主内容栏宽度自适应</div>
<aside class="aside">右侧边栏宽度固定</aside>
</div>
<div class="layout">
<aside class="aside">第1个侧边栏宽度固定</aside>
<aside class="aside">第2个侧边栏宽度固定</aside>
<div class="main">主内容栏宽度自适应</div>
</div>
<div class="layout">
<div class="main">主内容栏宽度自适应</div>
<aside class="aside">第1个侧边栏宽度固定</aside>
<aside class="aside">第2个侧边栏宽度固定</aside>
</div>
1
2
3
4
5
6
7
8
9
.layout {
display: flex;
}
.main {
flex: 1;
}
.aside {
width: 200px;
}

自适应与响应式布局

自适应是为了解决如何才能在不同大小的设备上呈现同样的网页,实现一次设计,普遍适用而提出的技术,以避免维护多个版本的针对不同分辨率设备的网页。

但自适应存在一个问题,如果屏幕太小,即使网页能够根据屏幕大小进行适配,但是会感觉在小屏幕上查看,内容过于拥挤。响应式正是为了解决这个问题而衍生出来的概念。它可以自动识别屏幕宽度、并做出相应调整的网页设计,布局和展示的内容可能会有所变动。

目前网页的响应式布局解决方案成为当前主流,并因 twitter 开源的 bootstrap 而被大家熟知。响应式布局的实现原理如下:

  • 允许网页宽度自动调整

网页代码的头部,加入一行viewport元标签。

1
<meta name="viewport" content="width=device-width, initial-scale=1" />

viewport是网页默认的宽度和高度,上面这行代码的意思是,网页宽度默认等于屏幕宽度(width=device-width),原始缩放比例(initial-scale=1)为1.0,即网页初始大小占屏幕面积的100%。

  • 尽量少使用绝对宽度

由于网页会根据屏幕宽度调整布局,所以不能使用绝对宽度的布局,也不能使用具有绝对宽度的元素。这一条非常重要。具体说,CSS代码不能指定像素宽度:

1
width:xxx px;

通过指定百分比宽度来替代:同时还可以配合css的cal,进行计算宽度。

1
2
width: xx%;
width:auto;
  • 相对大小的字体

字体也不能使用绝对大小(px),而只能使用相对大小(em)或者高清方案(rem),rem不局限于字体大小,前面的宽度width也可以使用,代替百分比。

1
2
3
body {
font: normal 100% Helvetica, Arial, sans-serif;
}

上面的代码指定,字体大小是页面默认大小的100%,即16像素。

1
2
3
h1 {
  font-size: 1.5em;
}

然后,h1的大小是默认大小的1.5倍,即24像素(24/16=1.5)。

  • 流动布局(fluid grid)

“流动布局”的含义是,各个区块的位置都是浮动的,不是固定不变的。

1
2
3
4
5
6
7
8
9
.main {
  float: right;
  width: 70%;
}

.leftBar {
  float: left;
  width: 25%;
}

float的好处是,如果宽度太小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现。

  • 选择加载CSS

“自适应网页设计”的核心,就是CSS3引入的Media Query模块。

它的意思就是,自动探测屏幕宽度,然后加载相应的CSS文件。

1
2
3
4
5
6
7
<link rel="stylesheet" type="text/css"
    media="screen and (max-device-width: 400px)"
    href="tinyScreen.css" />

<link rel="stylesheet" type="text/css"
    media="screen and (min-width: 400px) and (max-device-width: 600px)"
    href="smallScreen.css" />

除了用html标签加载CSS文件,还可以在现有CSS文件中加载。

1
@import  url("tinyScreen.css") screen and (max-device-width: 400px);
  • CSS的@media规则

同一个CSS文件中,也可以根据不同的屏幕分辨率,选择应用不同的CSS规则。

1
2
3
4
5
6
7
8
9
10
@media  screen and (max-device-width: 400px) {
  .column {
    float: none;
    width:auto;
  }

  #sidebar {
    display:none;
  }
}
  • 图片的自适应(fluid image)

除了布局和文本,”自适应网页设计”还必须实现图片的自动缩放。这只要一行CSS代码:

1
img { max-width: 100%;}

布局相关CSS

display

display CSS 属性指定了元素的显示类型,它包含两类基础特征,用于指定元素怎样生成盒模型——外部显示类型定义了元素怎样参与流式布局的处理,内部显示类型定义了元素内子元素的布局方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* <display-outside> values */
display: block;
display: inline;
display: run-in;

/* <display-inside> values */
display: flow;
display: flow-root;
display: table;
display: flex;
display: grid;
display: ruby;

/* <display-outside> plus <display-inside> values */
display: block flow;
display: inline table;
display: flex run-in;

/* <display-listitem> values */
display: list-item;
display: list-item block;
display: list-item inline;
display: list-item flow;
display: list-item flow-root;
display: list-item block flow;
display: list-item block flow-root;
display: flow list-item block;

/* <display-internal> values */
display: table-row-group;
display: table-header-group;
display: table-footer-group;
display: table-row;
display: table-cell;
display: table-column-group;
display: table-column;
display: table-caption;
display: ruby-base;
display: ruby-text;
display: ruby-base-container;
display: ruby-text-container;

/* <display-box> values */
display: contents;
display: none;

/* <display-legacy> values */
display: inline-block;
display: inline-table;
display: inline-flex;
display: inline-grid;

/* Global values */
display: inherit;
display: initial;
display: unset;

position

CSS position属性用于指定一个元素在文档中的定位方式。top,right,bottom 和 left 属性则决定了该元素的最终位置。position 属性被指定为从下面的值列表中选择的单个关键字:

  • static

该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。

  • relative

该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。

  • absolute

不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。

  • fixed

不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。

  • sticky

盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky 对 table 元素的效果与 position: relative 相同。

float

float CSS属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它。该元素从网页的正常流动(文档流)中移除,尽管仍然保持部分的流动性(与绝对定位相反)。float 属性的值被指定为单一的关键字,值从下面的值列表中选择:

  • left

表明元素必须浮动在其所在的块容器左侧的关键字。

  • right

表明元素必须浮动在其所在的块容器右侧的关键字。

  • none

表明元素不进行浮动的关键字。

  • inline-start

关键字,表明元素必须浮动在其所在块容器的开始一侧,在ltr脚本中是左侧,在rtl脚本中是右侧。

  • inline-end

关键字,表明元素必须浮动在其所在块容器的结束一侧,在ltr脚本中是右侧,在rtl脚本中是左侧。

float属性具有包裹性和高度欺骗两个特性。

包裹性

block元素不指定width的话,默认是100%,一旦让该div浮动起来,立刻会像inline元素一样产生包裹性,宽度会跟随内容自适应。(这也是通常float元素需要手动指定width的原因)。

float的包裹性

图3 float的包裹性

效果非常近似于display:inline-block。但相比之下,浮动能设定为左浮和右浮,但display:inline-block都是从左到右排列的。(还有些细微差别,两个display:inline-block间会有空隙,但两个float间没有。)

高度欺骗性

float的高度欺骗性

图4 float的高度欺骗性

外层div在没有手动设定height的前提下,其高度是由内部content的最大高度决定的,由于img的float使得img具有高度塌陷的欺骗性,让div误以为img的line-height为0,因此div的高度就是文字的匿名inline-box的inline-height。

闭合浮动

闭合浮动的实现方法很多,最合理的方法是用:after伪元素,思路是用:after元素在div后面插入一个隐藏文本”.”,隐藏文本用clear来实现闭合浮动。

1
2
3
4
5
6
7
8
9
10
.clearfix:after {
clear: both;
content: "."; //你头可以改成其他任意文本如“abc”
display: block;
height: 0; //高度为0且hidden让该文本彻底隐藏
visibility: hidden;
}
.clearfix {
*zoom: 1;
}
1
2
3
4
5
6
7
8
9
<div style="border:4px solid blue;" class="clearfix">
<div style="width:200px; border:4px solid red; float:left;">
我是浮动元素1
</div>
<div style="width:200px; border:4px solid yellow; float:left;">
我是浮动元素2
</div>
</div>
<div style="border:4px solid gray;">我是页脚</div>

参考链接

  1. CSS布局十八般武艺都在这里了,by Shelley Lee.
  2. Flex 布局教程:语法篇,by 阮一峰.
  3. Flex 布局教程:实例篇,by 阮一峰.
  4. Flexbox 布局的最简单表单,by 阮一峰.
  5. 自适应网页设计(Responsive Web Design),by 阮一峰.
  6. CSS Grid 网格布局教程,by 阮一峰.
  7. 响应式和自适应的区别,by LorinLuo.
  8. display,by mozilla.
  9. position,by mozilla.
  10. CSS浮动float详解,by 张歆琳.
  11. float,by mozilla.
  12. Scrolling a flexbox with overflowing content,by stackoverflow.
  13. How to Fix Overflow Issues in CSS Flex Layouts,by moduscreate.
  14. An Interactive Guide to Flexbox,by joshwcomeau.

Mockjs入门简介

发表于 2019-08-09

Mock.js可生成随机数据,拦截Ajax请求,实现前后端分离的目的。Mockjs支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等数据类型,增加了单元测试的真实性,具有用法简单,方便扩展和开发无侵入的特点。下面简单介绍Mockjs的用法。

开始 & 安装

Node (CommonJS)

1
2
# 安装
npm install mockjs
1
2
3
4
5
6
7
8
9
10
11
// 使用 Mock
var Mock = require('mockjs')
var data = Mock.mock({
// 属性 list 的值是一个数组,其中含有 1 到 10 个元素
'list|1-10': [{
// 属性 id 是一个自增数,起始值为 1,每次增 1
'id|+1': 1
}]
})
// 输出结果
console.log(JSON.stringify(data, null, 4))

语法规范

Mock.js 的语法规范包括两部分:

  • 数据模板定义规范(Data Template Definition,DTD)
  • 数据占位符定义规范(Data Placeholder Definition,DPD)

数据模板定义规范 DTD

数据模板中的每个属性由 3 部分构成:属性名、生成规则、属性值:

1
2
3
4
// 属性名   name
// 生成规则 rule
// 属性值 value
'name|rule': value

注意:

  • 属性名 和 生成规则 之间用竖线 | 分隔。
  • 生成规则 是可选的。
  • 生成规则 有 7 种格式:
    • ‘name|min-max’: value
    • ‘name|count’: value
    • ‘name|min-max.dmin-dmax’: value
    • ‘name|min-max.dcount’: value
    • ‘name|count.dmin-dmax’: value
    • ‘name|count.dcount’: value
    • ‘name|+step’: value
  • 生成规则 的 含义 需要依赖 属性值的类型 才能确定。
  • 属性值 中可以含有 @占位符。
  • 属性值 还指定了最终值的初始值和类型。

数据占位符定义规范 DPD

占位符 只是在属性值字符串中占个位置,并不出现在最终的属性值中。

占位符 的格式为:

1
2
@占位符
@占位符(参数 [, 参数])

注意:

  • 用 @ 来标识其后的字符串是 占位符。
  • 占位符 引用的是 Mock.Random 中的方法。
  • 通过 Mock.Random.extend() 来扩展自定义占位符。
  • 占位符 也可以引用 数据模板 中的属性。
  • 占位符 会优先引用 数据模板 中的属性。
  • 占位符 支持 相对路径 和 绝对路径。

Mock.Random

Mock.Random 是一个工具类,用于生成各种随机数据。

Mock.Random 的方法在数据模板中称为『占位符』,书写格式为 @占位符(参数 [, 参数]) 。

1
2
3
4
5
6
7
var Random = Mock.Random
Random.email()
// => "n.clark@miller.io"
Mock.mock('@email')
// => "y.lee@lewis.org"
Mock.mock( { email: '@email' } )
// => { email: "v.lewis@hall.gov" }

参考链接

  1. Mockjs,by nuysoft.
  2. Mockjs语法规范,by nuysoft.
  3. Mock.Random,by nuysoft.

软件设计模式简介

发表于 2019-08-06 | 更新于 2022-12-07

软件模式是将模式的一般概念应用于软件开发领域,即软件开发的 总体指导思路或参照样板。软件模式并非仅限于设计模式,还包括 架构模式、分析模式和过程模式等,实际上,在软件生存期的每一个阶段都存在着一些被认同的模式。下面重点介绍各种经典的设计模式。

创建型模式

简单工厂模式( Simple Factory Pattern )

工厂方法模式(Factory Method Pattern)

抽象工厂模式(Abstract Factory)

建造者模式

单例模式

单例是指在程序运行周期内有且只有一个实例化的对象。

根据实例化的时机,主要分为饿汉和懒汉两种。

饿汉

第一次获取实例前就已经创建好。

1
2
3
4
5
6
7
8
9
10
11
class Singleton {
public:
static Singleton* GetInstance();
private:
static Singleton* instance_;
};
Singleton* instance_ = new Singleton(); // 已经创建好

Singleton* Singleton::GetInstance() {
return instance_;
}

懒汉

第一次获取实例时才创建。懒汉方式下会存在线程安全问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Singleton {
public:
static Singleton* GetInstance();
private:
static Singleton* instance_;
};
Singleton* instance_ = nullptr; // 静态变量的初始化,默认为nullptr

Singleton* Singleton::GetInstance() {
if (instance_ == nullptr) {
instance_ = new Singleton(); // instance_为空时才创建
}
return instance_;
}

结构型模式

适配器模式

桥接模式

装饰模式

外观模式

享元模式

代理模式

行为型模式

命令模式

中介者模式

观察者模式

状态模式

策略模式

参考链接

  1. 图说设计模式,by me115.
  2. 【置顶】探究osg中的程序设计模式【目录】,by 3wwang.
  3. 解释器模式(详解版),by c.biancheng.
  4. C++各类设计模式及实现详解,by linux.
  5. The Catalog of Design Patterns,by refactoringguru.
  6. C++ 静态单例,by sinat_31135199.
  7. 单例模式对象的删除,by hahacaidao.

UML类图中类之间关系

发表于 2019-08-06 | 更新于 2020-03-31

UML类图中类之间的关系主要有六种:泛化、实现、聚合、组合、依赖、关联。如图1所示。

UML类图

  • 车的类图结构为<>,表示车是一个抽象类;
  • 它有两个继承类:小汽车和自行车;它们之间的关系为实现关系,使用带空心箭头的虚线表示;
  • 小汽车为与SUV之间也是继承关系,它们之间的关系为泛化关系,使用带空心箭头的实线表示;
  • 小汽车与发动机之间是组合关系,使用带实心箭头的实线表示;
  • 学生与班级之间是聚合关系,使用带空心箭头的实线表示;
  • 学生与身份证之间为关联关系,使用一根实线表示;
  • 学生上学需要用到自行车,与自行车是一种依赖关系,使用带箭头的虚线表示;

熟悉这六种关系及其符号表示,有利于我们设计类图和同行之间交流。下面介绍这六种关系。

泛化关系(generalization)

类的继承结构表现在UML中为:泛化(generalize)与实现(realize):

继承关系为 is-a的关系;两个对象之间如果可以用 is-a 来表示,就是继承关系:(..是..)

例如:自行车是车、猫是动物。

泛化关系用一条带空心箭头的直接表示;如下图表示;

泛化关系

汽车在现实中有实现,可用汽车定义具体的对象;汽车与SUV之间为泛化关系;最终代码中,泛化关系表现为继承非抽象类;

实现关系(realize)

实现关系用一条带空心箭头的虚线表示;

例如:”车”为一个抽象概念,在现实中并无法直接用来定义对象;只有指明具体的子类(汽车还是自行车),才可以用来定义对象(”车”这个类在C++中用抽象类表示,在JAVA中有接口这个概念,更容易理解)

实现关系

最终代码中,实现关系表现为继承抽象类;

聚合关系(aggregation)

聚合关系用一条带空心菱形箭头的直线表示,如下图表示A聚合到B上,或者说B由A组成;

聚合关系

聚合关系用于表示实体对象之间的关系,表示整体由部分构成的语义;例如一个部门由多个员工组成;

与组合关系不同的是,整体和部分不是强依赖的,即使整体不存在了,部分仍然存在;例如, 部门撤销了,人员不会消失,他们依然存在;

组合关系(composition)

组合关系用一条带实心菱形箭头直线表示,如下图表示A组成B,或者B由A组成;

组合关系

与聚合关系一样,组合关系同样表示整体由部分构成的语义;比如公司由多个部门组成;

但组合关系是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也不存在了;例如, 公司不存在了,部门也将不存在了;

关联关系(association)

关联关系是用一条直线表示的;它描述不同类的对象之间的结构关系;它是一种静态关系, 通常与运行状态无关,一般由常识等因素决定的;它一般用来定义对象之间静态的、天然的结构; 所以,关联关系是一种“强关联”的关系;

比如,乘车人和车票之间就是一种关联关系;学生和学校就是一种关联关系;

关联关系默认不强调方向,表示对象间相互知道;如果特别强调方向,如下图,表示A
知道B,但 B不知道A;

关联关系

在最终代码中,关联对象通常是以成员变量的形式实现的;

依赖关系(dependency)

依赖关系是用一套带箭头的虚线表示的;如下图表示A依赖于B;他描述一个对象在运行期间会用到另一个对象的关系;

依赖关系

与关联关系不同的是,它是一种临时性的关系,通常在运行期间产生,并且随着运行时的变化; 依赖关系也可能发生变化;

显然,依赖也有方向,双向依赖是一种非常糟糕的结构,我们总是应该保持单向依赖,杜绝双向依赖的产生;

在最终代码中,依赖关系体现为类构造方法及类方法的传入参数,箭头的指向为调用关系;依赖关系除了临时知道对方外,还是“使用”对方的方法和属性;

参考链接

  1. 看懂UML类图和时序图,by me115.

提高效率的在线工具

发表于 2019-08-06

在此记录一些常用在线工具,提高工作效率。

百度文库在线下载

在某个文档页面的网址域名后面加上 vvv 三个字母,访问后就可以快捷下载。

比如:

https://wenku.baidu.com/view/3e6d30b2fd0a79563c1e72bd.html

加上 vvv 为:

https://wenku.baiduvvv.com/view/3e6d30b2fd0a79563c1e72bd.html

商品历史价格查询

在电商网站商品详情页的网址域名后面加入vvv三个字母访问后即可查询该商品的历史价格。

例如:

https://detail.tmall.com/item.htm?id=527080261251

添加vvv后变为:

https://detail.tmallvvv.com/item.htm?id=527080261251

参考链接

  1. VVV文档在线导出工具,by vvv.
  2. 商品历史价格查询,by hisprice.

Nodejs调试入门

发表于 2019-07-31 | 更新于 2024-01-21

调试是每个程序员必备的技能,因此选择合适的调试工具能极大地方便我们调试代码。Node.js 的调试方式也有很多,常见的有:

  1. 万能的 console.log
  2. debugger
  3. node –inspect + chrome devtools

本文重点介绍最有用的node –inspect方法。具体步骤如下:

  1. node –inspect app.js
  2. 打开 Chrome 浏览器,访问 chrome://inspect,选择第一步的调试目标。
  3. 在chrome访问源代码,设置断点调试。

参考链接

  1. 《Node.js 调试指南》,by nswbmw.
  2. Node.js Power Tools: 13 Libraries Every Developer Should Know,by Pinjari Rehan.

Mock数据

发表于 2019-07-28 | 更新于 2019-08-08

在实际开发中,最理想的前后端交互方式当然是后端先帮前端 mock 数据,然后前端开发,但现实很骨感,总会因为种种原因,前端需要自己来 mock 假数据。常用的伪造假数据的库有:Mockjs和easy-mock。这两个库有各自问题,因此需要一种新的 mock 假数据方案。

Mockjs

原理是: 拦截了所有的请求并代理到本地,然后进行数据模拟,所以你会发现 network 中没有发出任何的请求。

但它的最大的问题是就是它的实现机制。它会重写浏览器的XMLHttpRequest对象,从而才能拦截所有请求,代理到本地。

大部分情况下用起来还是蛮方便的,但就因为它重写了XMLHttpRequest对象,所以比如progress方法,或者一些底层依赖XMLHttpRequest的库都会和它发生不兼容。

另外,因为是它是本地模拟数据,实际上不会走任何网络请求。所以本地调试起来很蛋疼,只能通过console.log来调试。

easy-mock

天然支持跨域,还是支持MockJs的所有语法。但因为用的人多了,它的免费服务会经常的挂,可以说天天挂。官方的建议是自己搭建服务。如果你的公司整体搭建一个这样的 mock 服务的话也是一个不错的选择。但大部分人可能还是没有这个技术条件的。

新的Mock假数据方案

本地会启动一个mock-server来模拟数据,线上环境还是继续使用mockjs来进行模拟(因为本项目是一个纯前端项目,你也可以自己搭建一个线上 server 来提供数据)。不管是本地还是线上所以的数据模拟都是基于mockjs生成的,所以只要写一套 mock 数据,就可以在多环境中使用。

该方案的好处是,在保留 mockjs 的优势的同时,解决之前的痛点。由于我们的 mock 是完全基于webpack-dev-serve来实现的,所以在你启动前端服务的同时,mock-server就会自动启动,这里还通过 chokidar 来观察 mock 文件夹内容的变化。在发生变化时会清除之前注册的mock-api接口,重新动态挂载新的接口,从而支持热更新。有兴趣的可以自己看一下代码 mock-server.js。由于是一个真正的server,所以你可以通过控制台中的network,清楚的知道接口返回的数据结构。并且同时解决了之前mockjs会重写 XMLHttpRequest对象,导致很多第三方库失效的问题。

vue.config.js中配置本地mock-server服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true
},
proxy: {
// change xxx-api/login => mock/login
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://127.0.0.1:${port}/mock`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
// 输入app为exress实例,即var app = express();
// after: function(app, server) {
// do fancy stuff
// }
after: require('./mock/mock-server.js')
}

参考链接

  1. 手摸手,带你用vue撸后台 系列五(v4.0新版本),by 花裤衩.
  2. Getting Started,by mockjs.

JavaScript最新语法学习笔记

发表于 2019-07-28 | 更新于 2023-04-04

JavaScript目前发展很快,明年都会出一些新的语法特性。为了便于学习,本文对一些遇到的JavaScript语法特性做一些笔记。

JavaScript版本简介

JavaScript 由 Brendan Eich 于 1995 年发明,并于 1997 年成为 ECMA 标准。

ECMAScript 是该语言的官方名称。

从 2015 年起,ECMAScript 按年命名(ECMAScript 2015)。

ECMAScript 版本
版本 官方名称 描述
1 ECMAScript 1 (1997) 第一版。
2 ECMAScript 2 (1998) 只改变编辑方式。
3 ECMAScript 3 (1999) 添加了正则表达式。添加了 try/catch。
4 ECMAScript 4 从未发布过。
5 ECMAScript 5 (2009) 添加了“严格模式”。添加了 JSON 支持。添加了 String.trim()。添加了 Array.isArray()。添加了数组迭代方法。
5.1 ECMAScript 5.1 (2011) 编辑改变。
6 ECMAScript 2015 添加了 let 和 const。添加了默认参数值。添加了 Array.find()。添加了 Array.findIndex()
7 ECMAScript 2016 添加了指数运算符(**)。添加了 Array.prototype.includes。
8 ECMAScript 2017 添加了字符串填充。添加了新的 Object 属性。添加了异步功能。添加了共享内存。
9 ECMAScript 2018 添加了 rest / spread 属性。添加了异步迭代。添加了 Promise.finally()。增加 RegExp。

JavaScript新语法特性

…运算符

es6中引入扩展运算符(…),它用于把一个数组转化为用逗号分隔的参数序列,它常用在不定参数个数时的函数调用,数组合并等情形。

  • 将实现了 Iterator 接口的对象转为数组
1
2
var nodeList = document.querySelectorAll('div');  
var array = [...nodeList];

解构赋值

解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

1
2
3
4
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10
b; // 20
rest; // { c: 30, d: 40 }

async函数

async函数是最新的javascript异步操作方式,初始定义于ES2017。async函数声明用于定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。但是如果你的代码使用了异步函数,它的语法和结构会更像是标准的同步函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 获取用户信息 */
async function userInfoRoute(req, res, next) {
try {
var decoded = jwt.verify(req.body.token.split(' ')[1], appConfig.secretOrPrivateKey);
var user = await models.User.findByPk(decoded.userId);
res.json({
code: 20000,
data: user
});
} catch (err) {
res.send(406, {
message: 'Account and password are incorrect.'
});
}
}

/* 获取用户信息 */
router.post('/user_info', userInfoRoute);

ES6 class

请参考ES6篇 - class 基本语法和ES6-Class如何优雅的进行“糖化”。

参考链接

  1. JavaScript 版本,by w3school.
  2. ES6 扩展运算符 三个点(…),by ten5743.
  3. 解构赋值,by MDN web docs.
  4. async 函数的含义和用法,by 阮一峰.
  5. async function,by MDN web docs.
  6. 从面向对象设计角度,全面解读——JS中的函数与对象、Object与Function、以及原型链与继承,by scott.cgi.
  7. ES6篇 - class 基本语法,by 王锦添.
  8. ES6-Class如何优雅的进行“糖化”,by 前端小魔女.

Vuejs调试入门

发表于 2019-07-28 | 更新于 2022-08-17

每个应用,不论大小,都需要理解程序是如何运行失败的。下面将探讨调试浏览器中运行的通过 Vue CLI 生成的 Vue.js 应用程序。

前提条件

  • Chrome
  • Vue CLI
  • Vue Devtools

浏览器中展示源代码

在可以从 VS Code 调试你的 Vue 组件之前,你需要更新 webpack 配置以构建 source map。做了这件事之后,我们的调试器就有机会将一个被压缩的文件中的代码对应回其源文件相应的位置。这会确保你可以在一个应用中调试,即便你的资源已经被 webpack 优化过了也没关系。

打开 config/index.js 并找到 devtool 属性。将其更新为:

如果你使用的是 Vue CLI 2,请设置并更新 config/index.js 内的 devtool 属性:

1
devtool: 'source-map',

如果你使用的是 Vue CLI 3,请设置并更新 vue.config.js 内的 devtool 属性:

1
2
3
4
5
module.exports = {
configureWebpack: {
devtool: 'source-map'
}
}

调试方法

在Chrome浏览器中调试

利用Chrome浏览器的开发工具,在Vuejs应用源代码中设置断点,进行调试。

在Chrome浏览器中调试

图1 在Chrome浏览器中调试

简单的 debugger 语句

可以直接在代码中使用原生的 debugger 语句。如果你选择了这种方式,请千万记得当你调试完毕之后把这个语句移除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
export default {
data() {
return {
message: ''
}
},
mounted() {
const hello = 'Hello World!'
debugger
this.message = hello
}
};
</script>

参考链接

  1. 在 VS Code 中调试,by vuejs.
  2. 下载并安装vue-devtools(详细步骤),by 鲤鱼砸龙门.
  3. vue调试工具vue-devtools的安装,by web前端.

ESLint工具入门教程

发表于 2019-07-27 | 更新于 2019-09-03

ESLint最初是由Nicholas C. Zakas 于2013年6月创建的开源项目。它的目标是提供一个插件化的javascript代码检测工具。

ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。在许多方面,它和 JSLint、JSHint 相似,除了少数的例外:

  • ESLint 使用 Espree 解析 JavaScript。
  • ESLint 使用 AST 去分析代码中的模式
  • ESLint 是完全插件化的。每一个规则都是一个插件并且你可以在运行时添加更多的规则。

用户指南

先决条件:Node.js (>=6.14), npm version 3+。

你可以使用 npm 安装 ESLint:

1
npm install eslint --save-dev

紧接着你应该设置一个配置文件:

1
./node_modules/.bin/eslint --init

之后,你可以在任何文件或目录上运行ESLint如下:

1
./node_modules/.bin/eslint yourfile.js

也可以在全局而不是本地安装 ESLint (使用 npm install eslint –global)。但是,你使用的任何插件或可共享配置都必须安装在本地。

命令行

命令行工具有几个选项,你可以通过运行 eslint -h 查看所有选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
eslint [options] file.js [file.js] [dir]

Basic configuration:
--no-eslintrc Disable use of configuration from .eslintrc.*
-c, --config path::String Use this configuration, overriding .eslintrc.* config options if present
--env [String] Specify environments
--ext [String] Specify JavaScript file extensions - default: .js
--global [String] Define global variables
--parser String Specify the parser to be used
--parser-options Object Specify parser options
--resolve-plugins-relative-to path::String A folder where plugins should be resolved from, CWD by default

Specifying rules and plugins:
--rulesdir [path::String] Use additional rules from this directory
--plugin [String] Specify plugins
--rule Object Specify rules

Fixing problems:
--fix Automatically fix problems
--fix-dry-run Automatically fix problems without saving the changes to the file system
--fix-type Array Specify the types of fixes to apply (problem, suggestion, layout)

Ignoring files:
--ignore-path path::String Specify path of ignore file
--no-ignore Disable use of ignore files and patterns
--ignore-pattern [String] Pattern of files to ignore (in addition to those in .eslintignore)

Using stdin:
--stdin Lint code provided on <STDIN> - default: false
--stdin-filename String Specify filename to process STDIN as

Handling warnings:
--quiet Report errors only - default: false
--max-warnings Int Number of warnings to trigger nonzero exit code - default: -1

Output:
-o, --output-file path::String Specify file to write report to
-f, --format String Use a specific output format - default: stylish
--color, --no-color Force enabling/disabling of color

Inline configuration comments:
--no-inline-config Prevent comments from changing config or rules
--report-unused-disable-directives Adds reported errors for unused eslint-disable directives

Caching:
--cache Only check changed files - default: false
--cache-file path::String Path to the cache file. Deprecated: use --cache-location - default: .eslintcache
--cache-location path::String Path to the cache file or directory

Miscellaneous:
--init Run config initialization wizard - default: false
--debug Output debugging information
-h, --help Show help
-v, --version Output the version number
--print-config path::String Print the configuration for the given file

修复警告和错误

1
eslint --fix file.js [file.js] [dir]

参考链接

  1. ESLint 可组装的JavaScript和JSX检查工具,by ESLint homepage.
  2. VsCode保存时自动修复Eslint错误,by 前端进阶积累.
上一页1…373839…54下一页

Jack Huang

535 日志
69 标签
© 2026 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse