You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
5.2 KiB

2 years ago
# 组件的代码设计基本思路
我们以一个分页组件为例,阐述一下FineUI中组件代码的基本思路
## 控件功能
上一页,下一页,带个输入框,有总页数.四个按钮带disabled逻辑,无上一页或者下一页时候灰化
![示例](../images/9.png)
## 第一步: 明确对外提供的props
总页数,当前页数 就这两个属性够了
```javascript
const props = {
total: 200,
page: 10,
}
```
## 第二步: 明确要对外提供哪些方法
一个getValue方法加一个populate就行了
```javascript
// 获取当前页码
const page = this.page.getValue()
// 设置总页数和页码
this.pager.attr("total", 100)
this.pager.attr("page", 1)
this.pager.populate()
```
## 第三步: 明确对外提供哪些事件
事件只需要一个就够了,通知外部使用者当前page,养成良好习惯,事件尽量带上参数
```javascript
this.fireEvent("EVENT_CHANGE", page)
```
## 生命周期
万物皆render,能render一遍就执行好的,尽量别用其他生命周期,mounted之类的,避免没必要的回流重绘 如果组件是异步的, beforeInit/beforeRender.那么你在render中一定可以拿到所有的状态了,就没必要再通过一次watch来实现效果.当然,有些事情必须在mounted中做(例如获取组件宽高)那就另说了.
## 抛砖引玉
比如这个pager组件按钮的灰化,我就借用最新的响应式写个例子 [自动相应变更](http://fanruan.design/doc.html?post=afe4c84120)
```demo
const Pager = BI.inherit(BI.Widget, {
props: {
total: 1,
page: 1,
},
init: function () {
this.state = Fix.define({
currentPage: this.options.page,
total: this.options.total,
});
},
render: function () {
return {
type: "bi.vertical_adapt",
columnSize: [24, 24, "fill", "", 24, 24],
hgap: 5,
items: [
{
type: "bi.icon_button",
cls: "pre-page-h-font",
disabled: () => {
return this.state.currentPage === 1;
},
handler: () => {
this.state.currentPage = 1;
this.fireEvent("EVENT_CHANGE", this.getValue());
},
}, {
type: "bi.icon_button",
cls: "pre-page-h-font",
disabled: () => {
return this.state.currentPage === 1;
},
handler: () => {
this.state.currentPage--;
this.fireEvent("EVENT_CHANGE", this.getValue());
},
}, {
type: "bi.text_editor",
ref: ref => this.editor = ref,
value: () => this.state.currentPage,
validationChecker: (v) => (BI.parseInt(v) >= 1) && (BI.parseInt(v) <= this.state.total),
errorText: "error",
listeners: [
{
eventName: "EVENT_CHANGE",
action: () => {
this.state.currentPage = BI.parseInt(this.editor.getValue());
this.fireEvent("EVENT_CHANGE", this.getValue());
},
},
],
}, {
type: "bi.label",
text: () => "/" + this.state.total,
}, {
type: "bi.icon_button",
cls: "next-page-h-font",
disabled: () => {
return this.state.currentPage === this.state.total;
},
handler: () => {
this.state.currentPage++;
this.fireEvent("EVENT_CHANGE", this.getValue());
},
}, {
type: "bi.icon_button",
cls: "next-page-h-font",
disabled: () => {
return this.state.currentPage === this.state.total;
},
handler: () => {
this.state.currentPage = this.state.total;
this.fireEvent("EVENT_CHANGE", this.getValue());
},
},
],
};
},
getValue: function () {
return this.state.currentPage;
},
populate: function () {
this.state.currentPage = this.options.page;
this.state.total = this.options.total;
},
});
BI.shortcut("pager", Pager);
let pager;
BI.createWidget({
type: "bi.vertical",
vgap: 20,
items: [
{
type: "pager",
ref: ref => pager = ref,
height: 24,
width: 250,
total: 100,
page: 2,
}, {
type: "bi.button",
text: "populate",
handler: () => {
pager.attr("total", 500);
pager.attr("page", 400);
pager.populate();
},
},
],
});
```