Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

vuejs组件间通信的方法

发表于 2019-09-02 | 更新于 2023-08-30

Vuejs一个吸引人的地方是可以进行组件化开发,避免了前端开发的无序状态。组件无法单独工作,必然会跟父子组件或兄弟组件之间进行通信,以合作实现某种功能。下面即简单介绍Vuejs组件之间的各种通信方式。

方法一、props/$emit

  • 父组件向子组件传值
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
// 父组件中
<template>
<div class="section">
<com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
<p>{{currentIndex}}</p>
</div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
name: 'HelloWorld',
components: { comArticle },
data() {
return {
currentIndex: -1,
articleList: ['红楼梦', '西游记', '三国演义']
}
},
methods: {
onEmitIndex(idx) {
this.currentIndex = idx
}
}
}
</script>
  • 子组件向父组件传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
</div>
</template>

<script>
export default {
props: ['articles'],
methods: {
emitIndex(index) {
this.$emit('onEmitIndex', index)
}
}
}
</script>

方法二、$emit/$on

方法三、vuex

方法四、$attrs/$listeners

方法五、provide/inject

Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。
provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

需要注意的是:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

虽说provide 和 inject 主要为高阶插件/组件库提供用例,但如果你能在业务中熟练运用,可以达到事半功倍的效果!

方法六、$parent / $children与 ref

参考链接

  1. Vue 组件间通信六种方式(完整版),by 浪里行舟.
  2. 逐行剖析 Vue.js 源码,by 难凉热血.
  3. Vue 组件间通信的八种方式,by ikoala.

客户端使用JS导出CSV文件及中文乱码问题解决方案

发表于 2019-08-27 | 更新于 2020-05-14

在浏览器端无需服务器端支持,直接将JS Array数据导出成CSV文件并下载,是一个常见的开发需求。具体方法如下:

1
2
3
4
5
6
7
8
9
var csvContent= this.$refs.flightInfoGrid.exportdata('csv')
var link = document.createElement('a');
// "\ufeff"是为了解决CSV中文乱码问题
var blob = new Blob(["\ufeff" +csvContent],{type: 'text/csv;charset=utf-8;'});
var url = URL.createObjectURL(blob);
link.href = url;
link.setAttribute('download', 'FlightInfo.csv');
link.click();
document.body.removeChild(link);

中文乱码问题分析

utf-8保存的csv格式要让Excel正常打开的话,必须加入在文件最前面加入BOM(Byte order mark)。

ANSI的话是可以做到正常显示和保存,但是这是有前提的,就是必须在你的电脑(区域和语言设置)把对非Unicode字符处理设置为Chinese,如果是English的话,显示照样是乱码。

Unicode的csv,Excel就根本不支持,打开虽然可以显示不乱码,但是已经不是按逗号显示在不同的单元格里面了,而是按行显示在第一个单元格里面。

BOM(byte-order mark),即字节顺序标记,它是插入到以UTF-8、UTF16或UTF-32编码Unicode文件开头的特殊标记,用来识别Unicode文件的编码类型。具体编码如下表:

BOM Encoding
EF BB BF UTF-8
FE FF UTF-16 (big-endian)
FF FE UTF-16 (little-endian)
00 00 FE FF UTF-32 (big-endian)
FF FE 00 00 UTF-32 (little-endian)

微软建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”来识别文件中使用的编码和字节顺序。BOM的本意不错,但它并不是一个通用标准,从而导致了很多不兼容的问题。

UTF-8

UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字元编码,也是一种前缀码。它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码,属于Unicode标准的一部分,最初由肯·汤普逊和罗布·派克提出。

由于较小值的编码点一般使用频率较高,直接使用Unicode编码效率低下,大量浪费内存空间。UTF-8就是为了解决向后兼容ASCII码而设计,Unicode中前128个字符(与ASCII码一一对应),使用与ASCII码相同的二进制值的单个字节进行编码,这使得原来处理ASCII字元的软体无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他储存或传送文字优先采用的编码方式。

