天天看點

微信小程式實作搜尋功能以及效果(超詳細)

我們先來看一下實作哪些功能:

1 搜尋曆史記錄以及清空曆史記錄

2 熱門搜尋推薦以及更新推薦内容

3 根據輸入框輸入的内容來自動搜尋相關查詢,背景邏輯是模糊查詢,背景就先不扯了

這裡我用的是自己定義的虛拟資料,暫時沒用背景接口,可能有點問題,希望大家指出,共同解決,一起進步

好了廢話就不多說了,我們先看看代碼吧

wxml

<!-- 自定義頂部導航 S -->
<view class="navbar custom-class" style='height:{{navHeight}}px;'>
  <view class="navbar-action-wrap navbar-action-group row item-center" style='top:{{navTop}}px;'>
    <image style="width: 1rem; height: 1.2rem; " src="{{leftIcon}}" catchtap="goBack"></image>
  </view>
  <view class='navbar-title' style='top:{{navTop}}px'>
    <view class="search-input">
      <span class="search-con">
        <view class="center-30f2b4d">
          <!-- 自定義區域 -->
          <image class="icon" src="{{searchIcon}}" catchtap="searchbegin" data-postname="{{inputValue}}"></image>
          <input class="search-size" confirm-type="search" value="{{inputValue}}" type="text" bindinput="getInputValue" placeholder="搜尋品牌或商品" placeholder-class="phcolor"></input>
        </view>
      </span>
    </view>
  </view>
</view>
<!-- 自定義頂部導航 E -->
<view class="read-in">
  <!-- 最近搜尋 S -->
    <view class="headline" wx:if="{{historyStorage.length!=0}}" hidden="{{historyStorageShow?false:true}}">
      <view class="head-headline justify">
        <view class="headline-size">最近搜尋</view>
        <view class="right size" catchtap="remove">清除</view>
      </view>
      <!-- 最近搜尋内容 S -->
      <view class="lately-main">
        <view class="chunk" wx:for="{{historyStorage}}" wx:key="index" bindtap='routeToSearchResPage' data-index='{{index}}'>
          <text>{{item}}</text>
        </view>
      </view>
      <!-- 最近搜尋内容 E -->
    </view>
    <!-- 最近搜尋 E -->
    <!-- 熱門搜尋 S -->
    <view class="headline">
      <view class="head-headline">
        <view class="headline-size">熱門搜尋</view> 
        <view class="liang">
          <view class="low-bo">
            <image class="icon-eye low-bottom" bindtap="reye" src="{{eyeIconOne}}" hidden="{{!eye}}"></image> 
            <image class="icon-eye low-bottom" bindtap="reye" src="{{eyeIcon}}" hidden="{{eye}}"></image> 
          </view>
          <view class="right size" bindtap="changeother">換一批</view>
        </view>
      </view>
      <!-- 熱門推薦内容 S -->
      <view class="lately-main" hidden="{{eye?false:true}}">
        <view class="chunk" wx:for="{{falg ? hotsearch1 : hotsearch2}}" wx:key="index">
          <text>{{item.title}}</text>
        </view>
      </view>
      <!-- 熱門推薦内容 E -->
    </view>
    <!-- 熱門搜尋 E -->
</view>


<!--搜尋結果-->
<view class="searchresult" wx:if="{{inputValue != ''}}" hidden="{{searchresult?false:true}}">
  <view class="result" wx:for="{{searchResult}}" catchtap="searchbegin" wx:key="index" bindtap="getInputValue" data-postname="{{item.result}}">
    <view>{{item.result}}</view>
    <image src="{{upperLeftArrow}}"></image>
  </view>
</view>      

大家應該都能看懂吧,可能有人就會問了 

<view class="result" wx:for="{{searchResult}}" catchtap="searchbegin" wx:key="index" bindtap="getInputValue" data-postname="{{item.result}}">
    <view>{{item.result}}</view>
    <image src="{{upperLeftArrow}}"></image>
  </view>      

為什麼這個wx:for用了兩個點選事件,catchtap和bindtap,如果用兩個catchtap或者bindtap可不可以,這裡我就告訴你,不可以,親測,會有沖突

