Qt Creator中提供了各种快捷键来加快开发进程。
如果需要查看或自定义快捷键,选择工具->选项->环境->键盘。快捷键按类别列出,可以在过滤器(Filter)处输入命令名称、标签名称或快捷键名称,来快速定位想要查找的快捷键。
以红颜色显示的快捷键与某些功能相关联。Qt Creator可以在当前上下文中执行该功能。如果几个功能用同一个快捷键,那么就会产生冲突,Qt Creator不会执行任何功能。
键盘快捷键也可能与窗口管理器使用的快捷键冲突。这种情况下,Qt Creator的快捷键就不会起作用。通常,可以在窗口管理器中配置快捷键,但如果不行,则可以改变Qt Creator的快捷键。例如,在Ubuntu 11.10窗口管理器中使用了F10,因此默认的Qt Creator的键盘快捷键F10(单步调试)就不会在该系统上运行。
选择工具->选项->环境->键盘。
从列表中选择一个命令。
在快捷键设置的”Key sequence”处,有以下选择:
(1) 输入与选定命令关联的快捷键。
(2) 选择”Record”,按下要设置的快捷键,选择”Stop Recording”来完成录制。
恢复默认的快捷键,选择”Reset”。
Qt Creator允许使用不同的键盘快捷键映射方案:
要导入键盘快捷键映射方案,单击”Import…”,然后选择要导入的快捷键映射方案.kms文件。
要导出键盘快捷键映射方案,单击”Export…”,然后选择要导出.kms文件的位置。
默认快捷键
下表列出了默认的快捷键,它们是由动作进行分类。
【领QT开发教程学习资料,点击→「链接」←莬费领取,先码住不迷路~】
动作 | 快捷键 |
打开文件或项目(O)… | Ctrl+O |
新建文件或项目(N)… | Ctrl+N |
在外部编辑器中打开 | Alt+V, Alt+I |
全选(A) | Ctrl+A |
删除 | Del |
剪切(T) | Ctrl+X |
复制(C) | Ctrl+C |
粘贴 | Ctrl+V |
撤销 | Ctrl+Y |
打印 | Ctrl+P |
保存 | Ctrl+S |
保存所有文件(L)… | CTRL+Shift+S |
关闭窗口 | Ctrl+W |
关闭所有文件 | Ctrl+Shift+W |
关闭当前文件 | Ctrl+F4 |
后退 | Alt+Left |
前进 | Alt+Right |
跳转行(G)… | Ctrl+L |
历史中下个打开的文件 | Ctrl+Shift+Tab |
切换到其他分栏 | Ctrl+E, O |
历史中先前打开的文件 | Ctrl+Tab |
激活定位器 | Ctrl+K |
切换到欢迎模式 | Ctrl+1 |
切换到编辑模式 | Ctrl+2 |
切换到设计模式 | Ctrl+3 |
切换到调试模式 | Ctrl+4 |
切换到项目模式 | Ctrl+5 |
切换到分析模式 | Ctrl+6 |
切换到帮助模式 | Ctrl+7 |
切换问题窗口 | Alt+1 (Cmd+1 on OS X) |
切换搜索结果窗口 | Alt+2 (Cmd+2 on OS X) |
切换应用程序输出窗口 | Alt+3 (Cmd+3 on OS X) |
切换编译输出窗口 | Alt+4 (Cmd+4 on OS X) |
切换其它输出窗口 | Alt+编号 (Cmd+编号 on OS X) 编号为”输出窗口”中的编号 |
激活书签窗口 | Alt+M |
激活文件系统窗口 | Alt+Y |
激活打开文档窗口 | Alt+O |
最大化输出窗口 | Alt+9 |
输出窗口-下一项 | F6 |
输出窗口-上一项 | Shift+F6 |
激活项目窗口 | Alt+X |
全屏 | Ctrl+Shift+F11 |
切换侧边栏 | Alt+0 (Cmd+0 on OS X) |
撤销 | Ctrl+Z |
移动到编辑模式。在编辑模式下:第一次按下将焦点移动到编辑器中,第二次按下关闭辅助窗口 | Esc |
退出Qt Creator | Ctrl+Q |
动作 | 快捷键 |
自动缩进 | Ctrl+I |
折叠 | Ctrl+< |
展开 | Ctrl+> |
在此范围内触发完成 | Ctrl+Space |
复制行 | Ctrl+Ins |
复制到行下 | Ctrl+Alt+Down |
复制到行上 | Ctrl+Alt+Up |
查看剪切板历史 | Ctrl+Shift+V |
剪切行 | Shift+Del |
追加行 | Ctrl+J |
在当前行上方插入新行 | Ctrl+Shift+Enter |
在当前行下方插入新行 | Ctrl+Enter |
减小字体大小 | Ctrl+- (Ctrl+鼠标滚轮向下) |
增加字体大小 | Ctrl++ (Ctrl+鼠标滚轮向上) |
重置字体大小 | Ctrl+0 |
切换Vim的编辑风格 | Alt+V, Alt+V |
分栏 | Ctrl+E, 2 |
左右分栏 | Ctrl+E, 3 |
删除所有分割 | Ctrl+E, 1 |
删除当前分割 | Ctrl+E, 0 |
全选 | Ctrl+A |
跳转至块结尾 | Ctrl+] |
跳转至块开始 | Ctrl+[ |
跳转至以}结尾的块 | Ctrl+} |
跳转至以{开始的块 | Ctrl+{ |
向下移动当前行 | Ctrl+Shift+Down |
向上移动当前行 | Ctrl+Shift+Up |
在此范围激活重构 | Alt+Enter |
重新包装段 | Ctrl+E, R |
选择当前块,第二次按下选择父块 | Ctrl+U |
启用文本换行 | Ctrl+E, Ctrl+W |
注释选中的内容 | Ctrl+/ |
可视化的空白 | Ctrl+E, Ctrl+V |
调整大小 | Ctrl+J |
网格布局 | Ctrl+G |
水平布局 | Ctrl+H |
垂直布局 | Ctrl+L |
预览 | Alt+Shift+R |
编辑信号和槽 | F4 |
切换书签 | CTRL+M |
下个书签 | Ctrl+. |
上个书签 | Ctrl+, |
取得代码片段 | Alt+C, Alt+F |
粘贴代码片段 | Alt+C, Alt+P |
查找所有引用 | Ctrl+Shift+U |
跟随鼠标下的符号 | F2 |
重命名光标所在符号 | Ctrl+Shift+R |
切换函数声明/定义 | Shift+F2 |
打开类型层次窗口 | Ctrl+Shift+T |
切换头文件/源文件 | F4 |
选中的文本变小写 | Alt+U |
选中的文本变大写 | Alt+Shift+U |
在JavaScript中执行静态检查来查找共同问题 | Ctrl+Shift+C |
查找和替换 | Ctrl+F |
向下查找 | F3 |
向上查找 | Shift+F3 |
查找选中文本下一次出现 | Ctrl+F3 |
查找选中文本上一次出现 | Ctrl+Shift+F3 |
替换和查找下一个 | Ctrl+= |
打开高级搜索 | Ctrl+Shift+F |
录制宏 | Alt+( |
停止录制宏 | Alt+) |
播放最近的宏 | Alt+R |
显示Qt Quick工具栏 | Ctrl+Alt+Space |
在FakeVim模式执行用户行为 | Alt+V, n, 其中n是用户动作的数量, 从1到9 |
动作 | 快捷键 |
切换背景 | Ctrl+[ |
显示轮廓线 | Ctrl+] |
放大 | Ctrl++ |
缩小 | Ctrl+- |
适应屏幕 | Ctrl+= |
原始大小 | Ctrl+0 |
动作 | 快捷键 |
打开定义所选组件的QML文件 | F2 |
切换代码编辑器/可视化编辑器 | F4 |
切换左侧侧边栏 | Ctrl+Alt+0 |
切换右侧侧边栏 | Ctrl+Alt+Shift+0 |
动作 | 快捷键 |
开始/继续调试 | F5 |
停止调试 | Shift+F5 |
单步跳过 | F10 |
单步进入 | F11 |
单步跳出 | Shift+F11 |
切换断点 | F9 |
运行到选择的函数 | Ctrl+F6 |
执行到行 | Ctrl+F10 |
相反方向 | F12(暂无) |
动作 | 快捷键 |
构建项目 | Ctrl+B |
构建所有项目 | Ctrl+Shift+B |
新建项目… | Ctrl+Shift+N |
载入项目… | Ctrl+Shift+O |
选择构建套件(Kit)构建和运行项目 | Ctrl+T |
运行 | Ctrl+R |
动作 | 快捷键 |
上下文相关帮助 | F1 |
在帮助模式下激活内容 | Ctrl+T(暂无) |
添加书签 | Ctrl+M |
在帮助模式下激活索引 | Ctrl+I(暂无) |
重置字体大小 | Ctrl+0(暂无) |
在帮助模式下激活查找 | Ctrl+S(暂无) |
言
当我们拿到一个 PC 端页面的设计稿的时候,往往会发现页面的布局并不是随意的,而是遵循的一定的规律:行与行之间会以某种方式对齐。对于这样的设计稿,我们可以使用栅格布局来实现。
早在 Bootstrap 一统江湖的时代,栅格布局的概念就已深入人心,整个布局就是一个二维结构,包括列和行, Bootstrap 会把屏幕分成 12 列,还提供了一些非常方便的 CSS 名让我们来指定每列占的宽度百分比,并且还通过媒体查询做了不同屏幕尺寸的适应。
element-ui 也实现了类似 Bootstrap 的栅格布局系统,那么基于 Vue 技术栈,它是如何实现的呢?
需求分析
和 Bootstrap 12 分栏不同的是,element-ui 目标是提供的是更细粒度的 24 分栏,迅速简便地创建布局,写法大致如下:
<el-row> <el-col>aaa</el-col> <el-col>bbb</el-col> </el-row> <el-row> ... </el-row> 复制代码
这就是二维布局的雏形,我们会把每个列的内容写在 <el-col></el-col> 之间,除此之外,我们还需要支持控制每个 <el-col> 所占的宽度自由组合布局;支持分栏之间存在间隔;支持偏移指定的栏数;支持分栏不同的对齐方式等。
了解了 element-ui Layout 布局组件的需求后,我们来分析它的设计和实现。
设计和实现
组件的渲染
回顾前面的例子,从写法上看,我们需要设计 2 个组件,el-row 和 el-col 组件,分别代表行和列;从 Vue 的语法上看,这俩组件都要支持插槽(因为在自定义组件标签内部的内容都分发到组件的 slot 中了);从 HTML 的渲染结果上看,我们希望模板会渲染成:
<div class="el-row"> <div class="el-col">aaa</div> <div class="el-col">bbb</div> </div> <div class="el-row"> ... </div> 复制代码
想达到上述需求,组件的模板可以非常简单。
el-row 组件模板代码如下:
<div class="el-row"> <slot></slot> </div> 复制代码
el-col 组件代码如下:
<div class="el-col"> <slot></slot> </div> 复制代码
这个时候,新需求来了,我希望 el-row 和 el-col 组件不仅能渲染成 div,还可以渲染成任意我想指定的标签。 那么除了我们要支持一个 tag 的 prop 之外,仅用模板是难以实现了。
我们知道 Vue 的模板最终会编译成 render 函数,Vue 的组件也支持直接手写 render 函数,那这个需求用 render 函数实现就非常简单了。
el-row 组件:
render(h) {
return h(this.tag, {
class: [
'el-row',
]
}, this.$slots.default);
}
复制代码
el-col 组件:
render(h) {
return h(this.tag, {
class: [
'el-col',
]
}, this.$slots.default);
}
复制代码
其中,tag 是定义在 props 中的,h 是 Vue 内部实现的 $createElement 函数,如果对 render 函数语法还不太懂的同学,建议去看 Vue 的官网文档 render 函数部分。
了解了组件是如何渲染之后,我们来给 Layout 组件扩展一些 feature 。
分栏布局
Layout 布局的主要目标是支持 24 分栏,即一行能被切成 24 份,那么对于每一个 el-col ,我们想要知道它的占比,只需要指定它在 24 份中分配的份数即可。
于是我们给刚才的示例加上一些配置:
<el-row> <el-col :span="8">aaa</el-col> <el-col :span="16">bbb</el-col> </el-row> <el-row> ... </el-row> 复制代码
来看第一行,第一列 aaa 占 8 份,第二列 bbb 占 16 份。总共宽度是 24 份,经过简单的数学公式计算,aaa 占总宽度的 1/3,而 bbb 占总宽度的 2/3,进而推导出每一列指定 span 份就是占总宽度的 span/24。
默认情况下 div 的宽度是 100% 独占一行的,为了让多个 el-col 在一行显示,我们只需要让每个 el-col 的宽占一定的百分比,即实现了分栏效果。设置不同的宽度百分比只需要设置不同的 CSS 即可实现,比如当某列占 12 份的时候,那么它对应的 CSS 如下:
.el-col-12 {
width: 50%
}
复制代码
为了满足 24 种情况,element-ui 使用了 sass 的控制指令,配合基本的计算公式:
.el-col-0 {
display: none;
}
@for $i from 0 through 24 {
.el-col-#{$i} {
width: (1 / 24 * $i * 100) * 1%;
}
}
复制代码
所以当我们给 el-col 组件传入了 span 属性的时候,只需要给对应的节点渲染生成对应的 CSS 即可,于是我们可以扩展 render 函数:
render(h) {
let classList = [];
classList.push(`el-col-${this.span}`);
return h(this.tag, {
class: [
'el-col',
classList
]
}, this.$slots.default);
}
复制代码
这样只要指定 span 属性的列就会添加 el-col-${span} 的样式,实现了分栏布局的需求。
分栏间隔
对于栅格布局来说,列与列之间有一定间隔空隙是常见的需求,这个需求的作用域是行,所以我们应该给 el-row 组件添加一个 gutter 的配置,如下:
<el-row :gutter="20"> <el-col :span="8">aaa</el-col> <el-col :span="16">bbb</el-col> </el-row> <el-row> ... </el-row> 复制代码
有了配置,接下来如何实现间隔呢?实际上非常简单,想象一下,2 个列之间有 20 像素的间隔,如果我们每列各往一边收缩 10 像素,是不是看上去就有 20 像素了呢。
先看一下 el-col 组件的实现:
computed: {
gutter() {
let parent = this.$parent;
while (parent && parent.$options.componentName !== 'ElRow') {
parent = parent.$parent;
}
return parent ? parent.gutter : 0;
}
},
render(h) {
let classList = [];
classList.push(`el-col-${this.span}`);
let style = {};
if (this.gutter) {
style.paddingLeft = this.gutter / 2 + 'px';
style.paddingRight = style.paddingLeft;
}
return h(this.tag, {
class: [
'el-col',
classList
]
}, this.$slots.default);
}
复制代码
这里使用了计算属性去计算 gutter,其实是比较有趣的,它通过 $parent 往外层查找 el-row,获取到组件的实例,然后获取它的 gutter 属性,这样就建立了依赖关系,一旦 el-row 组件的 gutter 发生变化,这个计算属性再次被访问的时候就会重新计算,获取到新的 gutter。
其实,想在子组件去获取祖先节点的组件实例,我更推荐使用 provide/inject 的方式去把祖先节点的实例注入到子组件中,这样子组件可以非常方便地拿到祖先节点的实例,比如我们在 el-row 组件编写 provide:
provide() {
return {
row: this
};
}
复制代码
然后在 el-col 组件注入依赖:
inject: ['row'] 复制代码
这样在 el-col 组件中我们就可以通过 this.row 访问到 el-row 组件实例了。
使用 provide/inject 的好处在于不论组件层次有多深,子孙组件可以方便地访问祖先组件注入的依赖。当你在编写组件库的时候,遇到嵌套组件并且子组件需要访问父组件实例的时候,避免直接使用 this.$parent,尽量使用 provide/inject,因为一旦你的组件嵌套关系发生变化,this.$parent 可能就不符合预期了,而 provide/inject 却不受影响(只要祖先和子孙的关系不变)。
在 render 函数中,我们会根据 gutter 计算,给当前列添加了 paddingLeft 和 paddingRight 的样式,值是 gutter 的一半,这样就实现了间隔 gutter 的效果。
那么这里能否用 margin 呢,答案是不能,因为设置 margin 会占用外部的空间,导致每列的占用空间变大,会出现折行的情况。
render 过程也是有优化的空间,因为 style 是根据 gutter 计算的,那么我们可以把 style 定义成计算属性,这样只要 gutter 不变,那么 style 就可以直接拿计算属性的缓存,而不用重新计算,对于 classList 部分,我们同样可以使用计算属性。组件 render 过程的一个原则就是能用计算属性就用计算属性。
再来看一下 el-row 组件的实现:
computed: {
style() {
const ret = {};
if (this.gutter) {
ret.marginLeft = `-${this.gutter / 2}px`;
ret.marginRight = ret.marginLeft;
}
return ret;
}
},
render(h) {
return h(this.tag, {
class: [
'el-row',
],
style: this.style
}, this.$slots.default);
}
复制代码
由于我们是通过给每列添加左右 padding 的方式来实现列之间的间隔,那么对于第一列和最后一列,左边和右边也会多出来 gutter/2 大小的间隔,显然是不符合预期的,所以我们可以通过设置左右负 margin 的方式填补左右的空白,这样就完美实现了分栏间隔的效果。
偏移指定的栏数
如图所示,我们也可以指定某列的偏移,由于作用域是列,我们应该给 el-col 组件添加一个 offset 的配置,如下:
<el-row :gutter="20"> <el-col :offset="8" :span="8">aaa</el-col> <el-col :span="8">bbb</el-col> </el-row> <el-row> ... </el-row> 复制代码
直观上我们应该用 margin 来实现偏移,并且 margin 也是支持百分比的,因此实现这个需求就变得简单了。
我们继续扩展 el-col 组件:
render(h) {
let classList = [];
classList.push(`el-col-${this.span}`);
classList.push(`el-col-offset-${this.offset}`);
let style = {};
if (this.gutter) {
style.paddingLeft = this.gutter / 2 + 'px';
style.paddingRight = style.paddingLeft;
}
return h(this.tag, {
class: [
'el-col',
classList
]
}, this.$slots.default);
}
复制代码
其中 offset 是定义在 props 中的,我们根据传入的 offset 生成对应的 CSS 添加到 DOM 中。element-ui 同样使用了 sass 的控制指令,配合基本的计算公式来实现这些 CSS 的定义:
@for $i from 0 through 24 {
.el-col-offset-#{$i} {
margin-left: (1 / 24 * $i * 100) * 1%;
}
}
复制代码
对于不同偏移的分栏数,会有对应的 margin 百分比,就很好地实现分栏偏移需求。
对齐方式
当一行分栏的总占比和没有达到 24 的时候,我们是可以利用 flex 布局来对分栏做灵活的对齐。
对于不同的对齐方式 flex 布局提供了 justify-content 属性,所以对于这个需求,我们可以对 flex 布局做一层封装即可实现。
由于对齐方式的作用域是行,所以我们应该给 el-row 组件添加 type 和 justify 的配置,如下:
<el-row type="flex" justify="center"> <el-col :span="8">aaa</el-col> <el-col :span="8">bbb</el-col> </el-row> <el-row> ... </el-row> 复制代码
由于我们是对 flex 布局的封装,我们只需要根据传入的这些 props 去生成对应的 CSS,在 CSS 中定义 flex 的布局属性即可。
我们继续扩展 el-row 组件:
render(h) {
return h(this.tag, {
class: [
'el-row',
this.justify !== 'start' ? `is-justify-${this.justify}` : '',
{ 'el-row--flex': this.type === 'flex' }
],
style: this.style
}, this.$slots.default);
}
复制代码
其中 type 和 justify 是定义在 props 中的,我们根据它们传入的值生成对应的 CSS 添加到 DOM 中,接着我们需要定义对应的 CSS 样式:
@include b(row) {
position: relative;
box-sizing: border-box;
@include utils-clearfix;
@include m(flex) {
display: flex;
&:before,
&:after {
display: none;
}
@include when(justify-center) {
justify-content: center;
}
@include when(justify-end) {
justify-content: flex-end;
}
@include when(justify-space-between) {
justify-content: space-between;
}
@include when(justify-space-around) {
justify-content: space-around;
}
}
}
复制代码
element-ui 在编写 sass 的时候主要遵循的是 BEM 的命名规则,并且编写了很多自定义 @mixin 来配合样式名的定义。
这里我们来花点时间来学习一下它们,element-ui 的自定义 @mixin 定义在 pacakages/theme-chalk/src/mixins/ 目录中,我并不会详细解释这里面的关键字,如果你对 sass 还不熟悉,我建议在学习这部分内容的时候配合 sass 的官网文档看。
mixins/config.scss 中定义了一些全局变量:
$namespace: 'el'; $element-separator: '__'; $modifier-separator: '--'; $state-prefix: 'is-'; 复制代码
mixins/mixins.scss 中定义了 BEM 的自定义 @mixin,先来看一下定义组件样式的 @mixin b:
@mixin b($block) {
$B: $namespace+'-'+$block !global;
.#{$B} {
@content;
}
}
复制代码
这个 @mixin 很好理解,$B 是内部定义的变量,它的值通过 $namespace+'-'+$block 计算得到,注意这里有一个 !global 关键字,它表示把这个局部变量变成全局的,意味着你也可以在其它 @mixin 中引用它。
通过 @include 我们就可以去引用这个 @mixin,结合我们的 case 来看:
@include b(row) {
// xxx content
}
复制代码
会编译成:
.el-row {
// xxx content
}
复制代码
再来看表示修饰符的 @mixin m:
@mixin m($modifier) {
$selector: &;
$currentSelector: "";
@each $unit in $modifier {
$currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
}
@at-root {
#{$currentSelector} {
@content;
}
}
}
复制代码
这里是允许传入的 $modifier 有多个,所以内部用了 @each,& 表示父选择器,$selector 和 $currentSelector 是内部定义的 2 个局部变量,结合我们的 case 来看:
@mixin b(row) {
@include m(flex) {
// xxx content
}
}
复制代码
会编译成:
.el-row--flex {
// xxx content
}
复制代码
有同学可能会疑问,难道不是:
.el-row {
.el-row--flex {
// xxx content
}
}
复制代码
其实并不是,因为我们在该 @mixin 的内部使用了 @at-root 指令,它会把样式规则定义在根目录下,而不是嵌套在其父选择器下。
最后来看一下表示同级样式的 @mixin when:
@mixin when($state) {
@at-root {
&.#{$state-prefix + $state} {
@content;
}
}
}
复制代码
这个 @mixin 也很好理解,结合我们的 case 来看:
@mixin b(row) {
@include m(flex) {
@include when(justify-center) {
justify-content: center;
}
}
}
复制代码
会编译成:
.el-row--flex.is-justify-center {
justify-content: center;
}
复制代码
关于 BEM 的 @mixin,常用的还有 @mixin e,用于定义组件内部一些子元素样式的,感兴趣的同学可以自行去看。
再回到我们的 el-row 组件的样式,我们定义了几种flex 布局的对齐方式,然后通过传入不同的 justify 来生成对应的样式,这样我们就很好地实现了灵活对齐分栏的需求。
响应式布局
element-ui 参照了 Bootstrap 的响应式设计,预设了五个响应尺寸:xs、sm、md、lg 和 xl。
允许我们在不同的屏幕尺寸下,设置不同的分栏配置,由于作用域是列,所以我们应该给 el-col 组件添加 xs xs、sm、md、lg 和 xl 的配置,如下:
<el-row type="flex" justify="center"> <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">aaa</el-col> <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">bbb</el-col> <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">ccc</el-col> <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">ddd</el-col> </el-row> <el-row> ... </el-row> 复制代码
同理,我们仍然是通过这些传入的 props 去生成对应的 CSS,在 CSS 中利用媒体查询去实现响应式。
我们继续扩展 el-col 组件:
render(h) {
let classList = [];
classList.push(`el-col-${this.span}`);
classList.push(`el-col-offset-${this.offset}`);
['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => {
classList.push(`el-col-${size}-${this[size]}`);
});
let style = {};
if (this.gutter) {
style.paddingLeft = this.gutter / 2 + 'px';
style.paddingRight = style.paddingLeft;
}
return h(this.tag, {
class: [
'el-col',
classList
]
}, this.$slots.default);
}
复制代码
其中,xs、sm、md、lg 和 xl 是定义在 props 中的,实际上 element-ui 源码还允许传入一个对象,可以配置 span 和 offset,但这部分代码我就不介绍了,无非就是对对象的解析,添加对应的样式。
我们来看一下对应的 CSS 样式,以 xs 为例:
@include res(xs) {
.el-col-xs-0 {
display: none;
}
@for $i from 0 through 24 {
.el-col-xs-#{$i} {
width: (1 / 24 * $i * 100) * 1%;
}
.el-col-xs-offset-#{$i} {
margin-left: (1 / 24 * $i * 100) * 1%;
}
}
}
复制代码
这里又定义了表示响应式的 @mixin res,我们来看一下它的实现:
@mixin res($key, $map: $--breakpoints) {
// 循环断点Map,如果存在则返回
@if map-has-key($map, $key) {
@media only screen and #{inspect(map-get($map, $key))} {
@content;
}
} @else {
@warn "Undefeined points: `#{$map}`";
}
}
复制代码
这个 @mixns 主要是查看 $map 中是否有 $key,如果有的话则定义一条媒体查询规则,如果没有则抛出警告。
$map 参数的默认值是 $--breakpoints,定义在 pacakges/theme-chalk/src/common/var.scss 中:
$--sm: 768px !default; $--md: 992px !default; $--lg: 1200px !default; $--xl: 1920px !default; $--breakpoints: ( 'xs' : (max-width: $--sm - 1), 'sm' : (min-width: $--sm), 'md' : (min-width: $--md), 'lg' : (min-width: $--lg), 'xl' : (min-width: $--xl) ); 复制代码
结合我们的 case 来看:
@include res(xs) {
.el-col-xs-0 {
display: none;
}
@for $i from 0 through 24 {
.el-col-xs-#{$i} {
width: (1 / 24 * $i * 100) * 1%;
}
.el-col-xs-offset-#{$i} {
margin-left: (1 / 24 * $i * 100) * 1%;
}
}
}
复制代码
会编译成:
@media only screen and (max-width: 767px) {
.el-col-xs-0 {
display: none;
}
.el-col-xs-1 {
width: 4.16667%
}
.el-col-xs-offset-1 {
margin-left: 4.16667%
}
// 后面循环的结果太长,就不贴了
}
复制代码
其它尺寸内部的样式定义规则也是类似,这样我们就通过媒体查询定义了各个屏幕尺寸下的样式规则了。通过传入 xs、sm 这些属性的值不同,从而生成不同样式,这样在不同的屏幕尺寸下,可以做到分栏的占宽不同,很好地满足了响应式需求。
基于断点的隐藏类
Element 额外提供了一系列类名,用于在某些条件下隐藏元素,这些类名可以添加在任何 DOM 元素或自定义组件上。
我们可以通过引入单独的 display.css:
import 'element-ui/lib/theme-chalk/display.css'; 复制代码
它包含的类名及其含义如下:
我们来看一下它的实现,看一下 display.scss:
.hidden {
@each $break-point-name, $value in $--breakpoints-spec {
&-#{$break-point-name} {
@include res($break-point-name, $--breakpoints-spec) {
display: none !important;
}
}
}
}
复制代码
实现很简单,对 $--breakpoints-spec 遍历,生成对应的 CSS 规则,$--breakpoints-spec 定义在 pacakges/theme-chalk/src/common/var.scss 中:
$--breakpoints-spec: (
'xs-only' : (max-width: $--sm - 1),
'sm-and-up' : (min-width: $--sm),
'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})",
'sm-and-down': (max-width: $--md - 1),
'md-and-up' : (min-width: $--md),
'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})",
'md-and-down': (max-width: $--lg - 1),
'lg-and-up' : (min-width: $--lg),
'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})",
'lg-and-down': (max-width: $--xl - 1),
'xl-only' : (min-width: $--xl),
);
复制代码
我们以 xs-only 为例,编译后生成的 CSS 规则如下:
.hidden-xs-only {
@media only screen and (max-width:767px) {
display: none !important;
}
}
复制代码
本质上还是利用媒体查询定义了这些 CSS 规则,实现了在某些屏幕尺寸下隐藏的功能。
总结
其实 Layout 布局还支持了其它一些特性,我不一一列举了,感兴趣的同学可以自行去看。Layout 布局组件充分利用了数据驱动的思想,通过数据去生成对应的 CSS,本质上还是通过 CSS 满足各种灵活的布局。
学习完这篇文章,你应该彻底弄懂 element-ui Layout 布局组件的实现原理,并且对 sass 的 @mixin 以及相关使用到的特性有所了解,对组件实现过程中可以优化的部分,应该有自己的思考。
把不会的东西学会了,那么你就进步了,如果你觉得这类文章有帮助,也欢迎把它推荐给你身边的小伙伴。
HTML5确实非常强大,小编之前也分享过很多基于HTML5 Canvas的动画特效。但是你是否知道我们可以利用纯CSS制作一些很酷的动画效果?对,CSS3可以做到。2D炫酷动效是需要技术积累的,这里有4个重点大家可以着重掌握一下:
CSS3 2D炫酷动效
1. 了解canvas动效原理
就是不断清除画布再绘制,清除再绘制。
2. 一定的JS基本功
了解实例对象的属性如何获取,以及上下文this指代什么;如何有效地遍历以及数据存储等等。
3. 知道如何运用一些动画算法
4. 了解canvas所有API,尤其基本的绘图API
如何使用canvas绘制线条,绘制圆,绘制不规则图形;如何描边,如何填充,如何控制透明度等等,都是必须要牢固掌握的。因为,无论是是圆圈圈,还是角星星,都离不开这些基础的API绘制。还需要了解图像绘制API,例如,本demo的星星,实际上还可以基于图片资源绘制,难度会稍微降低些,但可能要牺牲点效果。
css3选择器的用途与重要性
css3选择器是基于css2的一种创新,在css2的基础上增加了目标伪类选择器、语言伪类选择器、UI元素状态伪类选择器、结构伪类选择器、否定伪类选择器。
大致有以下三点作用:
1.网页代码更简洁,结构更清晰。
2.免除起名的烦恼。
3.避免css式样不生效。
在主页制作时采用css3技术,可以有效地对页面的布局、字体、颜色、背景和其它效果实现更加精确的控制。只要对相应的代码做一些简单的修改,就可以改变同一页面的不同部分,或者页数不同的网页的外观和格式。css3提供了非常多新途径去改善的设计工作,且做了不少重要的变化。
css3将完全向后兼容,所以没有必要修改现在的设计来让它们继续运作。网络浏览器也还将继续支持css2。对我们来说,css3主要的影响是将可以使用新的可用的选择器和属性,这些会允许实现新的设计效果(譬如动态和渐变),而且可以很简单的设计出现在的设计效果(比如说使用分栏)。
与css相比,使用css3有什么好处呢?最明显的就是css3能让页面看起来非常炫、非常酷,使网站设计锦上添花,但它的好处远远不止这些。在大多数情况下,使用css3不仅有利于开发与维护,还能提高网站的性能。与此同时,还能增加网站的可访问性、可用性,使网站能适配更多的设备,甚至还可以优化网站SEO,提高网站的搜索排名结果。
现在网站重视的更多的是用户体验,而优秀的动效则能使你的应用更具交互性,从而吸引更多用户的使用。在网站中加入一些动效会让整个页面看起来很有动感。但是如果你对CSS3中定义动效还不熟练,就需要多加学习、多加练习。
*请认真填写需求信息,我们会在24小时内与您取得联系。