基础版select选择器组件
目前题主小程序项目需要select选择器组件,没有现成组件,只能手写啦
效果图
功能点
- 获取物流列表,进行本地缓存
- 可模糊搜索
- 可下拉选择物流名称
实现
接下来,一步步来实现select 选择器
- 获取物流列表
/**
* 1. 获取快递公司列表进行缓存
*/
getLogisticsList() {
let that = this;
logisticsList().then(res => {
store.setItem('logisticsList', res.data); // 缓存物流信息
}).catch(err => {
app.Tips({
title: err.msg,
icon: 'none'
})
})
},
- 搭建组件骨架 (wxml)
<view class="select">
<input type="text" class="input" placeholder="请输入快递公司"/>
<scroll-view class="logistics_name" scroll-y="true">
<view class="logistics_name_item"></view>
</scroll-view>
</view>
- 给组件穿上漂亮的衣服 (wxss)
.select {
position: relative;
}
.select .input {
width: 340rpx;
font-size:28rpx;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(102,102,102,1);
line-height:48rpx;
text-align: left;
overflow: hidden;
border:1rpx solid #e7e7e7;
padding: 0 15rpx;
box-sizing: border-box;
}
.form_item .select .logistics_name {
position: absolute;
top: 0;
left: 0;
width: 340rpx;
max-height: 400rpx;
background:rgba(255,255,255,1);
box-shadow:3px 5px 23px 4px rgba(190,190,190,0.5);
z-index: 100;
padding: 15rpx 0;
}
.form_item .select .logistics_name .logistics_name_item{
font-size: 24rpx;
padding: 0 20rpx;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
height: 50rpx;
line-height: 50rpx;
box-sizing: border-box;
}
.form_item .select .logistics_name .logistics_name_item:active {
background: #F5F7FA;
color: #145af7;
}
- 好像看不到效果,那我们填充点数据
给input框绑定一个方法,用来搜索
<input type="text" class="input" placeholder="请输入快递单号" value="{{logistics_name}}" name="{{logistics_name}}" bindinput="getLogisticsName" />
给骨架填充肌肉
<scroll-view class="logistics_name" scroll-y="true">
<view class="logistics_name_item" wx:for="{{currentList}}" wx:key="index" data-id="{{item.id}}" data-name="{{item.name}}">
{{item.name}}
</view>
</scroll-view>
/**
* 获取快递公司
*/
getLogisticsName(e) {
let that = this;
// 有缓存
if (store.getItem('logisticsList')) {
that.setData({ current_value_status: true })
let currentList = that.search(store.getItem('logisticsList'), e.detail.value) // 模糊搜索方法
that.setData({
currentList: currentList
})
} else {
// 无缓存重新获取
that.getLogisticsList()
}
},
模糊搜索方法
/**
* 模糊搜索
* @ list 物流列表
* @ keywords 关键字
*/
search(list, keywords) {
var len = list.length;
var arr = [];
for (var i = 0; i < len; i++) {
//如果字符串中不包含目标字符会返回-1
if (list[i].name.indexOf(keywords) >= 0) {
arr.push(list[i]);
}
}
if (arr.length == 0) {
let obj = {};
obj.id = 0;
obj.name = "无匹配的快递公司";
arr.push(obj);
}
return arr;
}
- 可以模糊搜索啦,还不能选择物流公司,
<scroll-view class="logistics_name" wx:if="{{current_value_status}}" scroll-y="true">
<view class="logistics_name_item" wx:for="{{currentList}}" wx:key="index" data-id="{{item.id}}" data-name="{{item.name}}" bindtap="selectValue">
{{item.name}}
</view>
</scroll-view>
/**
* 选中当前快递公司
*/
selectValue(e) {
if (e.currentTarget.dataset.id == '0') return;
this.setData({
logistics_name: e.currentTarget.dataset.name, // 当前展示的物流名称
currentList: [], // 初始化当前物流列表
current_value_status: false // 隐藏物流当前物流列表状态
})
},
- 大功告成,但更需要三角样式
<view class="left" wx:if="{{current_value_status}}"></view>
.select .left {
position: absolute;
top: -20rpx;
left: 100rpx;
width: 0;
height: 0;
border-width: 10rpx;
border-style: solid;
z-index: 101;
border-color: transparent #fff transparent transparent;
transform: rotate(90deg); /*顺时针旋转90°*/
}
至此,基础版的select选择器组件已完成
- 把整个弹窗组件分享下,方便自己及大家学习
<!-- wxml -->
<!-- pages/authorize/authorize.wxml -->
<view class='Popup' hidden='{{iShidden}}'>
<view class='title'>邮回货品</view>
<view class="receive_info">
<view class="receive_item">
<view class="label">收件人</view>
<view class="value">{{receive_info.receive_name}}</view>
</view>
<view class="receive_item">
<view class="label">收件人手机</view>
<view class="value">{{receive_info.receive_phone}}</view>
</view>
<view class="receive_item">
<view class="label">邮寄地址</view>
<view class="value">{{receive_info.receive_address}}</view>
</view>
</view>
<view class="form">
<view class="form_item">
<view class="label">快递公司</view>
<view class="select">
<!-- <view class="current_name"></view> -->
<input class="input" type="text" placeholder="请输入快递公司" placeholder-class="placeholder" value="{{logistics_name}}" name="{{logistics_name}}" bindinput="getLogisticsName"/>
</view>
</view>
<view class="form_item">
<view class="label">快递单号</view>
<view class="select">
<input type="text" class="input" placeholder="请输入快递单号" placeholder-class="placeholder" value="{{logistics_num}}" name="{{logistics_num}}" bindinput="getLogisticsNum" />
<view class="left" wx:if="{{current_value_status}}"></view>
<scroll-view class="logistics_name" wx:if="{{current_value_status}}" scroll-y="true">
<view class="logistics_name_item" wx:for="{{currentList}}" wx:key="index" data-id="{{item.id}}" data-name="{{item.name}}" bindtap="selectValue">
{{item.name}}
</view>
</scroll-view>
</view>
</view>
</view>
<view class='bottom flex'>
<view class='item grant' bindtap="setUserInfo">提交</view>
</view>
</view>
<view class='mask' hidden='{{iShidden}}' catchtouchmove="true" bindtap='close'></view>
// json
{
"component":true
}
/* wxss */
/* pages/authorize/authorize.wxss */
@import "../../app.wxss";
.Popup {
position: relative;
width: 600rpx;
min-height: 530rpx;
background-color: #fff;
position: fixed;
top: 50%;
left: 50%;
margin-left: -300rpx;
transform: translateY(-50%);
z-index: 999;
background:rgba(255,255,255,1);
border-radius:24rpx;
/* overflow: hidden; */
font-family: PingFangSC-Regular,PingFang SC !important;
}
.Popup .title {
width: 100%;
height:82rpx;
line-height: 82rpx;
text-align: center;
border-bottom: 1rpx solid rgba(51,51,51,.5);
font-size: 32rpx;
font-weight: 600;
}
.Popup .receive_info {
padding: 0 38rpx;
}
.Popup .receive_info .receive_item {
display: flex;
margin-top: 12rpx;
}
.Popup .label {
width: 150rpx;
text-align: right;
font-size:28rpx;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(102,102,102,1);
line-height:48rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.Popup .value {
width: 340rpx;
font-size:28rpx;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(102,102,102,1);
line-height:48rpx;
text-align: left;
overflow: hidden;
margin-left: 44rpx;
white-space: nowrap;
text-overflow: ellipsis;
}
.Popup .form {
padding: 0 38rpx;
height: 120rpx;
margin-top: 20rpx;
}
.Popup .form .form_item {
display: flex;
margin-top: 20rpx;
}
.Popup .form .form_item .input {
width: 340rpx;
font-size:28rpx;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(102,102,102,1);
line-height:48rpx;
text-align: left;
overflow: hidden;
margin-left: 44rpx;
white-space: nowrap;
text-overflow: ellipsis;
border:1rpx solid #e7e7e7;
padding: 0 15rpx;
box-sizing: border-box;
}
.form_item .select {
position: relative;
}
.form_item .select .left {
position: absolute;
top: -20rpx;
left: 100rpx;
width: 0;
height: 0;
border-width: 10rpx;
border-style: solid;
z-index: 101;
border-color: transparent #fff transparent transparent;
transform: rotate(90deg); /*顺时针旋转90°*/
}
.form_item .select .logistics_name {
position: absolute;
top: 0;
left: 44rpx;
width: 340rpx;
max-height: 400rpx;
background:rgba(255,255,255,1);
box-shadow:3px 5px 23px 4px rgba(190,190,190,0.5);
z-index: 100;
/* overflow-y: auto; */
padding: 15rpx 0;
/* box-sizing: border-box; */
}
.form_item .select .placeholder {
color: #e7e7e7;
}
.form_item .select .logistics_name .logistics_name_item{
font-size: 24rpx;
padding: 0 20rpx;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
height: 50rpx;
line-height: 50rpx;
box-sizing: border-box;
}
.form_item .select .logistics_name .logistics_name_item:active {
background: #F5F7FA;
color: #145af7;
}
.Popup image {
width: 126rpx;
height: 126rpx;
display: block;
margin: 0 auto;
margin-top: 31rpx;
}
.Popup .tip {
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
/*font-size: 22rpx;*/
/*color: #555;*/
/*padding: 0 24rpx;*/
/*margin-top: 25rpx;*/
width:414rpx;
height: 96rpx;
text-align: center;
font-size:24rpx;
margin: 0 auto;
margin-top: 15rpx;
font-weight:500;
padding: 0 10rpx;
color:rgba(102,102,102,1);
}
.Popup .tip view{
text-align: center;
font-size:24rpx;
margin: 0 auto;
font-weight:500;
padding: 0 10rpx;
color:rgba(102,102,102,1);
}
.Popup .bottom {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 92rpx;
}
.Popup .bottom .item {
width: 100%;
height:92rpx;
background-color: #eee;
text-align: center;
line-height: 80rpx;
font-size: 28rpx;
color: #666;
line-height: 92rpx;
font-weight: 500;
}
.Popup .bottom .item.on {
width: 100%;
}
.flex {
display: flex;
}
.Popup .bottom .item.grant {
font-size: 28rpx;
color: #fff;
font-weight: bold;
background-color: #e93323;
border-radius: 0;
padding: 0;
font-weight: 600;
border-radius: 0 0 24rpx 24rpx;
}
.mask {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.65);
z-index: 310;
}
import store from '../../utils/store';
import { serviceOrderConfig, logisticsList, serviceOrderLogistics } from "../../api/order";
let app = getApp();
Component({
properties: {
iShidden: {
type: Boolean,
value: true,
},
serviceId: {
type: Number,
value: 0
}
},
data: {
receive_info: {}, // 收货人信息
logistics_num: '', // 快递单号
logistics_company: '', // 快递公司
// 当前所搜索的快递公司名称
currentList: [],
current_value_status: false, // 下拉框状态
},
attached() {
// this.get_logo_url();
this.getConfigNews();
// this.getLogisticsList();
},
methods: {
/**
* 关闭弹窗
*/
close() {
this.setData({
iShidden: true,
currentList: [],
});
},
/**
* 1. 获取快递公司列表进行缓存
*/
getLogisticsList() {
let that = this;
logisticsList().then(res => {
store.setItem('logisticsList', res.data);
}).catch(err => {
app.Tips({
title: err.msg,
icon: 'none'
})
})
},
/**
* 2. 获取收件人等配置信息
*/
getConfigNews() {
let that = this;
serviceOrderConfig({
config_name: "receive_info"
}).then(res => {
if (res.status_code == '200') {
that.setData({
receive_info: res.data.receive_info
})
} else {
app.Tips({
title: res.msg,
icon: 'none'
})
}
}).catch(err => {
app.Tips({
title: err,
icon: 'none'
})
})
},
/**
* 3. 获取快递单号
*/
getLogisticsNum(e) {
this.setData({
logistics_num: e.detail.value
})
},
/**
* 4. 获取快递公司
*/
getLogisticsName(e) {
let that = this;
if (store.getItem('logisticsList')) {
that.setData({ current_value_status: true })
let currentList = that.search(store.getItem('logisticsList'), e.detail.value)
that.setData({
currentList: currentList
})
} else {
// 无缓存重新获取
that.getLogisticsList()
}
},
/**
* 5. 选中当前快递公司
*/
selectValue(e) {
if (e.currentTarget.dataset.id == '0') return;
this.setData({
logistics_name: e.currentTarget.dataset.name,
logistics_company: e.currentTarget.dataset.name,
currentList: [],
current_value_status: false
})
},
/**
* 6. 提交快递售后信息
*/
setUserInfo(e) {
if (this.data.logistics_company == '') {
return app.Tips({
title: '请选择快递公司',
icon: 'none'
})
}
if (this.data.logistics_num == '') {
return app.Tips({
title: '请输入快递单号',
icon: 'none'
})
}
serviceOrderLogistics({
service_id: this.data.serviceId,
logistics_company: this.data.logistics_company,
logistics_num: this.data.logistics_num
}).then(res => {
if (res.status_code == '200') {
app.Tips({
title: '已提交邮回物流信息',
icon: 'success'
})
} else {
app.Tips({
title: res.msg,
icon: 'none'
})
}
}).catch(err => {
app.Tips({
title: err,
icon: 'icon'
})
})
},
/**
* 7. 模糊搜索
*/
search(list, keywords) {
var len = list.length;
var arr = [];
for (var i = 0; i < len; i++) {
//如果字符串中不包含目标字符会返回-1
if (list[i].name.indexOf(keywords) >= 0) {
arr.push(list[i]);
}
}
if (arr.length == 0) {
let obj = {};
obj.id = 0;
obj.name = "无匹配的快递公司";
arr.push(obj);
}
return arr;
}
},
})
父组件引用
// 父组件
{
"usingComponents": {
"mailback": "/components/mail_back_goods/mail_back_goods"
}
}
<mailback serviceId="{{service_id}}" iShidden="{{iShidden}}"></mailback>
// openPostSale 打开弹窗
/**
* 邮回品牌弹窗并传参
*/
openPostSale(e) {
this.setData({
iShidden: false, // 弹窗状态
service_id: e.currentTarget.dataset.id
})
},