从 0 到 1 实现一个框架BootstrapVue: Lesson 4
如何实现一个<BAspect />
1.首先看最核心的 render function
h 的第一个参数是 tag, 比如'div', 表示一种 html 元素
h 的第二个参数是 VNode 的属性, 这里只有 class, 用于调整组件的样式
h 的第三个参数是 VNode 的 children VNode, 这里有$sizer, $content
return h(this.tag, { staticClass: `${CLASS_NAME} d-flex` }, [$sizer, $content]);
我们看一下这两个 children. $content
有 slot. 而$sizer
没有.
然后样式上有一点差别.相同点是, 两个都受 flex 影响.
不同点是: $sizer
自己的高度是 0, 但是有一个 paddingBottom. $content
宽度要占满 100%.然后要向左偏移 100%. 这是因为 flex 布局下, 两者本应该是并排显示的, 但是向左偏移后, 两者就又合到一起了, 而且利用 paddingBottom 占据一个 minimum 的高度.
const $sizer = h("div", {
staticClass: `${CLASS_NAME}-sizer flex-grow-1`,
style: { paddingBottom: this.padding, height: 0 },
});
const $content = h(
"div",
{
staticClass: `${CLASS_NAME}-content flex-grow-1 w-100 mw-100`,
style: { marginLeft: "-100%" },
},
this.normalizeSlot()
);
2.看一下组件实现的核心功能
这里是传一个 aspect ratio. 即长宽比. 比如显示器大部分是 '16:9'. 组件会根据这个长宽比, 在固定宽度下, 算出一个对应的高度. 这个高度是组件的最小高度.
{
"prop": "aspect",
"description": "Aspect as a width to height numeric ratio (such as `1.5`) or `width:height` string (such as '16:9')"
}
这个计算也非常简单, 就是先校验输入的长宽比对不对, 然后取出来转成 float 类型, 再去计算比率, 最后转换成对应的百分比, 比如'100%'
padding() {
const aspect = this.aspect
let ratio = 1
if (RX_ASPECT.test(aspect)) {
// Width and/or Height can be a decimal value below `1`, so
// we only fallback to `1` if the value is `0` or `NaN`
const [width, height] = aspect.split(RX_ASPECT_SEPARATOR).map(v => toFloat(v) || 1)
ratio = width / height
} else {
ratio = toFloat(aspect) || 1
}
return `${100 / mathAbs(ratio)}%`
}
3.技术总结
这可能是我们讲到过的最简单的一个组件了. 但是麻雀虽小, 仍五脏俱全.
- 编写组件的核心是想清楚你需要实现什么东西
这里我们是要实现一个占高的东西, 因此使用了 $sizer, $content
. $sizer
用来占高, $content
用 slot 来接收后面的内容.
- 有了实现方向, 再去探讨具体的技术
这里只需要一个 prop, 即aspect
, 通过约定的形式, 比如'16:9'.很容易解析出长宽, 最后反应到样式上的百分比上去.