参考链接

  1. Excel 2007 打开 UTF-8 编码 CSV 文件的BUG,by oyi319.
  2. How to export JavaScript array info to csv (on client side)?,by stackoverflow.
  3. blob 导出csv 用execl打开出现乱码,by 黑魔法.
  4. UTF-8,by wikipedia.

如何使用图标icon

发表于 2019-08-25 | 更新于 2022-08-24

在前端网页的世界里,Icon是最基本的元素之一。使用Icon已成为前端开发者最基本的技能。下面将主要介绍利用SVG Sprites技术在前端中使用Icon的方法。

Icon的演化史

Icon最早用img实现,后为了提高效率,减少img请求,出现image sprite技术,实现将多个图片合成一个图片,然后利用 css 的 background-position 定位显示不同的 icon 图标。但该技术维护困难。

随后出现了font库实现页面图标,例如 Font Awesome。目前最常用的是iconfont,里面图标应有尽有,且开源。

iconfont的使用方法

unicode

优势:

  • 兼容性最好,支持ie6+
  • 支持按字体的方式去动态调整图标大小,颜色等等

劣势:

  • 不支持多色图标
  • 在不同的设备浏览器字体的渲染会略有差别

具体使用方法参考手摸手,带你优雅的使用 icon,不建议使用。

font-class

与unicode使用方式相比,具有如下特点:

  • 兼容性良好,支持ie8+
  • 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。

symbol

随着IE浏览器逐渐淡出历史舞台,svg-icon 使用形式慢慢成为主流和推荐的方法,请参考未来必热:SVG Sprites技术介绍。其优点有:

  • 支持多色图标了,不再受单色限制。
  • 支持像字体那样通过font-size,color来调整样式。
  • 支持 ie9+
  • 可利用CSS实现动画。
  • 减少HTTP请求。
  • 矢量,缩放不失真
  • 可以很精细的控制SVG图标的每一部分

具体使用方法如下:

  • 使用SVG Sprite生成SVG雪碧图

SVG雪碧图

图1 SVG雪碧图
  • 加入通用css代码(引入一次就行)
1
2
3
4
5
6
7
8
<style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
  • 挑选相应图标并获取类名,应用于页面
1
2
3
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>

使用svg-icon的好处是再也不用发送woff|eot|ttf| 这些很多个字体库请求了,所有的svg都可以内联在html内。且svg 是一个真正的矢量,不管再怎么的放缩它都不会失真模糊,而且svg可以控制的属性也更加的丰富,也能做出更加生动和复杂的图标。

生成SVG sprite的方法

推荐使用svg-sprite-loader ,它是一个Webpack loader。

1
2
import '@/src/icons/qq.svg; //引入图标
<svg><use xlink:href="#qq" /></svg> //使用图标

自动导入多个SVG

使用 webpack 的 require.context 实现自动导入多个SVG Icon,避免手动一个个引入。

require.context有三个参数:

  • directory:说明需要检索的目录
  • useSubdirectories:是否检索子目录
  • regExp: 匹配文件的正则表达式
1
2
3
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)

参考链接

  1. 手摸手,带你优雅的使用 icon,by 花裤衩.
  2. 未来必热:SVG Sprites技术介绍,by 张鑫旭.
  3. 如何在vue项目中优雅的使用SVG,by SilentLove.
  4. 关于webpack的require.context,by yeyan1996.
  5. requireContext.keys().map(requireContext)在批量导入时的作用,by 咲奈.
  6. 使用require.context实现前端工程自动化,by 心_c2a2.
  7. webpack依赖管理,by docschina.
  8. 懒人神器:svg-sprite-loader实现自己的Icon组件,by
    Yawenina.
  9. SVG on the Web – Implementation Options,by svgontheweb.
  10. SVG Search,by uiset.
  11. SVG图标颜色文字般继承与填充,by 张鑫旭.
  12. How To Create a Beautiful Color Palette for your Website or App,by goodpalette.

