小程序实现搜索效果

首页入口
小程序实现搜索效果

进入搜索页
小程序实现搜索效果

搜索结果页
小程序实现搜索效果
小程序实现搜索效果

后台提供三个接口

<?php

/**
 * 搜索商品
 */
class SearchAction extends CommonAction{
    public function _initialize(){
        parent::_initialize();
    }

    /**
     * 获取搜索历史和热门搜索
     */
    public function getHotAndHistory() {
        if (!$uid = $_POST['uid']) {
            $this->json->setErr('10001', '缺少用户id');
            $this->json->Send();
        }

        // 历史
        $data['history'] = [];
        $search_history = M('search_history');
        $search_history_list = $search_history->where(['uid'=>$uid,'status'=>1])->order('id desc')->select();
        foreach ($search_history_list as $k=>$v) {
            $data['history'][] = $v['keywords'];
        }
        // 热门
        $configs = M('configs');
        $hot_search = $configs->where(['this_key'=>'hot_search'])->getField('this_value');
        $data['hot'] = explode(',',$hot_search); // 爆炸成数组
        $this->json->S($data);
    }

    /**
     * 搜索数据
     */
    public function searchData() {
        if (!$uid = $_POST['uid']) {
            $this->json->setErr('10001', '缺少用户id');
            $this->json->Send();
        }

        if (!$keywords = $_POST['keywords']) {
            $this->json->setErr('10001', '请输入要查询的内容');
            $this->json->Send();
        }

        if (!isset($_POST['page']) || $_POST['page'] < 1) {
            $_POST['page'] = 1;
        }

        if (!isset($_POST['page_size']) || $_POST['page_size'] < 1) {
            $_POST['page_size'] = C('PAGE_NORMAL_COUNT');
        }

        $page      = $_POST['page'];
        $page_size = $_POST['page_size'];

        if ($page == 1) {
            // 删除之前的记录
            $search_history = M('search_history');
            $search_history->where(['uid'=>$uid,'keywords'=>$keywords])->save(['status'=>0,'update_time'=>time()]);
            // 添加新的记录
            $search_history->add(['uid'=>$uid,'keywords'=>$keywords,'update_time'=>time(),'create_time'=>time()]);
        }

        $where['title']    = ['like','%'.$keywords.'%'];
        $where['status'] = 1; // 显示
        $where['is_del'] = 0; // 未删除
        $where['spec_main'] = 1; // 是否主商品

        // 获取总数
        $product = M('product');
        $count       = $product->where($where)->count();
        $total_page  = ceil($count / $page_size);

        if ($page > $total_page) {
            $return_data = ['data_list' => [], 'total_page' => $total_page, 'current_page' => $page];
            $this->json->S($return_data, '没有更多了');
        }

        $data_list = $product->where($where)
            ->order('id desc')
            ->limit((($page - 1) * $page_size) . ',' . $page_size)
            ->field('id,title,title_img,sales_count,price')
            ->select();


        if ($data_list) {
            vendor('Func.Math');
            foreach ($data_list as $k => &$v) {
                $v['price']          = Math::div($v['price'], 100);
            }
        }

        $out_data    = $data_list ?: [];
        $return_data = ['data_list' => $out_data, 'total_page' => $total_page, 'current_page' => $page];
        $this->json->S($return_data);
    }

    /**
     * 清除数据
     */
    public function clearData() {
        if (!$uid = $_POST['uid']) {
            $this->json->setErr('10001', '缺少用户id');
            $this->json->Send();
        }
        // 删除之前的记录
        $search_history = M('search_history');
        $clear_res = $search_history->where(['uid'=>$uid])->save(['status'=>0,'update_time'=>time()]);
        if ($clear_res !== false) {
            $this->json->S();
        } else {
            $this->json->E('清理失败');
        }
    }
}

搜索页面

<view class="search">
    <view class="search-container">
        <view class="search-left">
            <image class="search-image" src="/images/index/search.png" />
            <input class="search-input"  placeholder="请输入你喜欢的商品" bindinput='watchSearch'/>
        </view>
        <view class="search-btn" data-keywords="{{keywords}}" bindtap="go_to_search_result">搜索</view>
    </view>
</view>
<view class="history">
    <view class="history-title">
        <view class="history-title-left">搜索历史</view>
        <view class="history-title-right" bindtap="clearSearchHistory">清除历史</view>
    </view>
    <view class="history-content">
        <block wx:if="{{index_data.history != false}}">
            <block wx:for="{{index_data.history}}" wx:key="id">
                <view class="history-item" data-keywords="{{item}}" bindtap="go_to_search_result">{{item}}</view>
            </block>
        </block>
    </view>
</view>
<view class="hot">
    <view class="hot-title">热门搜索</view>
    <view class="hot-content">
         <block wx:if="{{index_data.hot != false}}">
            <block wx:for="{{index_data.hot}}" wx:key="id">
                <view class="hot-item" data-keywords="{{item}}" bindtap="go_to_search_result">{{item}}</view>
            </block>
        </block>
    </view>
</view>

搜索页面业务逻辑

import { initNoPage } from "../../common/requestData";
import Storage from "../../common/auth/Storage";
import tips from "../../common/tips";
import request from "../../common/request";

const app = getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    index_data: [],
    keywords: ''
  },
  // 清理
  clearSearchHistory: function () {
    tips.showConfirm("您确认清理搜索历史吗").then(() => {
      const uid = app.globalData.uid || Storage.get().uid;
      request("clearData", { uid: uid })
        .then(() => {
          tips.showMsg("清理成功");
          this.setData({
            "index_data.history": []
          });
        })
        .catch(({ errdesc }) => {
          return tips.showMsg(errdesc);
        });
    });
  },
  // 监听输入
  watchSearch: function (event) {
    console.log(event.detail.value);
    let keywords = event.detail.value;
    // 设置值
    this.setData({
      "keywords": keywords
    });
  },
  go_to_search_result({
    currentTarget: {
      dataset: { keywords }
    }
  }) {
    console.log(keywords);
    if (keywords == '') {
      return tips.showMsg("请输入要搜索的内容");
    }
    wx.navigateTo({
      url: "/pages/search/result/index?keywords=" + keywords
    });
  },


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 展示
   */
  onShow: function (options) {
    const uid = app.globalData.uid || Storage.get().uid;
    console.log(uid);
    // 初始化
    initNoPage(this, [
      {
        api: "getHotAndHistory",
        outDataName: "index_data",
        inData: { 'uid': uid }
      }
    ]);
    setTimeout(() => {
      this.setData({
        wo_title: app.globalData.wo_title
      });
    }, 300);
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () { },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() { },
});

搜索页面样式

.search {
    height: 124rpx;
    background-color: #F7F7F7;
    display: flex;
    justify-content: center;
    .search-container {
        margin-top: 30rpx;
        height: 64rpx;
        // border:1px solid red;
        margin-left:22rpx;
        margin-right:33rpx;
        width: 695rpx;
        display: flex;
        
        .search-left {
            display: flex;
            background-color: #FFFFFF;
            border-radius: 32rpx;
            .search-input  {
                // border:1px solid blue;
                height: 64rpx;
                line-height: 64rpx;
                font-size: 28rpx;
                width: 500rpx;
            }
            .search-image {
                width:34rpx;
                height: 34rpx;
                margin-left: 30rpx;
                margin-top:15rpx;
                margin-right: 15rpx;
            }
        }
       
        .search-btn {
            font-size: 32rpx;
            line-height: 64rpx;
            font-weight: bold;
            color:#313131;
            text-align: center;
            margin-left:30rpx;
        }
    }
}

