开篇
本来想把el-row和el-col放在同一篇来写,然鹅发现对于一个菜鸟来说,简单的el-row(它不简单)已经让我学到很多。
内容
这是我的row.js文件
模仿代码中均以el-test 替换el, 目的是为了边模仿边测试和el组件的效果对比
export default {
// 驼峰命名法
name: 'ElTestRow',
props: {
gutter: Number,
// 渲染的标签类型
tag: {
type: String,
default: 'div'
},
//是否使用flex布局
type: String,
justify: {
type: String,
default: 'start'
},
align: {
type: String,
default: 'top'
}
},
render(h) {
let classStyle = []
let style = {}
//为什么在设置gutter的时候 父组件要设置margin? 是为了保证col第一个和最后一个仍然贴紧row的左侧和右侧 但是这样做会撑开el-row
if (this.gutter) {
style.marginLeft = `-${this.gutter/2}px`
style.marginRight = style.marginLeft
}
classStyle = [
'el-test-row',
this.justify !== 'start' ? `is-justify-content-${this.justify}` : '',
this.align !== 'top' ? `is-align-items-${this.align}` : '',
{'el-test-row-flex': this.type === 'flex'}
]
return h(this.tag,{
class: classStyle,
style
}, this.$slots.default)
},
}
用render函数形式创建插件el-row。在VUE官网上有说Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。 。在以前看这句话,说我感觉就是render有更快的编译渲染速度?(感觉是这个描述)。后来听了尤大在Vue conf上的演讲发现并不是这样。 使用render并不是因为它有更快的编译速度,相反,template模板更快些。render的好处在于它足够灵活,这个你可以参见vue官网的例子render。 我们举个例子吧
<div id="demo">
<p class="demo1">静态的我</p>
<p class="demo1">静态的我</p>
<p class="demo1">{{message}}</p>
<p class="demo1">静态的我</p>
<p class="demo1">静态的我</p>
<p class="demo1">静态的我</p>
</div>
像这样的一个静态模板,如果你要做视图更新的时候,你觉得怎样消耗最小?我们只用检测
<p class="demo1">{{message}}</p>这一行的更新就可以了。但是render不一样。render在每次message改变的时候都动态重新生成模板,因此我们不能直接追踪到message的变化,并且在这个例子上,性能消耗render会更高,(它重绘了页面)。因此render的优点是足够灵活,但也是因为它足够灵活的原因,在diff的时候也会造成很大的性能浪费。慎用render。
另外,感觉render在某些时候相对于template更加灵活一点,你可以想一下如果用template row组件该怎么写。
关于render函数该如何使用,我觉得看官网就够了cn.vuejs.org/v2/guide/re…。不要怕,写就完了! 在仿制过程中产生了疑问,在element的row.js中 是使用计算属性监控gutter
computed: {
style() {
const ret = {};
if (this.gutter) {
ret.marginLeft = `-${this.gutter / 2}px`;
ret.marginRight = ret.marginLeft;
}
return ret;
}
},
**疑问一:为什么要使用计算属性来改变style?(已解决于2019年7月10日,见文章尾)
在我的row文件中,我并没有使用计算属性判断gutter的改变,但是在测试过程中,改变gutter,视图一样会发生变化,所以我不是太理解为什么要使用
computed
总结
学到了两个方面的内容
- 1、仿制的过程中我也仿制了样式,因为element的样式也是值得我深入学习的 所以记录了class的部分连写规则
两个class连写
class1>class2 两个class之间有>号 代表选择父级为class1的所有class2
class1 class2 两个class 之间有空格 代表class1内部的所有class2 class2出现在class1的子级元素才会有效果
class1class2 两个class之间无空格 代表两个class出现在同一个元素上 class2才会有效果
class1,class2 两个class之间有逗号 代表选择所有的class1,class2
- 2、因为在el-col存在float属性,因此会存在难以撑起父组件的问题,通过查阅资料,有多种改变方法,我选择了添加伪类
.el-test-row:after{
content: '';
clear: both;
display: block;
}
同时我就看到element的row.css在class前后都添加了伪类
.el-row::after,
.el-row::before {
display: table;
content: "";
}
疑问2 为什么前后都要加伪类,不是很懂(我觉得加一个就够了😂)
提出一点我觉得需要优化的地方
在使用gutter的时候,element会在class el-row前后分别添加margin-left margin-right,以确保位于最左和最右的el-col是和el-row无间隔(目前我认为是这样)但是这样会撑开el-row的边框,因此在我以为,gutter可能需要一些优化,保证gutter不会撑开el-row的宽度。
疑问一答案
render函数在每一次有变量改变的时候都会触发,gutter的改变会触发style的改变,render也会跟着再次执行,但是如果按照我原来的写法把gutter改变导致样式改变写到render里面,那么在每一次render执行的时候都会去重新计算style,这是很没有必要的,比如说我们改变的是type、jutify这时候我们并不需要重新计算style,这时候style的值直接取缓存里面的就成,减少了重复计算style,优化了性能。
PS:由大佬总结来的一句话就是 computed有缓存。一位不爱负责的大佬