USB供电能力简介

发表于 2019-08-20

最近买了个行车记录仪,它通过USB接口供电,要求电源输入为5V2A,即要求电源的输出功率要达到10W。不想直接安装到车上,想插在电脑的USB接口上,测试行车记录仪的功能。那么电脑USB接口的供电能力足够吗?

USB标准供电能力

USB有多个标准,供电能力各不相同:

  • USB1.1 传输速率最高12Mbps; 电源供应 5V 500mA
  • USB2.0 传输速率最高480Mbps; 电源供应 5V 500mA
  • USB3.0 传输速率最高5Gbps; 电源供应 5V 900mA

最新的USB3.0标准输出电压为5V,输出电流最大为900mA,如果超过可能会因发热造成线路损坏。,因此电脑上的标准USB接口无法支持行车记录仪的正常使用。

注意: 输出电压由电源输出决定,但输出电流大小由负载决定。

USB快充技术

目前的快充技术基本有三种:USB-IF组织的USB PD、高通QC、联发科PEP/PE,其他手机厂商的快充方案大多来自这三个。

  • USB PD(快充标准)目前基本绑定在USB3.0(数据传输标准)和USB Type-C(接头物理标准)上了,也得到谷歌和苹果两大巨头的支持,非常有希望成为未来的统一标准。

  • 高通Quick Charge技术则是实际上被中高端智能手机采用最多的,小米、华硕、LG、乐视、中兴、HTC等最近两年的旗舰都是这个标准,三星FastCharge是QC的马甲,索尼也用QC。 由于硬件端和软件端都被强硬规定, 高通最新的QC 4.0已经使用了USB PD协议,成为了USB PD的一个分支。

  • 联发科PEP技术推广成本最低,广泛用于中低端手机,魅族mCharge也是基于PEP。 不过联发科的PE3.0有可能被苹果采用。

参考链接

  1. 关于USB快充你不得不知的几点问题,by EDN.
  2. 手机充电是用电脑 USB 快还是用插座快?,by zhihu.
  3. 瓦特,by wikipedia.
  4. 手机快充是跟数据线有关还是跟充电器有关?,by zhihu.

MSSQL2008中分页查询的实现

发表于 2019-08-17

在后台管理中,涉及分页操作,需要数据库支持limit和offset选项,但在MSSQL2008中这两个选项不支持,不过可以用ROW_NUMBER函数在SQL语句中实现数据分页效果。SQL代码示例如下:

1
2
3
4
5
6
SELECT * FROM  
(SELECT Users.id as id,name,sign,account,audit,roleName,RoleId, Users.deleteFlag as deleteFlag,
ROW_NUMBER() OVER (ORDER BY Users.createdAt) AS Seq
FROM Users LEFT JOIN Roles ON Users.RoleId=Roles.id)Users
Where deleteFlag=0 and
Seq > :offset_num and Seq<= :offset_num+:limit_num

参考链接

  1. How to use Offset . . .Fetch Next in SQL SERVER 2008 R2,by microsoft msdn.

关系数据库中存储树结构及前端还原的方法

发表于 2019-08-17

树形结构很常见,例如组织结构图、线性化讨论等。树形结构中,实例被称为节点(node),每个节点有多个子节点和一个父节点。最上层的节点叫根(root)节点,它没有父节点。最底层的节点叫叶(leaf)节点,它没有子节点。本文主要介绍如何在关系数据库中存储树结构,以及如何从关系数据库中恢复树结构。

关系数据库中存储树结构的方法

层级数据设计方案

在关系数据库中存储树结构主要有以下几种方案:

  • 邻接表模型

最常见的解决方案,在数据库表中添加parent_id字段,再引用同一张表中的其他记录的id。可通过一个外键约束维护这种关系。

