分类和搜索 uni-ui 数据缓存

<uni-icons type="search" size="15"></uni-icons>

search - 首页搜索实现吸顶效果(粘性布局)

  1. 在 home 首页定义如下的 UI 结构:
<MySearch class="my-search"></MySearch>
  1. 通过如下的样式实现吸顶的效果:
.my-search {
  // 设置定位效果为“吸顶”
  position: sticky;
  // 吸顶的“位置”
  top: 0;
  // 提高层级,防止被轮播图覆盖
  z-index: 999;
}

准备一个搜索页

  • 来到subpkg右键新建页面,输入search,用来做搜索页面

search - 点击自定义组件跳转到搜索页

  • 此时需要在 homecate 里给我们封装的顶部的自定义组件加click,但是我们要知道,给自己封装的组件写@事件名,那必须组件内部要加$emit('事件名'),不然是没效果的
  • 所以来到 components/mysearch给内容盒子加点击事件,点击事件里写$emit
<view class="search-content" @click="bindClick">
      <uni-icons type="search" size="15"></uni-icons>搜索
    </view>
methods: {
    bindClick() {
      this.$emit('click')
    }
  }
  • 然后就可以来到 homecate找到MySearch加点击事件和对应的方法即可
<MySearch @click="toSearch" class="my-search"></MySearch>
toSearch () {
    uni.navigateTo({
          url: "/subpkg/search/search"
        })
}

search - 搜索页基本布局

  • 放一个view,view里放一个 uni-ui里面的 搜索栏(快捷键usearch)
<view>
  <view class="search-box">
    <uni-search-bar v-model="key" radius="100" placeholder="请输入搜索内容" cancelButton="none" @confirm="search" />
  </view>
  </view>
  • 让这个div设置背景颜色
.search-box {
  background-color: #c00000;
}

search - 搜索建议区域布局

<!-- 搜索结果列表区域 -->
<uni-list>
  <uni-list-item v-for="item in 10" title="列表文字" link></uni-list-item>
</uni-list>

search - 历史记录布局

  • 一个大view,里面包上面和下面两个小view,上面的view放标题和垃圾删除的图标,下面放tag
<!-- 搜索历史区域 -->
  <view class="history-box">
    <view class="title">
      <text>搜索历史</text>
      <uni-icons type="trash" size="18"></uni-icons>
    </view>
    <!-- 具体的每一项历史记录 -->
    <view class="history-item">
      <uni-tag class="tag" v-for="item in 12" text="标签1" type="success" />
    </view>
  </view>

  • 对应的布局:标题部分用弹性布局,设置它们一左一右,并给左右间距
    • 标签每一项部分也用弹性布局,但是允许换行。然后给每一项设置右间距和下间距即可
.history-box {
  .title {
    padding: 0 10px;
    display: flex;
    font-size: 14px;
    justify-content: space-between;
  }

  .history-item {
    display: flex;
    flex-wrap: wrap;
    margin-top: 15px;
    padding-left: 30px;

    .tag {
      margin-right: 10px;
      margin-bottom: 10px;
    }
  }
}

search - 搜索建议与搜索历史布局只显示一个

  • 根据需要观察得到结论,搜索框里有内容就显示搜索结果,没内容就显示搜索历史
  • 所以给他们加v-if与v-else
<uni-list v-if="key != ''">
  <uni-list-item v-for="item in 10" title="列表文字" link></uni-list-item>
</uni-list>

<!-- 搜索历史区域 -->
<view v-else class="history-box">
        ......
  </view>

search - 根据输入关键词查询搜索结果

  • 要给搜索框加input事件,因为只有input是一边输入一边触发的(把之前confirm事件删了)
<view class="search-box">
  <uni-search-bar v-model="key" radius="100" placeholder="请输入搜索内容" cancelButton="none" @input="onInput" />
</view>
  • 事件里无非就是发请求,把拿到的结果存到数组里