.history {
    margin:0 auto;
    width: 710rpx;
    margin-top:30rpx;
    .history-title {
        display: flex;
        justify-content: space-between;
        .history-title-left {
            font-size: 28rpx;
            color:#313131;
        }
        .history-title-right {
            font-size: 28rpx;
            color:#AAAAAA;
        }
        margin-bottom: 15rpx;
    }
    .history-content {
        display: flex;
        flex-wrap: wrap;
        overflow: hidden;
        .history-item {
            margin-top:15rpx;
            margin-left:10rpx;
            margin-right:10rpx;
            padding-left:20rpx;
            padding-right: 20rpx;
            height: 48rpx;
            background-color: #eeeeee;
            border-radius: 24rpx;
            font-size: 24rpx;
            line-height: 48rpx;

        }
    }
}

.hot {
    margin:0 auto;
    width: 710rpx;
    margin-top:50rpx;
    .hot-title {
        display: flex;
        justify-content: space-between;
        font-size: 28rpx;
        color:#313131;
        margin-bottom: 15rpx;
    }
    .hot-content {
        display: flex;
        flex-wrap: wrap;
        overflow: hidden;
        .hot-item {
            margin-top:15rpx;
            margin-left:10rpx;
            margin-right:10rpx;
            padding-left:20rpx;
            padding-right: 20rpx;
            height: 48rpx;
            background-color: #eeeeee;
            border-radius: 24rpx;
            font-size: 24rpx;
            line-height: 48rpx;
        }
    }
}

搜索结果页面

<view class="search">
    <view class="search-container">
        <view class="search-left">
            <image class="search-image" src="/images/index/search.png" />
            <input class="search-input" placeholder="请输入你喜欢的商品" value="{{keywords}}" bindinput='watchSearch' />
        </view>
        <view class="search-btn" data-keywords="{{keywords}}" bindtap="go_to_search_result">搜索</view>
    </view>
</view>
<block wx:if="{{noData == 1}}">
    <view class="no-data">
        <view class="img">
            <image class="search-image" src="/images/search/nodata.png" />
        </view>
        <view class="msg">什么也没搜到哦</view>
    </view>
</block>
<block wx:else>
    <view class="data-list">
        <block wx:for="{{searchResult}}" wx:key="id">
            <view class="data-item">
                <view class="item-img">
                    <image src="{{item.title_img}}" />
                </view>
                <view class="item-content">
                    <view class="item-content-title">{{item.title}}</view>
                    <view class="item-content-property">
                        <view class="property-item">销量:{{item.sales_count}}</view>
                        <!-- <view class="property-item">库存:1970</view> -->
                    </view>
                    <view class="item-content-price">¥{{item.price}}</view>
                    <view class="item-content-add">
                        <image src="/images/common/buy_more.png" catch:tap="openTypeSelect" data-id="{{item.id}}" lazy-load="{{true}}"/>
                    </view>
                </view>
            </view>
        </block>
        <block wx:if="{{noMore==1}}">
        <view class="no-more">无更多结果</view>
        </block>
    </view>
</block>

<goodsType id="goodsType" />

搜索结果页逻辑

import { initInPage } from "../../../common/requestData";
import Storage from "../../../common/auth/Storage";
import tips from "../../../common/tips";


const app = getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    index_data: [],
    keywords: ''
  },

  openTypeSelect({
    currentTarget: {
      dataset: { id }
    }
  }) {
    this.selectComponent("#goodsType").openTypeSelect(id);
  },

  // 监听输入
  watchSearch: function (event) {
    console.log(event.detail.value);
    let keywords = event.detail.value;
    // 设置值
    this.setData({
      "keywords": keywords
    });
  },
  go_to_search_result({
    currentTarget: {
      dataset: { keywords }
    }
  }) {
    console.log(keywords);
    if (keywords == '') {
      return tips.showMsg("请输入要搜索的内容");
    }

    const uid = app.globalData.uid || Storage.get().uid;
    console.log(uid);
    // 初始化
    initInPage(
      this,
      "searchData",
      { 'uid': uid, 'keywords': keywords, page: 1, page_size: 5 },
      { inDataName: "inData", outDataName: "searchResult" }
    );
  },


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 能获取到参数
    console.log(options.keywords);
    // 设置值
    this.setData({
      "keywords": options.keywords
    });
  },

  /**
   * 展示
   */
  onShow: function (options) {
    // 获取不到参数
    let keywords = this.data.keywords;
    const uid = app.globalData.uid || Storage.get().uid;
    console.log(uid);
    // 初始化
    initInPage(
      this,
      "searchData",
      { 'uid': uid, 'keywords': keywords, page: 1, page_size: 5 },
      { inDataName: "inData", outDataName: "searchResult" }
    );
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () { },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() { },
  /**
  * 页面上拉触底事件的处理函数
  */
  onReachBottom: function () {
    return initInPage(this, "searchData", this.inData, { inDataName: "inData", outDataName: "searchResult" });
  },

});