优点:增加叶节点、修改节点或子树位置很方便。

缺点:查询节点的所有后代、删除子树很困难。

  • 路径枚举

路径枚举是一个由连续的直接层级关系组成的完整路径。例如/usr/local/lib。

优点:查询节点所有后代、插入新节点很方便。
缺点:依赖应用程序逻辑代码维护路径字符串,验证字符串正确性开销大。受限于字符串长度,树结构无法无限扩展。

  • 嵌套集

嵌套集解决方案是存储子孙节点的相关信息,而不是节点的直接祖先。通常使用两个数字nsleft和nsright编码每个节点,以表示子孙节点信息。

nsleft的数值小于该节点所有后代的ID,同时nsright的值大于该节点所有后代的ID。

确定这三个值(nsleft,ID,nsright)的简单方法是对树进行一次深度优先遍历,在逐层深入过程中依次递增地分配nsleft的值,并在返回时依次递增地分配nsright的值。

优点:查询给定节点祖先和后代很容易,删除非叶子节点,其后代会自动代替被删除节点成为其祖先节点的直接后代。

缺点:不易理解,插入和移动节点复杂。

  • 闭包表

闭包表通过额外的数据库表记录树中节点间父子的关系,包括直接的父子关系、间接的父子关系和指向自己的关系。

层级数据设计比较

层级数据设计比较
设计 表 查询子 查询树 插入 删除 引用完整性
邻接表 1 简单 困难 简单 简单 是
邻接表+递归查询 1 简单 简单 简单 简单 否
路径枚举 1 简单 简单 简单 简单 否
嵌套集 1 困难 简单 困难 困难 否
闭包集 2 简单 简单 简单 简单 是
  • 邻接表设计最简单,如果使用的数据库支持WITH或CONNECT BY PRIOR的递归查询,将使得邻接表查询更为高效。

前端从关系数据库中还原树结构

表结构,使用sequelize的对象表示:

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
'use strict';
module.exports = (sequelize, DataTypes) => {
const Role = sequelize.define('Role', {
id: {
type: DataTypes.STRING(50),
primaryKey: true
},
roleName: {
type: DataTypes.STRING(128),
allowNull: false
},
path: {
type: DataTypes.STRING(512),
allowNull: false,
unique: true,
comment: '角色路径唯一!'
},
deleteFlag:{
type: DataTypes.BOOLEAN,
defaultValue: false
}
}, {});
Role.associate = function(models) {
// associations can be defined here
Role.hasMany(models.User)
};
return Role;
};

递归生成角色树:

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
// 获取第一层节点
function getFirstLevel(recordList){
var firstLevelList=[];
for(let i=0;i< recordList.length;i++){
let record=recordList[i]
if (record.path.length === 2 && record.path.split('')[1] === '/' && parseInt(record.path.split('')[0])>=0){
record.label=record.roleName
firstLevelList.push(record)
}
}
return firstLevelList
}

// 指定根节点,递归生成角色树
function recursiveTree(parentRecord,recordList){
for (let i = 0; i < recordList.length; i++){
let record = recordList[i]
if(parentRecord.path==record.path.slice(0,-2)){
record=recursiveTree(record,recordList)
if (parentRecord.children==undefined){
parentRecord.children=[]
}
parentRecord.children.push(record)
}
}
parentRecord.label = parentRecord.roleName
return parentRecord
}

// 生成角色树
export function parseRoleTree(recordList){
var result = getFirstLevel(recordList);

for (let i=0;i<result.length;i++){
parent = result[i]
parent = recursiveTree(parent, recordList)
}

return result;
}

参考链接

  1. java递归生成树形结构菜单,by 伊宇紫.
  2. Bill Karwin著,谭振林,Push Chen译. SQL反模式[M].人民邮电出版社.

网页布局方法入门

发表于 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.
上一页1…353637…53下一页

Jack Huang

521 日志
67 标签
© 2025 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse