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逻辑,无上一页或者下一页时候灰化 |
||||||
|
|
||||||
|
 |
||||||
|
|
||||||
|
## 第一步: 明确对外提供的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