更多内容请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.com我们也你,你的我们的,,的,,,,,,,,,,,,,我们web肯定知道,如果我们在html中给radio表单设置相同的名字,就会被认为是一个radiogroup。我是会员1我是会员2我是member3对于一个单选组,我们只需要知道我们在这个组中选择的表单值即可。document.getElementsByName("group").forEach((v)=>{v.addEventListener("change",function(e){letvalue=e.currentTarget.valuedocument.getElementById("result").innerText="你选择了成员"+value},false)})单选组效果:在OpenHarmony应用开发中,我们可以使用多个Toggle组件来实现。OpenHarmonyToggle组件请参考:[甜酱OH文档补充]OpenHarmonyToggle组件先来看一个我们想要的效果。现在定义一个新组件RadioGroup。@ComponentstructRadioGroup{build(){}}Data要实现一个广播组组件,首先要知道我们需要什么。单项单项应该由两种数据组成。要为单选选项的相应值显示的文本。然后我们首先定义一个名为Option的接口。interfaceOption{displayValue:string,//显示文本值:string|number//对应的值}Radiogroup一个radiogroup必须由多个radio选项组成。然后RadioGroup组件必须获得单个选项数组Option[]。privatelist:Option[]//一个Option数组radiogroupvalue对于一个radiogroup,总会有一个value,因为总会有一个option被选中。对于单选组值,我们执行双向绑定。@链接值:字符串|number//类型与Option的取值一致如果没有给定radiogroup值,默认radiogroup值为第一个option对应的值。aboutToAppear(){if(!this.value){this.value=this.list[0].value}}现在让我们渲染一个基本页面看看效果。接口选项{显示值:字符串,值:字符串|number}@ComponentstructRadioGroup{私有列表:Option[]@Link值:字符串|numberaboutToAppear(){if(!this.value){this.value=this.list[0].value}}build(){Flex({wrap:FlexWrap.Wrap}){ForEach(this.list,(option:Option,index:number)=>{Toggle({type:ToggleType.Button,isOn:false}){Text(option.displayValue).fontSize(24).fontColor(Color.White)}.width(150)。height(80).selectedColor(Color.Blue)})}}}@Entry@ComponentstructIndex{privatelist:Option[]=[{displayValue:"这是选项A",value:"A"},{displayValue:"这是选项B",value:"B"},{displayValue:"这是选项C",value:"C"},{displayValue:"这是选项D",value:"D"}]@State值:字符串|number=''build(){Column(){RadioGroup({list:this.list,value:$value})Column(){Text(`Youselected${this.value}`).fontSize(30)}.height(100).margin({top:40})}.height('100%').width('100%').padding(20)}}但是现在每个Toggle组件控件都是一个独立的状态管理我们知道Toggle组件依赖于isOnRender的值你自己的当前状态,现在我们为无线电组创建一个状态管理数组。@State_state:boolean[]=[]//状态管理数组现在根据索引为每个选项组件建立自己的状态数据。该选项的默认状态为false。无线电组值对应的选项状态为真。如果(!this.value){this.value=this.list[0].value}this.list.forEach((option,index)=>{letstate=falseif(option.value==this.value){//radiogroupvalue对应选项state=true}this._state[index]=state})当我们每次修改radiogroupvalue值时,状态管理数组_state都要刷新。我们定义一个方法refresh来刷新状态。privaterefresh(){this.list.forEach((option,index)=>{letstate=falseif(option.value==this.value){state=true}this._state[index]=state})}Toggle组件每次切换状态都会执行onChange方法。当我们发现组件发生变化时,我们更新radio组值并刷新整个状态数组。ForEach(this.list,(option:Option,index:number)=>{Toggle({type:ToggleType.Button,isOn:this._state[index]}).onChange((isOn:boolean)=>{这个。value=option.valuethis.refresh()})})最重要的一步是确保选中的单个选项在再次点击后不会切换状态。这里使用了enabled属性,只要我们发现这个选项被选中,这个选项就不会响应。ForEach(this.list,(option:Option,index:number)=>{Toggle({type:ToggleType.Button,isOn:this._state[index]}).enabled(!this._state[index])//响应状态是否与选中状态值恰好相反})虽然自定义选项实现了一个radiogroup组件,但是我们发现每个选项的样式都是固定在RadioGroup组件中的。如果我们要修改样式,就必须修改RadioGroup组件。那么有什么办法可以让我们在使用radio组逻辑的同时自定义Toggle组件的样式呢?在这里感谢社区小伙伴提出的etsslotidea,通过@Builder装饰器使用ForEach实现。选项生成器首先,我们为RadioGroup组件添加一个选项生成器itemBuilder。typeUpdate=()=>voidtypeItemBuilder=(item:Option,index:number,state:boolean,update:Update)=>voidstructRadioGroup{privateitemBuilder:ItemBuilder...}此构造函数将为父组件提供一个RadioGroup选项信息。item:Option当前选项信息index:number当前选项索引state:boolean当前选项状态update:UpdateRefreshRadioGroup状态方法有了构造函数,我们可以使用构造函数返回的信息来渲染单个选项。让我们看看构造函数是如何使用的。@Builder装饰器定义了自定义组件应该如何呈现。这个装饰器提供了一个修改过的方法,其目的与构建函数一致。@Builder装饰器修饰的方法的语法规范也和build函数一致。@Builder装饰器可以在自定义组件内快速生成多个布局内容。@Entry@ComponentstructIndex{@Statevalue:string=''//渲染选项@BuilderOptionItem(option:Option,index:number,state:boolean,update:Update){Toggle({type:ToggleType.Button,isOn:state//切换组件状态}){//选项显示文本Text(`${option.displayValue}`).fontSize(24).fontColor(Color.White)}.onChange((isOn)=>{//发生改变时,执行刷新方法update()}).enabled(!state)//Toggle组件可以响应state.selectedColor(Color.Blue).size({width:150,height:80})}build(){Column(){RadioGroup({value:$value,//单选组值是双向绑定列表:this.list,itemBuilder:(option:Option,index:number,state:boolean,update:Update)=>{//在itemBuilder中调用@Builder装饰器方法this.OptionItem(option,index,state,update)}})}.height('100%').width('100%')}}实现constructor那么这个构造函数怎么实现呢?我们需要知道build方法只支持:组合组件使用渲染控制语法调用@Builder修饰的方法让itemBuilder构造方法在bu在ild中被调用,我们需要将itemBuilder做成一个组件,这将调出我们的ForEach循环渲染。当我们使用ForEach只执行一次循环时,相当于一个组件被渲染了。所以我们只要在ForEach生成子组件的lambda函数上重新定义itemBuilder构造函数方法,就可以让itemBuilder构造函数成为一个可以渲染的组件。bind()函数创建一个新函数(原始函数的副本),该函数采用提供新this上下文的参数,后跟任何可选的其他参数。当这个新函数被调用时,它的this关键字指向第一个参数的新上下文。而第二个后面的参数会和原函数的参数(原函数的参数在后面)组成一个新的参数,传递给函数。此外,还可以使用call()和apply()。我们想要的是重新定义ForEach的生成子组件的方法。private_once=Array(1)@BuilderRadioGroupItem(option:Option,index:number){ForEach(this._once,this.itemBuilder.bind(this,option,index,this._state[index],()=>{this.value=option.valuethis.refresh()}))}循环漂洗选项组build(){Flex({wrap:FlexWrap.Wrap}){ForEach(this.list,(option:Option,index:number)=>{this.RadioGroupItem(option,index)})}}完整代码ui/RadioGroup.etsexportinterfaceOption{displayValue:string,value:string|number}exporttypeUpdate=()=>voidexporttypeItemBuilder=(item:Option,index:number,state:boolean,update:Update)=>void//单选组@ComponentexportstructRadioGroup{privatelist:Option[]私有itemBuilder:ItemBuilder@State_state:boolean[]=[]@Link值:字符串|numberprivate_once:number[]privaterefresh(){this.list.forEach((option,index)=>{letstate=falseif(option.value==this.value){state=true}this._state[index]=state})}aboutToAppear(){this._once=[1]if(!this.value){this.value=this.list[0].value}this.refresh()}@BuilderRadioGroupItem(option:Option,index:number){ForEach(this._once,this.itemBuilder.bind(this,option,index,this._state[index],()=>{this.value=option.valuethis.refresh()}))}build(){Flex({wrap:FlexWrap.Wrap}){ForEach(this.list,(option:Option,index:number)=>{this.RadioGroupItem(option,index)})}}}index.etsimport{Option,RadioGroup,Update}来自'../ui/RadioGroup.ets';@Entry@ComponentstructIndex{@Statevalue:string=''privatelist:Option[]=[{displayValue:"这是选项A",value:"A"},{displayValue:"这是选项B",value:"B"},{displayValue:"这是选项C",value:"C"},{displayValue:"这是选项D",value:"D"}]@BuilderOptionItem(option:Option,index:number,state:boolean,update:Update){Flex({alignItems:ItemAlign.Center,justifyContent:FlexAlign.Center}){Toggle({type:ToggleType.Button,isOn:state}){Text(`${option.displayValue}`).flexGrow(1).fontSize(24).fontColor(Color.White)}.onChange((isOn)=>{更新()}).enabled(!state).selectedColor(Color.Blue).borderRadius(150).size({width:150,height:80})}.width('25%').margin({top:10,bottom:10})}build(){Column(){RadioGroup({value:$value,list:this.list,itemBuilder:(option:Option,index:number,state:boolean,update:Update)=>{this.OptionItem(option,index,state,update)}})Column(){Text(`您选择了${this.value}`).fontSize(30)}.margin(40)}.height('100%').width('100%')}}这是我自己的思路,自定义组件在实际应用开发中应该多考虑,想了解更多请访问:Harmonyos.51cto.com