关于搜索栏双向绑定出错问题

我们一帮都会给搜索栏进行双向数据绑定,然后点击搜索之后,把表单的数据,当做参数发起请求,

但是这样会出现一种情况:当我们在搜索栏输入了内容,但是没有点击搜索,这个时候切换当前的分页,就会出现默认搜索当前的值的情况,

解决方案 :,表单绑定的值和发送的请求,使用不一样的参数

 当点击了搜索按钮,把表单的值赋值给API,如果没有点击搜索,则不会携带表单的数据

        this.API = { ...this.fromData }
        this.API.chkState = undefined
        this.fnchoice()//发起请求
--------------------------------------------
 const res = await choice(this.API)//发起ajax请求.参数是this.API
        console.log('fnchoice', res)
        this.alllist = res.data.items
        this.counts = res.data.counts

注意我的用法,我没有直接把this.fromData 赋值给API.而是解构之后,在赋值的,

原因是,直接赋值,虽然第一次可以解决分页的问题.但是当你点击的搜索按钮之后,再在搜索框输入查询值不点击搜索,这时候点击分页时,还是会查询搜索框中的值,所以不能直接赋值地址

import { IBestNavBar, IBestSideBar, IBestSideBarItem,IBestPopup} from "@ibestservices/ibest-ui-v2"; import { FirstCateData, SecondCateData } from '../../api/Index' import { AxiosResponse } from '@ohos/axios' import { SeondCateId, FirstCate,ScondCate } from '../../interface/pord' import log from '@open/log' @ComponentV2 export struct Cate { router = this.getUIContext().getRouter() @Local visible: boolean = false @Local list: FirstCate[] = [] @Local groupId: string = "group" @Local active: number = 0 @Local secondList:ScondCate[]= [] // 存储二级分类数据 @Local proName:string='' firstcate = async () => { try { let res: AxiosResponse = await FirstCateData() this.list = res.data // 默认加载第一个分类的二级数据 if (this.list.length > 0) { this.secondcate({categoryId: this.list[0].id }) } } catch (error) { log.error("获取一级分类失败:", error) } } secondcate = async (params: SeondCateId) => { try { const queryParams:SeondCateId = { categoryId: params.categoryId } let ite: AxiosResponse = await SecondCateData(queryParams) this.secondList = ite.data // log.info(this.secondList) } catch (error) { log.error("获取二级分类失败:", error) } } handleCategoryClick(index: number) { this.active = index if (this.list[index]) { const params:SeondCateId={ categoryId:this.list[index].id } this.secondcate(params) } } aboutToAppear(): void { this.firstcate() } @Builder centerBuilder() { Column(){ IBestNavBar({ title: "搜索中心", titleColor: "#fff", titleFontSize: 24, titleFontWeight: FontWeight.Bold, navBarBgColor: "#476ce3", isShowLeft: true, leftIconSize:30, navBarHeight:60, leftIconColor:'#fff', onLeftClick:()=>{ this.visible=false } }) Row(){ TextInput({placeholder:'请输入商品名....',text:$$this.proName}) .width('80%') .contentType(ContentType.USER_NAME) Button('搜索') .backgroundColor('blue') .fontColor('#fff') .type(ButtonType.Normal) .width(70) .height(40) .onClick(()=>{ this.visible=false this.router.pushUrl({ url:"pages/Product", params:{ proName:this.proName } }) }) } .width('100%') .margin({ top:10 }) Row(){ Text('清空搜索记录') .fontSize(30) .fontColor('#cfcfcf') Image($rawfile('img/del.png')) .width(30) .height(30) } .width('100%') .justifyContent(FlexAlign.SpaceBetween) .border({ width:{ bottom:'2' }, color:"#cfcfcf" }) .margin(10) } .margin({ top:40 }) .width('100%') .height('100%') } build() { Column() { // 顶部导航栏 IBestNavBar({ title: "乐淘云购", titleColor: "#fff", titleFontSize: 24, titleFontWeight: FontWeight.Bold, navBarBgColor: "#476ce3", isShowLeft: true, leftIconSize: 30, leftIconColor: '#fff', onLeftClick: () => { this.router.back() }, navBarHeight: 60, rightIcon: $rawfile('img/search.png'), onRightClick:()=>{ this.visible = true }, isShowRight: true, rightIconSize: 30 }) // 主内容区 Row() { // 左侧导航栏 - 修复左对齐 Column() { IBestSideBar({ groupId: this.groupId, active: this.active, sideWidth:'100%', maxHeight:'100%', }) { ForEach(this.list, (v: FirstCate, index: number) => { IBestSideBarItem({ groupId: this.groupId, index: index, title: v.categoryName, onItemClick: () => this.handleCategoryClick(index) }) }) } } .width('30%') .height('100%') .backgroundColor("#fff") .border( { width:{ right:2 }, color:"#fff" }) // 右侧内容区 Scroll() { Column() { // 二级分类网格布局 Grid() { ForEach(this.secondList, (item:ScondCate) => { GridItem() { Column(){ // 分类图标 - 使用占位图 Image(item.brandLogo) .width('100%') .height(120) .objectFit(ImageFit.Fill) // 分类名称 Text(item.brandName) .fontSize(18) .textAlign(TextAlign.Center) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .width('100%') .height(140) .onClick(() => { this.router.pushUrl({ url:"pages/Product", params: { proName:item.brandName } }) }) } }) } .maxCount(2) .layoutDirection(GridDirection.Row) .columnsTemplate('1fr 1fr') .width('100%') .height('100%') } .width('100%') } .width('70%') .scrollBarWidth(2) } .layoutWeight(1) .height('100%') .width('100%') IBestPopup({ visible: this.visible, popupWidth: '100%', popupHeight:'100%', contentBuilder: this.centerBuilder }) } .width('100%') .height('100%') .backgroundColor("#f5f7fa") } }为什么点搜索日志报错?
最新发布
07-30
<think>我们分析问题:点击搜索按钮时,日志报错。根据提供的代码,搜索按钮的点击事件处理函数如下: ```typescript Button('搜索') .onClick(() => { this.visible = false; this.router.pushUrl({ url: "pages/Product", params: { proName: this.proName } }); }) ``` 报错可能的原因: 1. **`this.proName` 未正确绑定**:在TextInput中,我们使用`$$this.proName`进行双向绑定,但需要确认是否在组件中正确声明了`proName`。在代码中,我们确实有`@Local proName: string = '';`,所以声明没有问题。 2. **路由跳转问题**:可能`pages/Product`页面不存在,或者路由配置不正确。但根据之前代码,我们假设路由配置正确。 3. **日志报错的具体内容**:由于没有提供具体的错误信息,我们需要检查可能出现的错误。 4. **TextInput的双向绑定问题**:在HarmonyOS ArkUI中,使用`$$`进行双向绑定需要配合`@State`或`@Local`等装饰器。这里使用的是`@Local`,应该是可以的。但是,注意在TextInput中,我们使用了`$$this.proName`,这里的`this`指向是否正确? 在`centerBuilder`中,我们使用了`$$this.proName`,这个`this`指向的是当前组件实例吗?在ArkUI中,`@Builder`函数内部的`this`指向的是当前组件实例,所以应该可以访问到`proName`。 但是,在`centerBuilder`中,我们使用`TextInput`的代码是: ```typescript TextInput({placeholder:'请输入商品名....',text:$$this.proName}) ``` 这里使用`$$this.proName`进行双向绑定,当输入时,`this.proName`应该会更新。然后在按钮点击时,我们使用`this.proName`作为参数传递。 **可能的问题**:在`centerBuilder`中,`this`的指向问题。因为`centerBuilder`是一个函数,它被传递给`IBestPopup`的`contentBuilder`属性。在构建时,`this`应该指向当前组件实例,因为它是组件的成员函数(使用`@Builder`装饰)。所以,理论上没有问题。 **但是**,在ArkUI中,如果使用`this`,需要确保在构建时`this`确实指向组件实例。我们可以通过打印日志来检查。 **建议的调试步骤**: 1. 在`centerBuilder`中,尝试打印`this`,看是否是组件实例。 2. 在按钮点击事件中,打印`this.proName`,看是否获取到了输入的。 如果打印发现`this`不是组件实例,那么可能是作用域问题。在ArkUI中,为了避免作用域问题,我们通常使用箭头函数来确保`this`指向正确。 但是,在`@Builder`函数内部,`this`应该指向组件实例。如果发现不指向组件实例,我们可以通过以下方式解决: - 在组件中定义一个指向组件实例的变量,例如`self = this;`,然后在`centerBuilder`中使用`self.proName`。 但是,由于`@Builder`函数是组件的方法,所以直接使用`this`应该没问题。 **另一种可能**:在点击按钮时,`this.proName`可能为空,但不会导致报错,除非在目标页面中处理参数时出错。 **错误日志分析**:我们需要具体的错误信息。如果错误发生在路由跳转时,可能是目标页面在接收到`proName`参数时处理不当。 例如,在`pages/Product`页面中,我们通过`this.router.getParams()`获取参数,并赋给`proName`。如果获取参数的方式不对,可能会导致错误。 **总结**:由于没有具体错误信息,我们只能推测。建议在目标页面(Product)的`aboutToAppear`或`onPageShow`中打印接收到的参数,确保参数正确传递。 另外,在搜索按钮的点击事件中,我们可以先打印`this.proName`,确保有,然后再跳转。 修改代码,添加日志: ```typescript Button('搜索') .onClick(() => { log.info(`搜索关键词:${this.proName}`); // 添加日志 this.visible = false; this.router.pushUrl({ url: "pages/Product", params: { proName: this.proName } }); }) ``` 然后在控制台查看日志输出,确认`this.proName`是否有。 如果日志显示`this.proName`为`undefined`,则说明双向绑定没有成功。这时,我们需要检查双向绑定的方式。 在ArkUI中,TextInput的双向绑定可以这样写: ```typescript TextInput({ placeholder: '请输入商品名....', text: $$this.proName }) ``` 或者,也可以使用自定义组件变量,但这里我们使用的是组件的`@Local`变量,所以应该可以。 **另一种写法**:如果不确定双向绑定,可以改为事件监听的方式: ```typescript TextInput({ placeholder: '请输入商品名....' }) .onChange((value) => { this.proName = value; }) ``` 这样,当输入变化时,我们手动更新`this.proName`。 **修改建议**: 将TextInput的绑定改为事件监听方式: ```typescript TextInput({placeholder:'请输入商品名....'}) .onChange((value:string)=>{ this.proName=value; }) ``` 然后再次测试。 如果问题仍然存在,请提供具体的错误日志。 **注意**:在`centerBuilder`中,我们使用了`$$this.proName`,如果这种方式在Popup中不生效,可能是因为Popup的内容构建时机或上下文问题。改为事件监听方式更可靠。 因此,我们修改`centerBuilder`中的TextInput部分: ```typescript Row(){ TextInput({placeholder:'请输入商品名....'}) .width('80%') .contentType(ContentType.USER_NAME) .onChange((value: string) => { this.proName = value; }) Button('搜索') .backgroundColor('blue') .fontColor('#fff') .type(ButtonType.Normal) .width(70) .height(40) .onClick(()=>{ this.visible=false this.router.pushUrl({ url:"pages/Product", params:{ proName:this.proName } }) }) } ``` 这样,无论双向绑定是否存在问题,我们都能确保输入的被正确赋给`this.proName`。 **最后**:如果问题解决,则说明之前双向绑定可能存在问题;如果问题依旧,则需要查看具体的错误日志。 由于问题描述中没有具体错误信息,我们只能给出这些可能的解决方案。</think>根据您提供的代码,点击搜索按钮时日志报错的原因可能有以下几点: ### 主要原因分析: 1. **TextInput 双向绑定问题**: ```typescript TextInput({placeholder:'请输入商品名....',text:$$this.proName}) ``` HarmonyOS 的 `$$` 双向绑定语法在 TextInput 中使用时,**必须配合 `@State` 装饰器**,而您使用的是 `@Local` 装饰器: ```diff - @Local proName:string='' + @State proName:string='' ``` `@Local` 装饰器不支持双向绑定,会导致状态更新异常。 2. **路由参数传递问题**: 在搜索跳转时传递的参数格式不正确: ```typescript this.router.pushUrl({ url:"pages/Product", params:{ proName:this.proName } }) ``` 目标页面 `Product` 需要通过 `router.getParams()` 获取参数,但您没有处理参数类型转换: ```typescript // Product.ts const routeParams = this.router.getParams() as ProNameId; // 类型断言可能失败 ``` 3. **页面栈管理问题**: 多次打开/关闭弹出层可能导致路由状态异常: ```typescript this.visible = true/false // 弹出层状态切换 ``` ### 完整修复方案: ```typescript @ComponentV2 export struct Cate { router = this.getUIContext().getRouter() @Local visible: boolean = false @Local list: FirstCate[] = [] @Local groupId: string = "group" @Local active: number = 0 @Local secondList: ScondCate[] = [] // 修复1:改用@State支持双向绑定 @State proName: string = '' // ...其他方法保持不变... @Builder centerBuilder() { Column(){ // ...导航栏代码... Row(){ // 修复2:使用@State后双向绑定生效 TextInput({placeholder:'请输入商品名....', text: $$this.proName}) .width('80%') Button('搜索') .onClick(() => { this.visible = false // 修复3:添加参数校验 if (this.proName.trim() === '') { // 添加空提示 prompt.showToast({ message: "请输入搜索内容" }) return } this.router.pushUrl({ url: "pages/Product", params: { proName: this.proName } }) }) } // ...其他代码... } } // ...build方法保持不变... } ``` ### 目标页面接收参数优化 (Product.ts): ```typescript // 修复4:安全获取路由参数 const routeParams = this.router.getParams(); const proName = routeParams?.proName?.toString() || ''; // 安全转换 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值