uniapp自定义搜索组件实现全部功能

详情点击链接查看
如下代码只做记录没讲解
首先在项目的components文件夹的my-search文件中
在这里插入图片描述

写入代码如下:

<template>
 <view class="my-search-container" :style="{'background-color': bgcolor}">
   <view class="my-search-box" :style="{'border-radius': radius + 'px'}" @click="searchBoxHandler">
     <!-- 使用uni-ui的组件 -->
     <icon type="search" size="17"></icon>
     <text class="placeholder">搜索</text>
   </view>
 </view>
</template>

<script>
  export default {
    
    name:"my-search",
    data() {
      return {
        
      };
    },
    props: {
      // 背景颜色
      bgcolor: {
        type: String,
        default: '#C00000'
      },
      // 圆角尺寸
      radius: {
        type: Number,
        // 单位是 px
        default: 18
      }
    },
    methods: {
      // 点击了模拟的 input 输入框
      searchBoxHandler() {
        // 触发外界通过 @click 绑定的 click 事件处理函数
        this.$emit('click')
      }
    }
  }
</script>

<style lang="scss">
.my-search-container {
  // background-color: #c00000;
  height: 50px;
  padding: 0 10px;
  display: flex;
  align-items: center;
}

.my-search-box {
  height: 36px;
  background-color: #ffffff;
  // border-radius: 15px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;

  .placeholder {
    font-size: 15px;
    margin-left: 5px;
  }
}
</style>

效果展示
在这里插入图片描述

在pages文件夹中的使用者文件中

<template>
  <view>
    <!-- 使用自定义的搜索组件 -->
    <view class="search-box" >
      <!-- 动态传入背景颜色值与圆角值   -->
    <mySearch @click="gotoSearch" :bgcolor="'#c00000'" :radius="15"></mySearch>
    </view>
    <view class="scroll-view-container">
    <!-- 左侧的滚动视图区域 -->
    <scroll-view class="left-scroll-view" scroll-y :style="{height: wh + 'px'}">
    <block v-for="(item, i) in cateList" :key="i">
      <view :class="['left-scroll-view-item', i === active ? 'active' : '']" @click="activeChanged(i)">{{item.cat_name}}</view>
    </block>
    </scroll-view>
      <!-- 右侧的滚动视图区域 -->
    <!-- 右侧的滚动视图区域 -->
    <scroll-view class="right-scroll-view" scroll-y :style="{height: wh + 'px'}" :scroll-top="scrollTop">
      <view class="cate-lv2" v-for="(item2, i2) in cateLevel2" :key="i2">
        <view class="cate-lv2-title">/ {{item2.cat_name}} /</view>
        <!-- 动态渲染三级分类的列表数据 -->
        <view class="cate-lv3-list">
          <!-- 三级分类 Item 项 -->
          <view class="cate-lv3-item" v-for="(item3, i3) in item2.children" :key="i3"  @click="gotoGoodsList(item3)">
            <!-- 图片 -->
            <image :src="item3.cat_icon" mode=""></image>
            <!-- 文本 -->
            <text>{{item3.cat_name}}</text>
          </view>
        </view>
      </view>
    </scroll-view>
    </view>
  </view>
</template>


