From 51f25e41c3ed680e41df20defe09b2e6113ed625 Mon Sep 17 00:00:00 2001 From: zsmj Date: Mon, 11 Jul 2022 17:20:32 +0800 Subject: [PATCH] update --- README.md | 17 +- images/8.png | Bin 0 -> 4277 bytes images/9.png | Bin 0 -> 2563 bytes .../2.组件的代码设计基本思路.md | 174 ++++++++++++++++++ ...,为什么要先定义属性才可以.md | 1 - .../41.绝对布局的隐藏知识点.md | 31 +++- ...属性才可以正常watch,如何解决.md | 55 ++++++ questions/81.combo的一些特性.md | 0 8 files changed, 272 insertions(+), 6 deletions(-) create mode 100644 images/8.png create mode 100644 images/9.png create mode 100644 questions/2.组件的代码设计基本思路.md delete mode 100644 questions/30.Fix中对于对象属性的监听,为什么要先定义属性才可以.md create mode 100644 questions/55.Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决.md delete mode 100644 questions/81.combo的一些特性.md diff --git a/README.md b/README.md index 18ede4a..e056b9f 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,15 @@ FineUI入门100题,带你走进FineUI的世界 此系列内容来源于日常开发积累与沉淀,用于大家学习交流与项目中踩坑 -## 题目 +## 100-Questions列表 -### 项目基础 +--- +### 基础 + +- [0、前端工作进阶需要哪些必备技能](./questions/0.前端工作进阶需要哪些必备技能.md) - [1、前端如何正确书写资源路径](./questions/50.前端如何正确书写资源路径.md) +- [2、组件的代码设计基本思路](./questions/2.组件的代码设计基本思路.md) ### 布局篇 @@ -16,8 +20,15 @@ FineUI入门100题,带你走进FineUI的世界 - [3、我们为什么要设计el这个属性](./questions/40.我们为什么要设计el这个属性.md) - [4、绝对布局的隐藏知识点](./questions/41.绝对布局的隐藏知识点.md) +### Fix数据流篇 + +- [4、Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决](./questions/55.Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决.md) + ### 进阶 - [1、如何获取当前时间](./questions/1.如何获取当前时间.md) - [2、如何格式化输出日期](./questions/2.如何格式化输出日期.md) -- [3、为什么传递时间信息时候推荐使用时间戳](./questions/3.为什么传递时间信息时候推荐使用时间戳.md) \ No newline at end of file +- [3、为什么传递时间信息时候推荐使用时间戳](./questions/3.为什么传递时间信息时候推荐使用时间戳.md) +- [4、BI.config都可以做那些事情](./questions/9.BI.config都可以做那些事情.md) +- [5、BI.config的执行顺序是什么,为什么这么设计](./questions/10.BI.config的执行顺序是什么,为什么这么设计.md) +- [6、combo的一些特性详解](./questions/80.combo的一些特性详解.md) diff --git a/images/8.png b/images/8.png new file mode 100644 index 0000000000000000000000000000000000000000..a9dc2b877fe290de6bcbb870ef75332fd2e981e4 GIT binary patch literal 4277 zcmeAS@N?(olHy`uVBq!ia0y~yV0_BJz{JVH1{9ecrwXDNi-X*q7}lMWc?smOq&xaL zGB9lH=l+w(3gmMZctjR6Fo>ywFr#OX$_EAp0WVJ%$B>G+w|9KIQYs~nCQe`29mu|y z!Tr&O(g#9SyuH>1FI)?mPvaZ=IY+i{U%sm{k25gj`Q+z z9!kwVpXUClc)xdI{LeR^pNlg*`0qc3@qvPiBmC&mLd1@8`pK{rZZJ!v8t+=hsc~=(nb) z&d>k%*8BbLpV#{5$Nu~1Rj}T%{{H7>_pf^()K^H{G&{xrcmK90t4)?y3#B$p_6n@( zdA;m+R?B_$Q`^^8Z~eLL(wujmz!1=KU0GVKkS+Q&eEXB~-R661C3McdoaZ9>U`f!F zsO`TG@-P1L?ekNO+;KITEo>yZSROXKill-^xN;nKi1q`R@41+ za{NBKP1{f3zW!P7V;(#_gC3XZ|ID4fTHejF^5?wi&r1XAOi$!%Psu zurGf~{`5t_;PU^!xzhgU)A|3U@0Z(dKku=8{(Xev<2zh`cK_bz(B2tosuv8 z;q9ld=j%Sb>^9i{&uFtox6y&jr5d)!4r|>*LG+hfi^pe6S^GirnL? z8u#ZdsxzI#FaKrN-sg!muAo$;?fTL%FR<=szstTqKOeUT?yK728^2WJe%$Xzdw%Zw z@*628EAHApoh|ZoF+ymwH$2`bW%BQ<|8t)A{^e4+Ouz3crx?_~e(e8O@$;Me{38x? z&zADR6Z#EPm-PEH*4O_RY^qT`#ZVxyh=+k)kpN?}#{ajgYV*%}(J9Gj-We83?q*?S6Og2L8~K+_E-+`1u@${^t}s%HUmH)5b+tC4mB`%y85}Sb4q9e09a^WyZ`_I literal 0 HcmV?d00001 diff --git a/images/9.png b/images/9.png new file mode 100644 index 0000000000000000000000000000000000000000..a18df6e9dad9ee7f0bbab8e6cb16576ef9fd47cd GIT binary patch literal 2563 zcmb_edpwhEAD^>mO>!t+heQq!DtZk$&afp`whqWj(M)WlnK0*biVb-@LYTCt5G6II zdJ+#JMiSec4~wN@36p2`)_eHt{k)&g`^RFtZn=?>GMFs!> z0O2sGI{+XeXaGlPNkP9m1Q#y2h=jU3LjYAhf8z)y;uw2ZdjOy&Qj^I`ORN7WSW0I#HK;vA*yCiaZ(GL|x`V_W#+U0io z)PbdyPC`=ck`ndg6Pxawlu(d!Hgewf#NWkdB|d?ETf971FKa)xqk~P|RudXblBR0+ zbTyiWeMoEhywVe8susgp%2ub4jBggOky& z*35+UIZ6Cw{CO#UsNpRGRHgA-99;S13zGJH*UZNgaBnJqq}1CN1zH(LS3ayG7BW$B z$tLaC^Wob)b{5IL(RKYcJ7lc&`^$eVXyl!O@8t$ppBfr2@PQwj!C*sbJR2kq{}DRA zO4Ubpyg3BaZVLRUu9$jQlU_11TrjSttUat!1bU-yM6u$yW-Zq~i$rNMV&{@^m+{HP z&7#)W9{rANwmAGiL4&h|7BCez_vGs(P4_)=SW^nxjF>3{Rgq)$264OXs3w|>OaBQU z2lKO|cEcjxGp!Beuy$7+>g&K__Hj~;oZLKcN$R;A{B%1qOckXCKf;J`~4L0lFMm~@G9j2SJa@pOWcQYl0)6TYE!#=(j{W^Uv*?3;f zC~24CG?(&k5QC(6c4Lf~ck?uS%}|3ou~EKiQmA(e8(k8XkSs*S_>axS?)$^=hQT7p zZLh7pGi#B+08gbpz7xgl6r$QZoAj_`fR80inv7Rx_|^!*Tu|U_CpBI)_2xZCA1!U7 z<~>*!Ck>ILyc=f%EQ#Ep{W1-v3+Bk^CX;Bg)47;dbkdL^bHmTcD$bH) zVRrOle`tC;txT2vfcSLE=}}$tm%^n^n3BsGd&6T3W!=i1$_oK|nYU|~8Rx);Z~U=7 z@iy0J*Q;7^O_8;mJ}jdF-h@b}Zgb?9un7L>G00sC+J~;OIkSfz!hMSywH;lO;VE7w zO2@)f#}bg+UK9sw86BJT9~&C0%~>-=mYkFC1$qy9skcCw2DlP`6>TfwbxdSA0MKZbVYQ@=Rqwf zue5fy<~3B8yDYwULH4w~G#+{j*-ieEQ5F6Txze3I5f@{Q@W9{kmfFCVE3{0Eyz8&3 z<{>V0Bi4L<4LFLGk@*oe;W?Hp7AInuKZI5ph&rE6ZFkjm6a>N(Fp+l-O$1KA(1uO=+F7P3Ds^9jU0Ra^0vY7p7%xm1OGylo}a(m8vw zY`|+Y=_^Jr`}+4PqV-ms^=?f0X<N7xdUry z^VCc)!3oZ=3R#>YV|pv+bwhuP_5J9eJz7DrAU7TH7*VL_Z{_3{CBJ1z&iy$i?y9l? zQ56{WhAG`O>s#Aw$+!mG_28cy3<#neaUD=fM#exD^zcTs=BJL|eP zf0WnykqMIuoe$+|?}(B;ZHhxrfK^ap^dawtlL)46Q@7T}o2rpKM>>~B zZb<>M*AJ0`W-av0&!iOH#h?Rwj->DqORk7DZS782gyZ~8*)KPQY}TN`nua!YOZ&d} z6z%gcl%s8D-A3hEU&GrFo-WB8WhhVS>IlAIi<+M!Bf{?2%TB+`CdS;b-3bH=*^#)5 zmM3!qWBPXsix(-k3=_3{9Y0-=kUWv}d;>8DC$mbFrCn1Ru3gig=V+h8fl}HPv zsEne0{pwK}Xs`1Xu%^qWz_`uBVQD55G^O3J8^dYBE!OTAJl*~e`mahI$-J3y9FbaB zv_-zYcu*J)w4i{kg++AG5xwe|*$hzF&23xhrNBy#%eRorRM$8QYWs!9EEEcP;yLp@ z5y}A&im7!ORAs+Vxc-~6{M0Z>ty~eZ**=b6=*m4isz@J@HOSunLt?g6HV!6Ms!FeH z+LMZsgbrs=^SW7OqGU-Z_^MZ=sYCwcY_@)R5&FMNYShlL^^p$s=m zb0D7MHq85q0#Uqzl)#+mhTIkTbT-_^s^alj@x{7fbPT+WO%Ry6M&<=|K&qFJ+F=G+g@hG=ksz6s@+yHP#H)s{) GeEeTG4bHa! literal 0 HcmV?d00001 diff --git a/questions/2.组件的代码设计基本思路.md b/questions/2.组件的代码设计基本思路.md new file mode 100644 index 0000000..222854e --- /dev/null +++ b/questions/2.组件的代码设计基本思路.md @@ -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(); + }, + }, + ], +}); + +``` \ No newline at end of file diff --git a/questions/30.Fix中对于对象属性的监听,为什么要先定义属性才可以.md b/questions/30.Fix中对于对象属性的监听,为什么要先定义属性才可以.md deleted file mode 100644 index afe629f..0000000 --- a/questions/30.Fix中对于对象属性的监听,为什么要先定义属性才可以.md +++ /dev/null @@ -1 +0,0 @@ -# Fix中对于对象属性的监听,为什么要先定义属性才可以 \ No newline at end of file diff --git a/questions/41.绝对布局的隐藏知识点.md b/questions/41.绝对布局的隐藏知识点.md index 317954e..0ceee7a 100644 --- a/questions/41.绝对布局的隐藏知识点.md +++ b/questions/41.绝对布局的隐藏知识点.md @@ -105,9 +105,36 @@ BI.createWidget({ ![示例](../images/7.png) -4. 绝对布局支持shorthand写法inset +4. 位置属性使用负值会有起效 -使用Chrome审查元素的同学可能发现了,绝对布局的元素在chrome中会显示`inset: 0`这种形式,实际上这是top right bottom left属性的简写,规则遵循顺时针方向.需要注意的是只有第一种情况支持属性名为数字,其余情况需要加引号,毕竟我们是写js而不是css +在开发过程中会遇到有些按钮图标为了位置美观,会脱离正常位置的情况,此时利用负值属性可以很轻松实现 + +```demo +BI.createWidget({ + type: "bi.absolute", + width: 300, + height: 300, + css: { + background: "red", + }, + items: [ + { + el: { + type: "bi.button", + text: "保存", + }, + top: -30, + right: 10, + }, + ], +}); +``` + +![示例](../images/8.png) + +5. 绝对布局支持shorthand写法inset + +使用Chrome审查元素的同学可能发现了,绝对布局的元素在chrome中会显示`inset: 0`这种形式,实际上这是top right bottom left属性的简写,规则遵循顺时针方向.FineUI同样支持了这种写法,需要注意的是只有第一种情况支持属性名为数字,其余情况需要加引号,毕竟我们是写js而不是css ``` inset: 10 /* value applied to all edges */ diff --git a/questions/55.Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决.md b/questions/55.Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决.md new file mode 100644 index 0000000..b52475a --- /dev/null +++ b/questions/55.Fix中对于对象属性的监听,为什么要先定义属性才可以正常watch,如何解决.md @@ -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"); + }, +}); +``` \ No newline at end of file diff --git a/questions/81.combo的一些特性.md b/questions/81.combo的一些特性.md deleted file mode 100644 index e69de29..0000000