我們先回顧一下catchtap和bindtap差別: 

  • DOM模型是一個樹形結構,在DOM模型中,HTML元素是有層次的。當一個HTML元素上産生一個事件時,該事件會在DOM樹中元素節點與根節點之間按特定的順序傳播,路徑所經過的節點都會收到該事件,這個傳播過程就是DOM事件流。
  • JS冒泡事件:當一個元素上的事件被觸發的時候,比如說滑鼠點選了一個按鈕,同樣的事件将會在那個元素的(所有祖先元素)中被觸發。這 一過程被稱為事件冒泡;這個事件從原始元素開始一直冒泡到DOM樹的最上層

共同點:

在微信小程式的事件機制中,bindtap和catchtap都可以觸發一個元件的點選事件

差別:

bindtap不能阻止事件冒泡 

catchtap可以阻止事件冒泡

wxss

page {
    background: white;
}
.navbar {
  width: 100%;
  overflow: hidden;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10;
  flex-shrink: 0;
  background-color: white;
}

.navbar-title {
  width: 100%;
  box-sizing: border-box;
  padding-left: 40px;
  padding-right: 120px;
  height: 33px;
  line-height: 33px;
  position: fixed;
  left: 0;
  z-index: 10;
  color: #333;
  font-size: 16px;
  font-weight: bold;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
  display: flex;
}

.navbar-action-wrap {
  display: -webkit-flex;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
  left: 10px;
  z-index: 11;
  line-height: 1;
  padding-top: 4px;
  padding-bottom: 4px;
  position: fixed;
}

.navbar-action-group {
  border-radius: 20px;
  overflow: hidden;
}

.navbar-action_item {
  padding: 3px 0;
  color: #333;
}

.navbar-action-group .navbar-action_item {
  border-right: 1px solid #f0f0f0;
  padding: 3px 14px;
}

.navbar-action-group .last {
  border-right: none;
}

.navbar-title-size {
  font-size: 10px;
  margin-right: 20rpx;
  align-self: center;
  margin: 0 auto;
}

.navbar-title-size.active {
  color: red;
  border-bottom: 2px solid red;
}

.scroll-box {
  position: absolute;
  height: 100%;
}

.search-input {
  width: 100%;
  height: 28px;
  line-height: 28px;
  background: #f6f6f6;
  border-radius: 30rpx;
  /* margin-top: 2px; */
  font-size: 25rpx;
}

.search-con {
  display: flex;
  align-items: center;
}
.search-con .center-30f2b4d {
  height: 28px;
  line-height: 28px;
  flex: 1;
  display: flex;
  align-items: center;
}
.search-con .center-30f2b4d .icon {
  width: 15px;
  height: 15px;
  align-self: center;
  margin: 0 10px;
}
.search-con .center-30f2b4d .search-size {
  width: 60%; 
  font-size: 12px;
  font-family: "微軟雅黑";
}
.phcolor {
  color: #D3D3D3;
}
/* nav E */
/* 标題部分 */
.read-in {
  margin-top: 64px;
  padding: 0 40rpx;
}
.headline {
  padding-top: .5rem;
}

.head-headline {
  width: 100%;
  height: 45rpx;
  position: relative;
  display: flex;
}
.liang {
  width: 100%;
  display: flex;
  justify-content: space-between;
}
.justify {
  display: flex;
  justify-content: space-between;
}
.headline-size {
  width: 185rpx;
  font-size: 35rpx;
  float: left;
}

.low-bo {
  /* flex: 1; */
  height: 45rpx;
  position: relative;
  align-self: center;
}
.low-bottom {
  /* position:absolute; */
  bottom:0px;
  padding:0 10rpx  0;
  margin:0px;
}
.size {
  /* flex: 1; */
  float: right;
  font-size: 30rpx;
  color: #d4237a;
  /* position: absolute; */
  bottom:0px;
  align-self: center;
 
}