<script>
  import mySearch from "@/components/my-search/my-search.vue"
   export default {
     components:{
        mySearch
     },
     data() {
       return {
         // 窗口的可用高度 = 屏幕高度 - navigationBar高度 - tabBar 高度
         wh: 0,
        // 分类数据列表
        cateList: [],
        // 当前选中项的索引,默认让第一项被选中
        active: 0,
         // 二级分类列表
        cateLevel2: [],
      // 滚动条距离顶部的距离
          scrollTop: 0
       };
     },
     onLoad() {
       // 获取当前系统的信息
       const sysInfo = uni.getSystemInfoSync()
       // 可用高度 = 屏幕高度 - navigationBar高度 - tabBar高度 - 自定义的search组件高度
       this.wh = sysInfo.windowHeight - 50
        // 调用获取分类列表数据的方法
        this.getCateList()
     },
    methods: {
      async getCateList() {
        // 发起请求
        const { data: res } = await uni.$http.get('/api/public/v1/categories')
        // 判断是否获取失败
        if (res.meta.status !== 200) return uni.$showMsg()
        // 转存数据
        this.cateList = res.message
         // 为二级分类赋值
        this.cateLevel2 = res.message[0].children
        console.log(this.cateList)
      },
        // 选中项改变的事件处理函数
        activeChanged(i) {
          this.active = i
          // 为二级分类列表重新赋值
          this.cateLevel2 = this.cateList[i].children
          console.log(this.cateLevel2)
          // 让 scrollTop 的值在 01 之间切换
          this.scrollTop = this.scrollTop?0 :1
        } ,
        // 点击三级分类项跳转到商品列表页面
        gotoGoodsList(item3) {
          uni.navigateTo({
            url: '/subpkg/pages/goods_list/goods_list?cid=' + item3.cat_id
          })
        },
        // 跳转到分包中的搜索页面
        gotoSearch() {
          uni.navigateTo({
            url: '/subpkg/pages/search/search'
          })
        }
    }
       

   }
</script>

<style lang="scss">
.scroll-view-container {
  display: flex;

  .left-scroll-view {
    width: 120px;

    .left-scroll-view-item {
      line-height: 60px;
      background-color: #f7f7f7;
      text-align: center;
      font-size: 12px;

      // 激活项的样式
      &.active {
        background-color: #ffffff;
        position: relative;

        // 渲染激活项左侧的红色指示边线
        &::before {
          content: ' ';
          display: block;
          width: 3px;
          height: 30px;
          background-color: #c00000;
          position: absolute;
          left: 0;
          top: 50%;
          transform: translateY(-50%);
        }
      }
    }
  }
 .cate-lv2-title {
   font-size: 12px;
   font-weight: bold;
   text-align: center;
   padding: 15px 0;
 }
 .cate-lv3-list {
   display: flex;
   flex-wrap: wrap;
 
   .cate-lv3-item {
     width: 33.33%;
     margin-bottom: 10px;
     display: flex;
     flex-direction: column;
     align-items: center;
 
     image {
       width: 60px;
       height: 60px;
     }
 
     text {
       font-size: 12px;
     }
   }
 }
}
</style>

效果
在这里插入图片描述

点击搜索跳转到的搜索组件(分包内的search组件)

<template>
<view class="">
  <view class="search-box">
      <uni-search-bar :focus="true"  @input="input" cancelButton="none">
   		</uni-search-bar>
      <!-- 搜索建议列表 -->
     
  </view>
   <view class="sugg-list"  v-if="searchResults.length !== 0">
        <view class="sugg-item" v-for="(item, i) in searchResults" :key="i" @click="gotoDetail(item.goods_id)">
          <view class="goods-name">{{item.goods_name}}</view>
          <uni-icons type="arrowright" size="16"></uni-icons>
        </view>
      </view>
      <!-- 搜索历史 -->
      <view class="history-box" v-else>
        <!-- 标题区域 -->
        <view class="history-title">
          <text>搜索历史</text>
         <uni-icons type="trash" size="17" @click="cleanHistory"></uni-icons>
        </view>
        <!-- 列表区域 -->
        <view class="history-list">
          <uni-tag :text="item" v-for="(item, i) in historys" :key="i"  @click="gotoGoodsList(item)">
            <text style="margin: 10rpx;border: 1rpx solid #999999;">{{item}}</text>
          </uni-tag>
        </view>
      </view>
</view>
</template>

