微信小程序搜索框组件自带模糊搜索复杂数组对象功能的自定义组件

1,345 阅读4分钟
  • # 搜索框组件应该是我们日常工作中最常用的组件之一了,通常查询模糊搜索的功能都是由后端来写接口前端调用的服务完成搜索的,但其实前端js也可以实现模糊搜索,这里实现了一个封装好了搜索功能的搜索框组件,开袋即食,非常方便~

动画.gif

1.因为接口的返回是异步的,通常我们组件渲染的时候数据还没有返回,所有我们在用户开始搜索的时候进行缓存数组操作

image.png

image.png

2.当我们输入搜索关键词的时候 handInput会触发,此时我们会此时我们将搜索关键词存入inputValue并且调用handelChange方法,有handelChange方法调用父组件的两个绑定了change以及searchList的方法,将搜索的关键词value以及模糊搜索过后list传递给父组件 image.png

3.我们传递的list的时候调用了changelist方法并传递给了changeList方法一个name值也就是我们要搜索对象键值对的key值

image.png

keyWord就是关键词,lists就是要搜索的数组,reg定义了一个正则表达式,然后我们会判断name是否为空,假如为空那么就默认数组对象的每一个值,只要有一项符合关键词那么就返回整个对象,如果传递了name值那么就只比对对象内对应的name的哪一项,其他项目不影响搜索结果 ``

image.png

image.png

当然组件销毁的时候还会清理数组缓存,节省缓存空间

image.png

微信小程序的自定义组件 wxml由一些view和input以及image嵌套搭建代码如下,代码已经在码云上传了,点击gitee.com/zengweifeng… 可以直接下载代码,里面有个完整的示例,整个包移到自己的component包内就可以用了,组件完全独立,下面是源码

<view class="searchbar" style="height: {{height}}rpx; width: {{width}}rpx;">
    <view class="content" style=" width: {{width}}rpx; background-color: {{backoundColor}};">
        <image src="search.png" class="search-icon" hidden="{{hideicon}}"></image>
        <input bindinput="handleInput" bindconfirm="handleConfirm" type="text" value="{{inputValue}}" placeholder="{{placeholder}}" placeholder-class="placeholder" class="input" confirm-type="search" style="line-height: {{height}}rpx;"></input>
        <image wx:if="{{inputValue}}" bindtap="handleDeleteClick" class="delete-icon" src="close.png"></image>
    </view>
</view>

wxss代码如下

.searchbar {
    width: 702rpx;
    height: 80rpx;
    box-sizing: border-box;
    display: flex;
  }
  .content {
    padding: 0 18rpx;
    background: #F7F9FD;
    border-radius: 20rpx;
    flex: 1;
    display: flex;
    align-items: center;
  }
  .search-icon {
    width: 42.72rpx;
    height: 42rpx;
    margin-bottom: -4rpx;
  }
  .input {
    flex: 1;
    margin: 0 20rpx;
  }
  .delete-icon {
    width: 48rpx;
    height: 48rpx;
  }
  .text-btn {
    margin-left: 24rpx;
    height: 88rpx;
    line-height: 88rpx;
    font-size: 32rpx;
    font-family: PingFangSC;
    font-weight: 400;
    color: rgba(21,96,220,1);
  }
  .placeholder {
      font-size: 24rpx;
      line-height: 80rpx;
      color: #B0B2BF;
  }
  

json代码如下

{
    "component": true,
    "usingComponents": {}
}

主要的js代码如下

