一、简述
-
ElementUI
的row组件和col组件属于里面的layout部分,通过基础的 24 分栏,能快速的创建布局。
- 通过 row 和 col 组件,并通过 col 组件的 span 属性我们就可以*地组合布局。
二、解读源码
三、Row
export default {
name: 'BsRow', // 组件的name
componentName: 'BsRow', // 组件名,主要用于会被子组件获取
props: {
tag: { // 通过传入的tag,来渲染不同的标签
type: String,
default: 'div'
},
gutter: Number,// 通过gutter来控制row中的元素之间的间隔
type: String, // 控制是否以flex进行布局
justify: { // flex元素中水平排列规则
type: String,
default: 'start'
},
align: {
type: String,
default: 'top'
}
},
computed: {
style() {
const ret = {}; // 计算样式
if(this.gutter) {
ret.marginLeft = `${this.gutter / 2}px`;
ret.marginRight = ret.marginLeft;
}
return ret;
}
},
render(h) {
// 返回dom元素
return h(this.tag, {
class: [
'bs-row',
this.justify !== 'start'? `is-justify-${this.justify}`: '',
this.align !== 'top'? `is-align-${this.align}`: '',
{'bs-row-flex': this.type === 'flex'}
],
style: this.style
}, this.$slots.default)
}
}
3.1 computed
style() {
const ret = {}; // 计算样式
if(this.gutter) {
ret.marginLeft = `-${this.gutter / 2}px`;
ret.marginRight = ret.marginLeft;
}
return ret;
}
},
- 这段代码主要是通过gutter来设置row内部的元素间隔,因为设置了子元素的padding来控制间隔,所以首尾也会有间隔,我们通过将margin设置为负值即可解决
3.2 render函数
- render函数主要是用于渲染dom元素的,这就是采用了jsx的写法;通过返回一个h函数来创建一个组件
render(h) {
return h(this.tag, { // 自定义渲染标签
class: [
bs-row', // 组件基本样式
this.justify !== 'start' ? `is-justify-${this.justify}` : '', // 水平排列样式名生成
this.align !== 'top' ? `is-align-${this.align}` : '', // 垂直排列样式名生成
{ 'bs-row--flex': this.type === 'flex' } // flex布局样式
],
style: this.style
}, this.$slots.default);
}
- 关于组件的样式主要是利用了BEM的scss写法来控制css样式
四、Col
export default {
name: 'BsCol', // 组件名
props: {
span: { // 每个组件占据的比例
type: Number,
default: 24,
},
tag: {
type: String, // 自定义渲染标签
default: 'div'
},
offset: Number, // 栅格左侧间隔数
pull: Number, // 栅格向右移动格数
push: Number,// 栅格向左移动格数
xs: [Number, Object], // <768px 响应式栅格数或者栅格属性对象
sm: [Number, Object], // ≥768px 响应式栅格数或者栅格属性对象
md: [Number, Object],// ≥992px 响应式栅格数或者栅格属性对象
lg: [Number, Object],// ≥1200px 响应式栅格数或者栅格属性对象
xl: [Number, Object],// ≥1920px 响应式栅格数或者栅格属性对象
},
computed: {
gutter() {
// 获取父元素, 反向递归查找第一个名为BsRow的父组件
let parent = this.$parent;
while(parent && parent.$options.componentName !== 'BsRow') {
parent = parent.$parent;
}
return parent ? parent.gutter : 0
}
},
render(h) {
let classList = [];
let style = {};
// 通过父组件的gutter生成自生的padding-left与padding-right
if(this.gutter) {
style.paddingLeft = this.gutter / 2 + 'px';
style.paddingRight = style.paddingLeft;
}
// 这里逻辑是通过比对props对象,生成对应的CSS规则
['span', 'offet', 'pull', 'push'].forEach(prop => {
if(this[prop] || this.prop === 0) {
classList.push(
prop !== 'span'
? `bs-col-${prop}-${this[prop]}`
: `bs-col-${this[prop]}`
)
}
});
['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => {
if(typeof this[size] === 'object') {
let props = this[size];
Object.keys(props).forEach( prop => {
classList.push(
prop !== 'span'
? `bs-col-${size}-${prop}-${props[prop]}`
: `bs-col-${size}-${props[prop]}`
)
})
}
});
return h(this.tag, {
class: ['bs-col', classList],
style
}, this.$slots.default)
}
}
- 同样的通过传入的值,来生成css规则,从而实现响应式