diff --git a/README.md b/README.md index 27cd690..c05202e 100644 --- a/README.md +++ b/README.md @@ -56,14 +56,14 @@ FineUI 100个问题题,带你走进FineUI的世界 - [20、BI.Layers.create参数详解原理](./questions/29.BI.Layers.create参数详解原理.md) - [21、上对齐的横向布局](./questions/27.上对齐的横向布局.md) - [22、tab选项卡组件的logic属性实现动态高度](./questions/26.tab选项卡组件的logic属性实现动态高度.md) -- [23、为什么FineUI中采用display:none隐藏组件]() +- [23、隐藏与显示组件的冷门知识点](./questions/23.隐藏与显示组件的冷门知识点.md) - [24、选中、hover样式的通用处理规则](./questions/26.tab选项卡组件的logic属性实现动态高度.md) - [25、如何独立控制组件文字和图标颜色](./questions/34.独立控制组件文字和图标颜色.md) - [26、文件上传控件多次选择文件和自定义校验](./questions/35.文件上传控件多次选择文件和自定义校验.md) -- [27、effect的妙用](27.effect的妙用.md) -- [28、defer和nextTick有什么区别]() +- [27、effect的妙用](./questions/27.effect的妙用.md) +- [28、defer和nextTick有什么区别](./questions/28.defer和nextTick有什么区别.md) - [29、为什么说随意修改原始数据时万恶之源?]() -- [30、空状态提示的若干种实现方式]() +- [30、空状态提示的若干种实现方式](./questions/30.空状态提示的若干种实现方式.md) - [31、在响应式中谨慎使用解构](./questions/31.响应式中谨慎使用解构.md) - [32、有没有一种布局方式,在文本保持垂直居中的情况下,文本很多时,可以限制其不超出外层高度 并出现滚动条](./questions/32.有没有一种布局方式,在文本保持垂直居中的情况下,文本很多时,可以限制其不超出外层高度 并出现滚动条.md) - [33、如何快速的封装自定义combo](./questions/33.如何快速的封装自定义combo.md) diff --git a/images/58.png b/images/58.png new file mode 100644 index 0000000..687163a Binary files /dev/null and b/images/58.png differ diff --git a/images/59.png b/images/59.png new file mode 100644 index 0000000..ef71f91 Binary files /dev/null and b/images/59.png differ diff --git a/images/企业微信截图_20221229100941.png b/images/企业微信截图_20221229100941.png new file mode 100644 index 0000000..3773ea3 Binary files /dev/null and b/images/企业微信截图_20221229100941.png differ diff --git a/questions/23.隐藏与显示组件的冷门知识点.md b/questions/23.隐藏与显示组件的冷门知识点.md new file mode 100644 index 0000000..030dfc0 --- /dev/null +++ b/questions/23.隐藏与显示组件的冷门知识点.md @@ -0,0 +1,19 @@ +# 隐藏与显示组件的冷门知识点 + +FineUI中组件`setVisible`方法采用的是`display:none`的形式隐藏组件. + +优点大家都知道,不占据DOM流之类的. + +但是缺点也很明显,多tab之类的组件,隐藏的元素无法获取宽高,这也是一些"组件缩成一坨"问题的直接原因 + +那么为什么不用`visibility:hidden`呢? + +其实有个原因是input元素`focus`的特性导致 + +采用`visibility:hidden`形式隐藏组件,为了避免鼠标事件触发等,大多会附加一个超大的`top,left`样式,或者`translateX()`超大值,将其挪到屏幕外面 + +然而`focus`操作默认有个scrollToView特性,其会不受限制的自动跳到屏幕中间 + +![示例](../images/58.png) + +例如决策平台的modern主题,开发者无法控制每个打开的tab里面是否会有代码逻辑触发`focus`,因此只能采用`display:none`的形式隐藏tab,否则就容易出现这种位置异常 diff --git a/questions/27.effect的妙用.md b/questions/27.effect的妙用.md index 88349e8..8bc309b 100644 --- a/questions/27.effect的妙用.md +++ b/questions/27.effect的妙用.md @@ -4,7 +4,9 @@ FineUI组件中text,value,cls,css,selected,items,columnSize,rowSize,invisible,di 但是,总有一些属性没有支持响应式,或者一些组件提供的props并未支持响应式,这时候只能回归`_store`+`watch`了吗? -非也,有effect属性 +非也,有effect属性,看一个示例: 有一个自定义组件,想在状态变化的时候调用组件的某个方法 + +如下示例,effect函数自动收集`state.state1`依赖,在`state1`发生改变时,自动执行.需要注意的是effect函数会在组件初始化的时候自动执行一次. ```javascript const state = Fix.define({ @@ -19,3 +21,26 @@ const render = () => { }; }; ``` + +effect支持数组形式,形式是长度为2的元组,第一个函数收集依赖,第二个函数为依赖变化后需要执行的操作. +这与watch很像,可以理解为第一个函数是需要watch的内容,第二个函数时变化的回调 + +```javascript +const state = Fix.define({ + state1: 0, + state2: 0, +}); +const render = () => { + return { + type: "bi.my_custom_wdiget", + effect: [ + () => { + return [state.state1, state.state2]; + }, + (customWidget) => { + customWidget.customMethod(state.state1, state.state2); + } + ] + }; +}; +``` diff --git a/questions/28.defer和nextTick有什么区别.md b/questions/28.defer和nextTick有什么区别.md new file mode 100644 index 0000000..eda6565 --- /dev/null +++ b/questions/28.defer和nextTick有什么区别.md @@ -0,0 +1,12 @@ +# defer和nextTick有什么区别 + +研读FineUI代码时,会发现有的地方用了`BI.defer`,有的地方用了`BI.nextTick`,有什么区别呢? + +`BI.defer`源自lodash,官方描述是Defers invoking the func until the current call stack has cleared.,翻译一下就是在当前调用栈执行完毕之后调用. + +看起来很高大上实际上底层实现就是`settimeout(fn,0)` + +`BI.nextTick`的实现相对复杂,采用的是"能力检测"策略,优先使用`Promise.resolve()`,不支持的话使用`MutationObserver`,不支持的话`setImmediate`,还是不支持的话 +那就只能`settimeout(fn,0)`了 + +由此可见,实际作用都是异步的延迟执行某段事务,使用`BI.nextTick`效率会更高一些 diff --git a/questions/30.空状态提示的若干种实现方式.md b/questions/30.空状态提示的若干种实现方式.md new file mode 100644 index 0000000..4cd32ff --- /dev/null +++ b/questions/30.空状态提示的若干种实现方式.md @@ -0,0 +1,137 @@ +# 空状态提示的若干种实现方式 + +![示例](../images/59.png) + +## 布局实现 + +一般情况下,采用`bi.absolute`布局放置内容和空提示 + +```javascript +const widget = { + type: "bi.absolute", + items: [ + { + el: { + type: "content", + }, + inset: 0 + }, { + el: { + type: "empty_tip", + invisible: () => !this.model.tipVisible + }, + inset: 0 + } + ] +}; +``` + +## Layers实现 + +如果想脱离组件层面,以service的形式对组件施加空状态提示,也可以使用`BI.Layers`控制,实现对任意组件附加空提示 + +```javascript +function createEmptyTyp(widget) { + const name = BI.UUID(); + BI.Layers.create(name, null, { + container: widget, + render: { + type: "empty_tip", + }, + }); + + BI.Layers.show(name); + return () => { + BI.Layers.remove(name); + }; +} +``` + +## 状态控制 + +用独立清晰的状态控制空提示的显示隐藏,避免掺杂在其他状态控制中 + +如下示例,在items的watch中"顺带"处理tip组件显示隐藏,使得控制逻辑变的不够清晰 + +```javascript +class model extends Model { + state = { + items: [] + }; +}; + +class widget extends BI.Widget { + watch = { + items: (items) => { + this.list.populate(items); + this.tip.setVisible(BI.isEmpty(items)); + } + }; + + render() { + return { + type: "bi.absolute", + items: [ + { + el: { + type: "content", + ref: ref => this.list = ref, + }, + inset: 0 + }, { + el: { + type: "empty_tip", + ref: ref => this.tip = ref, + invisible: !BI.isEmpty(this.model.items) + }, + inset: 0 + } + ] + }; + } +}; +``` +将tip显示隐藏的状态独立出来,独立控制,这样状态到视图的映射清晰明了 + +```javascript +class model extends Model { + state = { + items: [] + }; + + computed = { + tipVisible: () => BI.isEmpty(this.model.items) + }; +}; + +class widget extends BI.Widget { + watch = { + items: (items) => { + this.list.populate(items); + }, + tipVisible: b => this.tip.setVisible(b) + }; + + render() { + return { + type: "bi.absolute", + items: [ + { + el: { + type: "content", + ref: ref => this.list = ref, + }, + inset: 0 + }, { + el: { + type: "empty_tip", + ref: ref => this.tip = ref, + invisible: !this.model.tipVisible, + }, + inset: 0 + } + ] + }; + } +}; +```