Component({
    lifetimes: {
        detached() {
            wx.removeStorage({
                key: 'mySearchList',
                success(res) {
                    console.log(res, '已删除search数组缓存')
                }
            })
        }
    },
    properties: {
        placeholder: {
            type: String,
            value: '请输入',
        },
        hideicon: {
            type: Boolean,
            value: false
        },
        height: {
            type: String,
            value: '88'
        },
        width: {
            type: String,
            value: '702'
        },
        backoundColor: {
            type: String,
            value: '#f7f9fd'
        },
        // 查找的数组
        list: {
            type: Array,
            value: []
        },
        // 指定查找的关键词对应对象内的key值
        name: {
            type: String,
            value: ''
        },
        newlist: {
            type: Array,
            value: []
        }
    },
    data: {
        inputValue: '',
        chengeNumber: 0,
    },
    methods: {
        // 用户输入触发
        handleInput: function (e) {
            // console.log("logggggg",e)
            this.setData({
                inputValue: e.detail.value
            })
            this.handelChange()
        },
        // 用户输入触发返回值给父组件
        handelChange() {
            if (this.data.chengeNumber == 0) {
                wx.setStorageSync('mySearchList', this.properties.list)
                this.setData({
                    chengeNumber: 1
                })
            }
            this.triggerEvent('change', {
                value: this.data.inputValue
            })
            this.triggerEvent('searchList', {
                list: this.changeList(this.properties.name)
            })
        },
        // 模糊搜索功能 传递一个数组返回一个数组 会模糊搜索里面的每一项
        /**
         * @param {Object} lists 所有数据
         * @param {Object} keyWord 查询的关键词
         */
        changeList(name) {
            let keyWord = this.data.inputValue
            let lists = wx.getStorageSync('mySearchList')
            let reg = new RegExp(keyWord);
            // 传递了name那么就模糊指定搜索对应的键值对
            if (name != '') {
                if (keyWord.length > 0) {
                    let resArr = [];
                    lists.filter(item => {
                        for (let i in item) {
                            if (name == i && reg.test(item[i])) {
                                resArr.push(item);
                            }
                        }
                    })
                    return resArr;
                } else {
                    return lists
                }
            }
            // 这里没有传递name那么就对象的每一项都会搜索有一项匹配那么就返回这项
            else {
                if (keyWord.length > 0) {
                    let resArr = [];
                    lists.filter(item => {
                        for (let i in item) {
                            if (reg.test(item[i])) {
                                resArr.push(item);
                                return
                            }
                        }
                    })
                    return resArr;
                } else {
                    return lists
                }
            }
        },
        // 返回一个高亮显示关键词的富文本字段
        stringifyObj(obj, keyword) {
            if (!obj) return '';
            const str = JSON.stringify(obj); // 将object转为字符串    
            let richStr = '';
            const b = str.split(keyword); // 将字符串以关键词分开    
            b.map((item, index) => {
                if (index === b.length - 1) { // 最后一个无需再拼接        
                    richStr += item;
                } else {
                    richStr += item + `<span style="color:#4C74E7;">${keyword}</span>`;
                }
            });
            return richStr.slice(1, -1);
        },
        // 点击清空输入框icon
        handleDeleteClick: function () {
            this.setData({
                inputValue: ''
            })
            this.handelChange()
        },
        // 点击取消触发
        handleTextbtnClick() {
            // 触发父组件中的方法
            this.setData({
                inputValue: ''
            })
        },
        // 用户点击确定触发
        handleConfirm() {
            this.triggerEvent('handleSearch', {
                value: this.data.inputValue
            })
        }
    }
})

父组件中引入方法如下 wxml

<view class="box">
    <view class="title">
        <text>全部路线</text>
        <text bindtap="addRoute">新增</text>
    </view>
    <view class="searchBox">
        <search bind:change="change" bind:searchList="searchList" list="{{list}}" name="routingName" placeholder="请输入地址查找"></search>
    </view>
    <block wx:for="{{list}}">
        <view class="itemBox" data-code="{{item.routingCode}}" bindtap="gotoDetail">
            <view class="left">
                <view class="addres">{{item.routingName}}</view>
                <view class="message">
                    <text>吨位单价(元):{{item.tonPrice}}</text>
                    <text>方量单价(元):{{item.cubePrice}}</text>
                </view>
            </view>
            <view class="rightArrow"></view>
        </view>
    </block>
</view>

wxss

.box {
    width: 750rpx;
    background-color: #ffffff;
    margin-top: 20rpx;
    display: flex;
    flex-direction: column;
    padding: 24rpx 40rpx;
    box-sizing: border-box;
}

.title {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
}

.title text:nth-child(1) {
    color: #303030;
    font-size: 32rpx;
    font-weight: 600;
    font-family: PingFang SC-Medium;
}

.title text:nth-child(2) {
    color: #4C74E7;
    font-size: 24rpx;
    font-family: PingFang SC-Regular;
}

.searchBox {
    width: 100%;
    padding: auto 40rpx;
    margin-top: 20rpx;
}

.itemBox {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    width: 670rpx;
    height: 140rpx;
    background-color: #fff;
    align-items: center;
    border-radius: 20rpx;
}

.itemBox:hover {
    background-color: #f2f3f5;
}

.rightArrow {
    width: 0;
    height: 0;
    border: 12rpx solid;
    border-color: transparent transparent transparent #979797;
    position: relative;
    margin: auto 0;
}

.rightArrow::after {
    content: '';
    position: absolute;
    left: -14rpx;
    top: -12rpx;
    border: 12rpx solid;
    border-color: transparent transparent transparent #fff;
}

.left {
    display: flex;
    flex-direction: column;
    justify-content: start;
    height: 100%;
}

.addres {
    color: #3B3D3D;
    font-size: 28rpx;
    font-family: PingFang SC-Medium;
    font-weight: 600;
    margin-top: 28rpx;
}

.message {
    margin-top: 10rpx;
    color: #969699;
    font-size: 24rpx;
    font-family: PingFang SC-Regular;
    width: 478rpx;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

json

{
    "component": true,
    "usingComponents": {
        "search": "/components/search/search"
    }
}

js


// Packageshome/components/findRoute/findRoute.js
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        list: {
            type: Array,
            value: []
        }
    },

    /**
     * 组件的初始数据
     */
    data: {},

    /**
     * 组件的方法列表
     */
    methods: {
        gotoDetail(e) {
            
        },
        addRoute() {
            
        },
        searchList(e) {
            this.setData({
                list: e.detail.list
            })
        }
    }
})