8 changed files with 272 additions and 6 deletions
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 2.5 KiB |
@ -0,0 +1,174 @@
|
||||
# 组件的代码设计基本思路 |
||||
|
||||
我们以一个分页组件为例,阐述一下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(); |
||||
}, |
||||
}, |
||||
], |
||||
}); |
||||
|
||||
``` |
@ -1 +0,0 @@
|
||||
# Fix中对于对象属性的监听,为什么要先定义属性才可以 |
@ -0,0 +1,55 @@
|
||||
# Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决? |
||||
|
||||
|
||||
先看如下代码示例,很明显按钮被点击后并不会输出phone的值,其实这和Vue2类似,是因为Fix在响应式处理的时候,遍历对象的每一个属性添加依赖的,并不能检测到新增的属性. |
||||
|
||||
```javascript |
||||
const state = Fix.define({ |
||||
name: "小明", |
||||
details: { |
||||
age: 18, |
||||
address: "北京", |
||||
}, |
||||
}); |
||||
|
||||
Fix.watch(state, "details.phone", phone => { |
||||
console.log(phone); |
||||
}); |
||||
|
||||
|
||||
const widget = BI.createWidget({ |
||||
type: "bi.button", |
||||
text: "button", |
||||
handler: () => { |
||||
state.details.phone = "123456789"; |
||||
}, |
||||
}); |
||||
``` |
||||
|
||||
在日常实践中我们一般采用两种方式来处理这种情况 |
||||
|
||||
1. 修改整个对象的引用 |
||||
|
||||
``` |
||||
const widget = BI.createWidget({ |
||||
type: "bi.button", |
||||
text: "button", |
||||
handler: () => { |
||||
state.details = { ...state.details, phone: "123456789"}; |
||||
}, |
||||
}); |
||||
``` |
||||
|
||||
2. 使用Fix.set方法 |
||||
|
||||
类似vue的$set方法 |
||||
|
||||
``` |
||||
const widget = BI.createWidget({ |
||||
type: "bi.button", |
||||
text: "button", |
||||
handler: () => { |
||||
Fix.set(state.details, "phone", "123456789"); |
||||
}, |
||||
}); |
||||
``` |
Loading…
Reference in new issue