data() {
      return {
        key: '',
        resultList: []
      };
    },
    methods: {
      async onInput() {
        // 发请求获取搜索的结果
        const res = await uni.$http.get('goods/qsearch', {
          query: this.key
        })
        this.resultList = res.data.message
      },
    }
  • 渲染到页面
<uni-list v-if="key">
    <uni-list-item v-for="item in resultList" :key="item.goods_id" :title="item.goods_name" link>
    </uni-list-item>
  </uni-list>

设置文字一行显示,超出显示省略号

  • 通过审查元素发现只要给某个span加样式即可,但是这个span在组件内部,而默认有样式隔离的影响
  • 所以要加深度作用选择器才有用
::v-deep .uni-list-item__content-title {
  span {
    display: inline-block;
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

使用防抖优化请求

  • 此时存在问题:我一边输就一边发请求,会造成性能浪费
  • 根据用户习惯,应该是在没输完的时候是连续输入的,输完肯定会停顿,所以我们就应该是停顿时才去发请求
  • 要用防抖:
    • 先让代码延迟执行,并且如果短时间内不断触发,就不断关掉定时器再开心的定时器
  • 代码如下
data() {
      return {
        .....
        time: null
      };
    },
methods: {
      onInput() {
        // 每次开启新的之前,把上一次的关掉
        clearTimeout(this.time)

        this.time = setTimeout(async () => {
                    // 如果输入框为空没必要发请求,直接return
          if (this.key === '') return
          // 发请求获取搜索的结果
          const res = await uni.$http.get('goods/qsearch', {
            query: this.key
          })
          this.resultList = res.data.message
        }, 500)
      },
    }

search - 搜索结果点击跳转至商品详情页

  • 要设置跳转,uni-list-item加一个to属性即可跳转)
<uni-list-item v-for="item in resultList" :key="item.goods_id" :title="item.goods_name" link
  :to="`/subpkg/goods_detail/goods_detail?goods_id=${item.goods_id}`">
</uni-list-item>
  • 因为跳转还要携带参数,所以加:以及在里面用模板字符串拼接

给搜索框加吸顶效果

.search-wrap {
  background-color: #c00000;
  position: sticky;
  top: 0;
  z-index: 9999;
}

search - 保存历史记录并缓存数据

  • 官方文档
  • 缓存数据跟localStorage的区别在于
    • localStorage保存时如果要存复杂类型必须转JSON字符串,而这个方法不用转,直接就可以存
    • 一套代码,它会自动根据不同的环境编译成不同的代码,比如浏览器就存到localStorage,如果微信就存到微信的地方
  • 先声明一个数组用来保存历史记录
data () {
    return {
        historyList:[]
    }
}
  • 去改良 uni-tag ,v-for改成根据 historyList 来生成
<view class="history-item">
    <uni-tag v-for="(item,index) in historyList" :key="index" :text="item" type="success" />
  </view>
  • 然后在每次去做搜索建议的时候,把输入的内容存到数组里
this.time = setTimeout(async () => {
          if (this.key === '') return
          // 发请求之前我先把历史记录存起来
          // 先把输入的内容加到数组里
          this.historyList.unshift(this.key)
          // 把数组存到本地
          uni.setStorageSync('history', this.historyList)
     ............
})
  • 然后取出来给默认值
data () {
    return {
        historyList: uni.getStorageSync('history') || []
    }
}
  • 此时发现:如果输入以前就搜索过的内容会让记录多一条,所以要做一个判断,如果搜索的内容不在数组里,才允许加到数组里
if (this.historyList.indexOf(this.key) === -1) {
    // 发请求之前我先把历史记录存起来
          // 先把输入的内容加到数组里
          this.historyList.unshift(this.key)
          // 把数组存到本地
          uni.setStorageSync('history', this.historyList)
}
posted @ 2023-01-31 11:11  Cherishe  阅读(117)  评论(0)    收藏  举报