搜索结果页样式

.search {
    height: 124rpx;
    background-color: #F7F7F7;
    display: flex;
    justify-content: center;
    .search-container {
        margin-top: 30rpx;
        height: 64rpx;
        // border:1px solid red;
        margin-left:22rpx;
        margin-right:33rpx;
        width: 695rpx;
        display: flex;
        
        .search-left {
            display: flex;
            background-color: #FFFFFF;
            border-radius: 32rpx;
            .search-input  {
                // border:1px solid blue;
                height: 64rpx;
                line-height: 64rpx;
                font-size: 28rpx;
                width: 500rpx;
            }
            .search-image {
                width:34rpx;
                height: 34rpx;
                margin-left: 30rpx;
                margin-top:15rpx;
                margin-right: 15rpx;
            }
        }
       
        .search-btn {
            font-size: 32rpx;
            line-height: 64rpx;
            font-weight: bold;
            color:#313131;
            text-align: center;
            margin-left:30rpx;
        }
    }
}

.data-list {
    margin-top:16rpx;
    overflow: hidden;
    .data-item {
        height: 240rpx;
        border-bottom: 1rpx solid #E2E2E2;
        padding:30rpx 20rpx;
        display: flex;
        .item-img {
            width: 180rpx;
            height: 180rpx;
            // border: 1rpx solid red;
            image {
                width: 180rpx;
                height: 180rpx;
            }
        }
        .item-content {
            margin-left:20rpx;
            width: 510rpx;
            height: 180rpx;
            // border:1rpx solid blue;
            position: relative;
            .item-content-title {
                font-size:26rpx;
                color:#313131;
            }
            .item-content-property {
                margin-top:20rpx;
                font-size: 24rpx;
                height:24rpx; /* 防止上下空隙 */
                line-height:24rpx;
                color:#AAAAAA;
                display: flex;
                .property-item:nth-child(n+2) {
                    margin-left:20rpx;
                }
            }
            .item-content-price {
                margin-top:46rpx;
                font-size:32rpx;
                font-weight: bold;
                color:#F6001F;
                height:32rpx;
                line-height:32rpx;
            }
            .item-content-add {
                position: absolute;
                right: 0rpx;
                bottom: 0rpx;
                line-height: 46rpx;
                font-size: 46rpx;
                height: 46rpx;
                color: #F6001F;
                image {
                    width: 46rpx;
                    height: 46rpx;
                }
            }
        }
    }

    .no-more {
        text-align: center;
        color:#E2E2E2;
        font-size: 32rpx;
        font-weight: bold;
        margin-top:30rpx;
    }
}

.no-data {
    // display: none; /* 暂时先隐藏 */
    margin:0 auto;
    margin-top:163rpx;
    height: 420rpx;
    // border:1px solid red;
    .img {
        width: 350rpx;
        height: 313rpx;
        // border:1px solid blue;
        margin:0 auto;
        image {
            width: 350rpx;
            height: 313rpx;
        }
    }
    .msg {
        text-align: center;
        font-size: 32rpx;
        color:#BFBFBF;
        margin-top:69rpx;
    }
}

小程序实现搜索效果

上一篇:《Arduino实战》——1.6 Arduino程序的结构


下一篇:《DBA修炼之道:数据库管理员的第一本书》——2.3节升级DBMS的主版本和次版本