<script>
  export default {
    data() {
      return {
            // 延时器的 timerId
            timer: null,
            // 搜索关键词
            kw: '',
            // 搜索结果列表
            searchResults: [],
            // 搜索关键词的历史记录
            historyList: ['a', 'app', 'apple']
      };
    },
    onLoad(){
       this.historyList = JSON.parse(uni.getStorageSync('kw') || '[]')
    },
    methods: {
      input(e) {
        // 清除 timer 对应的延时器
        clearTimeout(this.timer)
        // 重新启动一个延时器,并把 timerId 赋值给 this.timer
        this.timer = setTimeout(() => {
          // 如果 500 毫秒内,没有触发新的输入事件,则为搜索关键词赋值
          this.kw = e
          console.log(this.kw)
          this.getSearchList()
        }, 500)
      },
      // 根据搜索关键词,搜索商品建议列表
      async getSearchList() {
        // 判断关键词是否为空
        if (this.kw === '') {
          this.searchResults = []
          return
        }
        // 发起请求,获取搜索建议列表
        const { data: res } = await uni.$http.get('/api/public/v1/goods/qsearch', { query: this.kw })
        if (res.meta.status !== 200) return uni.$showMsg()
        this.searchResults = res.message
        console.log(res.message)
        if(res.message.length==0){
          console.log(111)
          uni.showToast({
            title:"暂无相关内容",
            icon:"none"
          })
        }else{
          this.saveSearchHistory()
        }
      },
      gotoDetail(goods_id) {
        uni.navigateTo({
          // 指定详情页面的 URL 地址,并传递 goods_id 参数
          url: '/subpkg/pages/goods_detail/goods_detail?goods_id=' + goods_id
        })
      },
      // 保存搜索关键词为历史记录
      saveSearchHistory() {
        const set = new Set(this.historyList)
        set.delete(this.kw)
        set.add(this.kw)
        this.historyList = Array.from(set)
        // 调用 uni.setStorageSync(key, value) 将搜索历史记录持久化存储到本地
        uni.setStorageSync('kw', JSON.stringify(this.historyList))
      },
      // 清空搜索历史记录
      cleanHistory() {
        // 清空 data 中保存的搜索历史
        this.historyList = []
        // 清空本地存储中记录的搜索历史
        uni.setStorageSync('kw', '[]')
      },
      // 点击跳转到商品列表页面
      gotoGoodsList(kw) {
        uni.navigateTo({
          url: '/subpkg/pages/goods_list/goods_list?query=' + kw
        })
      }
    },
    computed: {
      historys() {
        // 注意:由于数组是引用类型,所以不要直接基于原数组调用 reverse 方法,以免修改原数组中元素的顺序
        // 而是应该新建一个内存无关的数组,再进行 reverse 反转
        return [...this.historyList].reverse()
      }
    }
  }
</script>

<style lang="scss">
.search-box {
  position: sticky;
  top: 0;
  z-index: 999;
  background: #c00000;
  padding: 10rpx;
  align-items: center;
  input{
   height: 36px;
   background-color: #ffffff;
   border-radius: 15px;
   width: 100%;
   display: flex;
   align-items: center;
   justify-content: center;
   
   .placeholder {
     font-size: 15px;
     margin-left: 5px;
   }
  }
}
.sugg-list {
  padding: 0 5px;

  .sugg-item {
    font-size: 12px;
    padding: 13px 0;
    border-bottom: 1px solid #efefef;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .goods-name {
      // 文字不允许换行(单行文本)
      white-space: nowrap;
      // 溢出部分隐藏
      overflow: hidden;
      // 文本溢出后,使用 ... 代替
      text-overflow: ellipsis;
      margin-right: 3px;
    }
  }
}
.history-box {
  padding: 0 5px;

  .history-title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 40px;
    font-size: 13px;
    border-bottom: 1px solid #efefef;
  }

  .history-list {
    display: flex;
    flex-wrap: wrap;

    .uni-tag {
      margin-top: 5px;
      margin-right: 5px;
    }
  }
}
</style>


效果
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值