/* 内容部分 */
.lately-main {
  margin-top: 20rpx;
  overflow: hidden; 
}
.lately-main .chunk {
  display: inline-block;
  font-size: 25rpx;
  line-height: 20rpx;
  padding: 20rpx 20rpx;
  background: #f5f5f5;
  margin-right: 30rpx;
  border: 1px solid #DCDCDC;
  border-radius: 30rpx;
  margin-bottom: 30rpx;
  float: left;
}

.searchresult {
  margin-top: 20px; 
  position: absolute;
  top: 55px;
  left: 0;
  width: 100%;
  background: #fff;
}
.result {
  height: 50px;
  line-height: 50px;
  text-align: left;
  border-bottom: 1px solid #eee;
  padding: 0 30rpx;
  color: #333;
  font-family: "微軟雅黑";
  font-size: 30rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.result image {
  width: 50rpx;
  height: 50rpx;
}      

 css就不用說太多了吧,不過有個小bug,我在調試的時候發現的,不過很好解決,這裡就不多說了

js

const App = getApp()
Page({

  /**
   * 頁面的初始資料
   */
  data: {
    // 自定義頂部導航
    navHeight: App.globalData.navHeight,
    navTop: App.globalData.navTop,
    // 圖示
    leftIcon: "../../../img/icon/icon-left.png",
    searchIcon: "../../../img/icon/icon-search.png",
    eyeIconOne: "../../../img/icon/icon-eye-one.png",
    eyeIcon: "../../../img/icon/icon-eye.png",
    upperLeftArrow: "../../../img/icon/icon-upper-left-arrow.png",
    recommend: [ //熱門推薦
      {
        title: "冰箱"
      },
      {
        title: "紅魔手機"
      },
      {
        title: "洗衣機"
      },
      {
        title: "電視機"
      },
      {
        title: "冰箱 雙門"
      },
      {
        title: "海爾洗衣機 滾筒"
      },
      {
        title: "手機自營"
      },
      {
        title: "小天鵝洗衣機全自動"
      },
      {
        title: "手機"
      },
      {
        title: "筆記本"
      }
    ],
    historyStorage: [],        //曆史搜尋
    historyStorageShow: false,
    falg: true,         //換一批
    hotsearch1: [{ title: "短褲" }, { title: "背帶裙" }, { title: "牛仔褲男" }, { title: "運動 休閑男鞋" }, { title: "蕾絲連衣裙" }, { title: "電視" }, { title: "長裙" }, { title: "oppo" }, { title: "藍牙耳機" }, { title: "女包" }, { title: "格力空調" }, { title: "魅族" }],
    hotsearch2: [{ title: "平闆電腦" }, { title: "耳機" }, { title: "男鞋" }, { title: "iPhone" }, { title: "蕾絲連衣裙" }, { title: "電視" }, { title: "長裙" }, { title: "oppo" }, { title: "藍牙耳機" }, { title: "女包" }, { title: "格力空調" }, { title: "魅族" }],
    // searchresult: false,
    inputValue: "",        //輸入框輸入的值
    replaceValue: "",     //替換輸入框的值
    eye: true,        //顯示隐藏
    searchresult: false,
    searchResult: [{ result: "蘋果手機" }, { result: "手機支架" }, { result: "手機自營" }, { result: "手機套" }, { result: "手機膜" }, { result: "手機卡" }, { result: "手機報" }, { result: "蘋果手機殼" }, { result: "手機車載支架" }]//虛拟的查詢結果
  },
  // 點選傳回上一級
  goBack: function() {
    let pages = getCurrentPages();      //擷取小程式頁面棧
    let beforePage = pages[pages.length - 2];       //擷取上個頁面的執行個體對象
    beforePage.setData({
      txt: "修改資料了"
    })
    beforePage.goUpdate();           //觸發上個頁面自定義的go_update()方法
    wx.navigateBack({
      delta: 1
    })
  },
  /**
   * 擷取頂部固定高度
   */
  attached: function() {
    this.setData({
      navHeight: App.globalData.navHeight,
      navTop: App.globalData.navTop,
    })
  },
  /**
   * 換一批操作
   */
  changeother: function () {
    this.setData({
      falg: !this.data.falg
    })
  },

  /**
   * 熱門搜尋顯示隐藏
   */
  reye: function () {
    this.setData({
      eye: !this.data.eye
    })
  },

  /**
   * 清除
   */
  remove: function () {
    var _this = this
    wx: wx.showModal({
      content: '确認清除所有曆史記錄?',
      success: function (res) {
        if (res.confirm) {
          wx: wx.removeStorage({
            key: 'historyStorage',
            success: function (res) {
              _this.setData({
                historyStorage: []
              })
              wx.setStorageSync("historyStorage", [])
            },
          })
        } else {
          console.log("點選取消")
        }
      },
    })
  },


  /**
   * 擷取input的值
   */
  getInputValue(e) {
    // console.log("擷取value值",e.detail)   // {value: "ff", cursor: 2}
    this.setData({
      inputValue: e.detail.value
    })
    this.setData({
      searchresult: true,
    })
  },

  /**
   * 點選搜尋送出跳轉并存儲曆史記錄
   */
  searchbegin: function (e) {
    let _this = this
    var data = e.currentTarget.dataset;
    _this.data.replaceValue = e.currentTarget.dataset.postname
    // _this.data.replaceValue = 
    wx: wx.setStorage({
      key: 'historyStorage',
      data: _this.data.historyStorage.concat(_this.data.inputValue),
      data: _this.data.historyStorage.concat(_this.data.replaceValue)
    })
    // console.log(_this.data.inputValue)
    // console.log(_this.data.historyStorage)
    wx.navigateTo({
      url: '../../commodity/commodity-search-list/index?postName=' + data['postname']
    })
  },

  /**
   * 生命周期函數--監聽頁面加載
   */
  onLoad: function(options) {
    // 曆史搜尋
    let that = this
    wx.getStorage({
      key: 'historyStorage',
      success: function (res) {
        console.log(res.data)
        that.setData({
          historyStorageShow: true,
          historyStorage: res.data
        })
      }
    })
  },
  //點選進入詳情頁
  goToList: function (e) {
    
  },
  goUpdate: function() {
    this.onLoad()
    console.log("我更新啦")
  },
  /**
   * 生命周期函數--監聽頁面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函數--監聽頁面顯示
   */
  onShow: function() {

  },

  /**
   * 生命周期函數--監聽頁面隐藏
   */
  onHide: function() {

  },

  /**
   * 生命周期函數--監聽頁面解除安裝
   */
  onUnload: function() {

  },

  /**
   * 頁面相關事件處理函數--監聽使用者下拉動作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 頁面上拉觸底事件的處理函數
   */
  onReachBottom: function() {

  },

  /**
   * 使用者點選右上角分享
   */
  onShareAppMessage: function() {

  }
})      

js基本上都有備注,這裡就不說太多了,我就說一下這個函數吧

searchbegin: function (e) {
    let _this = this
    var data = e.currentTarget.dataset;
    _this.data.replaceValue = e.currentTarget.dataset.postname
    // _this.data.replaceValue = 
    wx: wx.setStorage({
      key: 'historyStorage',
      data: _this.data.historyStorage.concat(_this.data.inputValue),
      data: _this.data.historyStorage.concat(_this.data.replaceValue)
    })
    // console.log(_this.data.inputValue)
    // console.log(_this.data.historyStorage)
    wx.navigateTo({
      url: '../../commodity/commodity-search-list/index?postName=' + data['postname']
    })
  },      

自定義的data在點選執行這個函數的時候擷取input框輸入的value值,這個應該都明白吧

_this.data.replaceValue這個是在data裡面定義了一個變量名為replaceValue,然後将e.currentTarget.dataset.postname擷取到的值指派給replaceValue,下面的就不用多說了吧,将拿到的值存儲到historyStorage空清單裡面,下面的是點選搜尋跳轉到的結果清單

最後給大家看一下效果圖吧

微信小程式實作搜尋功能以及效果(超詳細)
微信小程式實作搜尋功能以及效果(超詳細)
微信小程式實作搜尋功能以及效果(超詳細)
微信小程式實作搜尋功能以及效果(超詳細)
微信小程式實作搜尋功能以及效果(超詳細)
微信小程式實作搜尋功能以及效果(超詳細)