当前位置: 首页 > Web前端 > HTML

HeadlessUIComponents

时间:2023-03-28 16:37:45 HTML

原文:https://www.merrickchristense...“策略与机制分离,界面与引擎分离。”—EricS.RaymondHeadlessui组件是一种新的ui组件开发模型,组件本身不提供ui上的实现,方便用户自由定制ui风格。“等一下,没有ui的ui组件,你知道你在说什么吗?”是的,与直觉相反,但这正是我们所提倡的。CoinFlip组件假设你要实现抛硬币的功能。需求如下:实现类似抛硬币的效果。翻转结束后,硬币出现正面和反面的概率为50/50。你跟产品说这个需求有点复杂,给我半年时间研究,然后你开始写democonstCoinFlip=()=>Math.random()<0.5?

:
尾巴
;```太简单了,然后你开个会,拿着ppt上去。产品好,功能有了,可以优化款式。对你来说没问题。constCoinFlip=()=>数学。随机()<0.5?(
):(
);很快,他们希望在营销页面上启动您的功能。他们将把它放在博客文章中,并希望您的组件对SEO友好。所以你卷起袖子继续做下去。constCoinFlip=(//将默认值设置为false以避免破坏以前的应用程序。//当前使用情况。{showLabels=false})=>Math.random()<0.5?(
{/*添加标签,在营销页面上使用*/}{showLabels&&Heads}
):(
{/*添加标签标签,用于营销页面*/}{showLabels&&Tails}
);然后还有一个需求,添加一个重新启动的按钮,这个按钮只在应用中添加。组件开始变得难看,毕竟我们不是动物认真对待我。<>{this.state.showButton&&(Reflip)}{this.state.flipResults<0.5?(
{showLabels&&Heads}
):(
{showLabels&&Tails}
)});}}然后有一天你的同事找到你:“我的朋友,你的抛硬币功能太棒了。我们有一个叫做掷骰子的新需求,你能重用你的代码吗?“你拆分了新的需求:1.需要一个重置按钮1.需要在应用程序和营销页面中使用1.与你的组件有完全不同的用户界面1.有不同的随机概率现在你面临两个选择,要么拒绝你的同事,要么改造你的组件,把掷骰子的功能放到抛硬币组件中,看着这个组件变得臃肿难维护。当一个组件的行为足够复杂,逻辑和视觉呈现可以解耦时,这种模式非常有效CoinFlip组件实现Headless的方式可以是让具体的ui实现是一个子组件或者renderProp传递输入,像这样:constflip=()=>({flipResults:Math.random(),});classCoinFlipextendsReact.Component{state=flip();handleClick=()=>{this.setState(flip);};render(){返回this.props.children({rerun:this.handleClick,isHeads:this.state.flipResults<0.5,});}}上面的组件是一个headlessui组件,因为这个组件不渲染任何东西。它完成逻辑状态提升并期望消费者进行实际的渲染工作。回到我们的应用程序,代码可能如下所示:imgsrc="/heads.svg"alt="头"/>
):(
)})}然后是我们的营销页面,它可能如下所示:{({isHeads})=>(<>{isHeads?(
Heads
):(
Tails
)})}
完美,我们把逻辑和状态抽象的很好,把ui剥离了,可以随意定制我们的ui。我知道你可能在想什么...>你是不是傻了,不就是个renderProp吗,有必要绕一圈吗?在这个例子中,恰好我们使用renderProp来实现。在react中,当然我们也可以使用HOC来实现。稍加思考,我们甚至可以将其实现为MVC中的View和Controller,或者MVVM中的ViewModel和View。(注意:封装了组件内部的逻辑状态,具体的渲染和事件绑定交给渲染框架,适配层单独开发,组件甚至可以跨平台。)这里的核心思想是分离组件的机制和性能。#回到掷骰子组件这种分离的好处是我们可以轻松扩展我们的无头组件以支持我们同事的掷骰子功能:construn=()=>({random:Math.random(),});classProbabilityextendsReact.Component{state=run();handleClick=()=>{this.setState(run);};render(){returnthis.props.children({rerun:this.handleClick,//set不同的阈值,不同的概率结果:this.state.random({({rerun,result})=>children({isHeads:result,rerun,})});同样,同事也可以通过复用Probability组件来实现自己的逻辑constRollDice=({children})=>(//六面骰子{({rerun,result})=>(
{/*一些自定义事件可以在这里实现*/}掷骰子!{/*完全不同的ui实现*/}{result?(
大赢家!
):(
你赢了一些,你输了大部分。
)}
)});优雅,非常优雅。#分离原则——Unix设计哲学这是业界广泛认可的共识,而且历时已久。Unix设计哲学基础#4:>“策略与机制分离,接口与引擎分离。”-EricS.Raymond我想引用这一部分并将策略一词替换为界面。>因为界面和机制是根据不同的时间尺度变化的,所以界面的变化比机制要快得多。GUI工具包的外观和感觉时尚来来去去,但光栅操作和组合确实是永恒的。因此,将界面与机制混为一谈有两个负面影响:一是会使界面僵化,难以适应用户需求的变化,二是也意味着界面的任何变化都可能动摇机制。相反,在探索新界面时,将两者剥离可能不足以打破机制。此外,我们可以更轻松地为该机制编写更好的测试(因为接口的生命周期太短,不值得花太多精力在上面)。我喜欢这里的见解,它也让我们思考无头ui设计模式非常有价值的情况。1、这个部件的寿命有多长?抛开界面表现不谈,背后的机制是否值得我们刻意保留?我们会在另一个外观和感觉完全不同的项目中使用这种机制吗?2.我们多久更新一次界面的外观?对于同一个功能,我们会有多少种不同的表现形式?将机制与政策分开是有代价的。我们需要平衡分离的收益和成本。我觉得这就是过去很多MV*模式容易出错的地方,坚持这个原则,一切都是这样解耦的。回到现实,很多机制和政策是深度耦合的,分离的收益可能不足以弥补成本。