小程序自定义API给筛选栏赋值
大家好,这篇文章主要分三部分讲解如果自定义一个筛选插件,并且封装api获取数据,并在页面调用这个插件对其赋值
先上效果图:
封装筛选插件
在我们的小程序开发中,主页经常会有很多功能,如果大家把这些功能写在一个页面,势必会造成页面代码繁多,后期维护起来也头疼,所以把功能封装成组件是大家要养成的良好习惯
js
先上代码
//Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
dropDownMenuTitle: {
type: Array,
value: ['时间', '地点', '类型','高级筛选'],
},
dropDownMenuFirstData: {
type:Array,
value:[
]
},
dropDownMenuSecondData: {
type: Array,
value: ['时间', '地点', '类型','高级筛选']
},
dropDownMenuThirdData: {
type: Array,
value:[
{"title" :"嘟嘟喵"},
{"title" :"小兔子"}
]
},
dropDownMenuFourthData: {
type: Array,
value: ['时间', '地点', '类型','高级筛选']
},
},
data: {
// 这里是一些组件内部数据
hyopen: false,
sqopen: false,
pxopen: false,
sortopen: false,
shownavindex: '',
dropDownMenuDataFirstRight: { },
select1: '',
select2: '',
selectedQt: 0,
selectedSq: 0,
selectedSort: 1,
},
methods: {
// 这里是自定义方法
listqy: function (e) {
if (this.data.hyopen) {
this.setData({
hyopen: false,
sqopen: false,
pxopen: false,
sortopen: false,
shownavindex: 0
})
} else {
this.setData({
hyopen: true,
pxopen: false,
sqopen: false,
sortopen: false,
shownavindex: e.currentTarget.dataset.nav
})
}
},
list: function (e) {
if (this.data.sqopen) {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: false,
shownavindex: 0
})
} else {
this.setData({
sqopen: true,
pxopen: false,
hyopen: false,
sortopen: false,
shownavindex: e.currentTarget.dataset.nav
})
}
},
listpx: function (e) {
if (this.data.pxopen) {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: false,
shownavindex: 0
})
} else {
this.setData({
sqopen: false,
pxopen: true,
sortopen: false,
hyopen: false,
shownavindex: e.currentTarget.dataset.nav
})
}
console.log(e.target)
},
listsort: function (e) {
if (this.data.sortopen) {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: false,
shownavindex: 0
})
} else {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: true,
shownavindex: e.currentTarget.dataset.nav
})
}
},
selectleft: function (e) {
var model = e.target.dataset.model.childModel;
var selectedId = e.target.dataset.model.id
var selectedTitle = e.target.dataset.model.title;
this.setData({
dropDownMenuDataFirstRight: model==null?"":model,
select1: selectedId,
select2: '',
})
if (model == null || model.length == 0) {
this.closeHyFilter();
this.triggerEvent("selectedItem", { index: this.data.shownavindex, selectedId: selectedId, selectedTitle: selectedTitle })
}
},
selectcenter: function (e) {
var selectedId = e.target.dataset.model.id
var selectedTitle = e.target.dataset.model.title;
this.closeHyFilter();
this.setData({
select2: selectedId
})
this.triggerEvent("selectedItem", { index: this.data.shownavindex, selectedId: selectedId, selectedTitle: selectedTitle })
},
selectsqitem: function (e) {
var selectedId = e.target.dataset.model.id
var selectedTitle = e.target.dataset.model.title;
this.closeHyFilter();
this.setData({
selectedSq: selectedId
})
this.triggerEvent("selectedItem", { index: this.data.shownavindex, selectedId: selectedId, selectedTitle: selectedTitle })
},
selecsortlitem: function (e) {
var selectedId = e.target.dataset.model.id
var selectedTitle = e.target.dataset.model.title;
this.closeHyFilter();
this.setData({
selectedSort: selectedId
})
this.triggerEvent("selectedItem", { index: this.data.shownavindex, selectedId: selectedId, selectedTitle: selectedTitle })
},
selecqtlitem: function (e) {
var selectedId = e.target.dataset.model.id
var selectedTitle = e.target.dataset.model.title;
this.closeHyFilter();
this.setData({
selectedQt: selectedId
})
this.triggerEvent("selectedItem", { index: this.data.shownavindex, selectedId: selectedId, selectedTitle: selectedTitle })
},
/**关闭筛选 */
closeHyFilter: function () {
if (this.data.hyopen) {
this.setData({
hyopen: false,
sqopen: false,
pxopen: false,
sortopen: false,
})
} else if (this.data.sqopen) {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: false,
})
}
else if (this.data.pxopen) {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: false,
})
}
else if (this.data.sortopen) {
this.setData({
sqopen: false,
pxopen: false,
hyopen: false,
sortopen: false,
})
}
},
},
//组件生命周期函数,在组件实例进入页面节点树时执行
attached: function () {
// 可以在这里发起网络请求获取插件的数据
},
})
组件有两个重要属性properties和data
他们两者有什么区别呢?
properties是外部可以访问到的,比如我们这个筛选插件的一些初始值可以放在properties里,当我们调用的时候可以动态给其赋值
data是组件的一些内部数据,这些数据在组件内进行赋值或运算,并不需要外部来访问
json
{
"component": true,
"usingComponents": {}
}
自定义组件的json里面通常有着两个属性
component是指明这是一个组件,外部可以使用它
usingComponents顾名思义是这个组件里面使用的其他组件,我们如果在这个组件里面需要使用其他组件就要引用进来
例:我在index页面引用我自定义的筛选组件
{
"usingComponents": {
"filter": "../../components/filter/filter"
}
}
wxml
二话不说直接上代码,大家复制即用
<view class="nav">
<view class="nav-son {{hyopen? 'active' : ''}}" bindtap="listqy" data-nav="1">
<view class="content">{{dropDownMenuTitle[0]}}</view>
<view class="icon"></view>
</view>
<view class="nav-son borders {{sqopen? 'active' : ''}}" bindtap="list" data-nav="2">
<view class="content">{{dropDownMenuTitle[1]}}</view>
<view class="icon"></view>
</view>
<view class="nav-son borders-right {{pxopen? 'active' : ''}}" bindtap="listpx" data-nav="3">
<view class="content">{{dropDownMenuTitle[2]}}</view>
<view class="icon"></view>
</view>
<view class="nav-son {{sortopen ? 'active' : ''}}" bindtap="listsort" data-nav="4">
<view class="content">{{dropDownMenuTitle[3]}}</view>
<view class="icon"></view>
</view>
</view>
<view class="quyu {{hyopen ? 'show' : 'disappear'}} ">
<view class="qy quyu-left">
<view class="{{select1 == item.id ? 'current' : ''}}" wx:for="{{dropDownMenuFirstData}}" bindtap="selectleft" data-model='{{item}}' wx:key="unique" >
{{item.title}}
</view>
</view>
<view class="qy quyu-center">
<view class="{{select2 == item.id ? 'current2' : ''}}" wx:for="{{dropDownMenuDataFirstRight}}" bindtap="selectcenter" data-model='{{item}}' wx:key="unique">
{{item.title}}
</view>
</view>
</view>
<view class="temp temp3 {{sqopen ? 'show' : 'disappear'}} ">
<view class='tempheight'>
<view>
<block wx:for="{{dropDownMenuSecondData}}" wx:key="unique">
<view class="sortitem {{selectedSq==item.id ? ' active ' : ' '}}" data-model='{{item}}' bindtap='selectsqitem'> {{item.title}}</view>
</block>
</view>
</view>
</view>
<view class="temp temp3 {{pxopen ? 'show' : 'disappear'}} ">
<view class='tempheight'>
<view>
<block wx:for="{{dropDownMenuThirdData}}" wx:key="unique">
<view class="sortitem {{selectedQt==item.id ? ' active ' : ' '}}" data-model='{{item}}' bindtap='selecqtlitem'> {{item.title}}</view>
</block>
</view>
</view>
</view>
<view class="temp temp3 {{sortopen ? 'show' : 'disappear'}} ">
<view class='tempheight'>
<view>
<block wx:for="{{dropDownMenuFourthData}}" wx:key="unique">
<view class="sortitem {{selectedSort==item.id ? ' active ' : ' '}}" data-model='{{item}}' bindtap='selecsortlitem'> {{item.title}}</view>
</block>
</view>
</view>
</view>
wxss
这里是样式文件,相当于css,也是直接复制
.page {
width: 100%;
height: 100%;
background: #fff;
overflow: hidden;
}
.position{position:absolute;}
.nav {
position: relative;
z-index: 99;
display: flex;
border-bottom: 1px solid #d1d3d4;
background: #fff;
}
.nav-son {
display: flex;
flex: 1;
text-align: center;
height: 20px;
align-items: center;
justify-content: center;
font-size: 14px;
margin: 20rpx 0;
}
.borders-right {
border-right: 1px solid #e6e6e6;
}
.borders-left {
border-left: 1px solid #e6e6e6;
}
.borders {
border-left: 1px solid #e6e6e6;
border-right: 1px solid #e6e6e6;
}
.content {
display: inline-block;
}
.icon {
display: inline-block;
border: 4px solid transparent;
border-top: 4px solid #9b9b9b;
margin-left: 5px;
}
.temp {
position: relative;
z-index: 4;
font-size: 14px;
}
.temp1 {
display: flex;
width: 100%;
height: 600rpx;
overflow-y: scroll;
background: #e0e0e0;
color: #666;
}
.slidedown {
transform: translateY(0%);
}
.quyu {
position: absolute;
display: none;
z-index: 5;
width: 100%;
height: 100%;
overflow-y: scroll;
background-color: rgba(0,0,0,0.5);
}
.quyu .qy {
overflow-y: scroll;
float: left;
width: 50%;
height: 600rpx;
line-height: 80rpx;
box-sizing: border-box;
font-size: 14px;
}
.qy view {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
padding-left: 15rpx;
}
.quyu-left {
background: #F7F7F7;
}
.quyu-center {
background: #fff;
}
.quyu-right {
background: #fff;
}
.quyu-right view {
border-bottom: 1px solid #c5c5c5;
}
.current {
background: #fff;
}
.current2 {
background: #fff;
color: #fa871e;
}
.fullbg {
position: fixed;
top: 0;
z-index: 1;
width: 100%;
height: 100%;
background: rgb(1, 1, 1);
transition: all 2s;
opacity: 0;
}
.fullopacity {
opacity: 0.2;
}
.nav-son.active .content {
color: #fa871e;
}
.nav-son.active .icon {
border-bottom: 4px solid #fa871e;
border-top: 0;
}
@keyframes slidown {
from {
transform: translateY(-100%);
}
to {
transform: translateY(0%);
}
}
.slidown {
display: block;
animation: slidown 0.2s ease-in both;
}
@keyframes slidup {
from {
transform: translateY(0%);
}
to {
transform: translateY(-100%);
}
}
.tempheight {
height: 600rpx;
overflow-y: scroll;
background: #fff;
}
.slidup {
display: block;
animation: slidup 0.2s ease-in both;
}
.disappear {
display: none;
}
.show {
display: block;
}
.slidowntop {
display: flex;
flex-direction: row;
padding: 20rpx 24rpx 10rpx 24rpx;
}
.emptyall {
margin-left: 475rpx;
color: #fa871e;
}
.emptyallright {
width: 80rpx;
text-align: center;
}
.endselect {
width: 350rpx;
text-align: left;
}
.return {
margin-left: 200rpx;
color: #fa871e;
}
.slidowncenter {
margin-top: 20rpx;
padding-top: 20rpx;
padding-left: 24rpx;
display: flex;
flex-direction: row;
align-content: space-between;
border-top: solid #d1d3d4 1rpx;
}
.slidownbottom {
margin-top: 10rpx;
padding: 10rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.sdbitem {
width: 119rpx;
text-align: center;
border: solid #ccc 1rpx;
margin: 12rpx;
justify-content: space-between;
padding: 12rpx 19rpx 12rpx 19rpx;
}
.emptyendcitys {
padding-left: 12rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.emptyendcitysitem {
width: 120rpx;
text-align: center;
border: solid #ccc 1rpx;
margin: 10rpx;
justify-content: space-between;
padding: 12rpx 18rpx 12rpx 18rpx;
}
.queding {
width: 100%;
height: 100rpx;
background-color: #fa871e;
color: #fff;
text-align: center;
}
.queding {
font-size: 18px;
line-height: 100rpx;
}
.temp2 {
width: 100%;
height: 600rpx;
overflow-y: scroll;
background: #fff;
color: #666;
}
.commanders{
padding: 10rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.sdbitem.active{
color: #fa871e;
background-color: #F1E6B8;
}
.sortitem {
border-bottom: solid #F7F7F7 1rpx;
justify-content: space-between;
padding: 20rpx 30rpx;
}
.sortitem.active{
color: #fa871e;
}
.temp3 {
width: 100%;
height: 100%;
position: absolute;
overflow-y: scroll;
background-color: rgba(0,0,0,0.5);
}
封装自定义api
所有api接口都可以做成一个通用功能,使用起来非常简单,
代码也很清爽,先看看结构图:
constant.js
这个js存放了api的一些基本配置,方便大家修改,大家可以根据实际情况酌情添加
exports.TOKEN ="USER_TOKEN"; //请求token
let ip = "XX.XXX.XXX.XX:8080";//服务器地址
exports.API_IP =ip;//请求的IP
exports.socketOpen =false;
let TEST = true; //是否测试状态
if(TEST){
exports.API_IP ="http://127.0.0.1:8080"
}else{
exports.API_IP ='http://${ip}';
}
exports.MTG_VERSION ="BATE1.0"//版本号
还有要说的一点,如果你想在本地测试你的接口,要在详情页面勾选不校验域名,否则你的ip是通不过的
api.js
这个js则存放了通用接口方法
大家先看看代码:
let CONSTANT = require('../api/constant')
// 从本地存储Storage中获取token值
function getToken() {
return wx.getStorageSync(CONSTANT.TOKEN);
}
// 创建请求头header的内容
function buildHeaders(isJson) {
let headers = {
"Content-Type": isJson ? 'application/json' : "application/x-www-form-urlencoded",
"version": CONSTANT.MINI_VERSION,
};
const token = getToken();
if (token) {
headers["token"] = token;
}
return headers;
}
// 发起 HTTPS 网络请求。
let baseURL = CONSTANT.API_IP;
function fetchApi(baseURL, url, params, method, isJson) {
// wx.getNetworkType判断网路类型。eg:wifi、2g、3g...;none值表示无网路
wx.getNetworkType({
success: function(res) {
// &&表示“并”"none" === e.networkType如果为真,才会去执行&&后面的内容,否则不执行
"none" === res.networkType && (wx.hideLoading(), wx.showModal({
title: "提示",
content: "当前无网络,请检查网络设置后重新加载",
showCancel: false
}));
}
});
return new Promise((resolve, reject) => {
wx.request({
url: `${baseURL}${url}`,
method: method,
header: buildHeaders(isJson),
data: params,
success: function(res) {
// 成功返回statusCode参数表示开发者服务器返回的 HTTP 状态码
// 统一拦截提示错误
// var o = res.statusCode;
// if (o !== 200 && [21020000, 41020001, 41020003, 21020002].indexOf(res.data.status) == -1) {
// wx.hideLoading();
// wx.showModal({
// title: "提示",
// content: res.data.msg
// });
// return;
// } 2020.3.9
// 41020001表示未登录那就要去拿code值
// 21020002表示登录超时
// 并重新请求获取token值
if (41020001 == res.data.status || 21020002 === res.data.status) {
wx.login({
success: res => {
wx.request({
url: baseURL + "/api/user/login",
method: "GET",
header: {
"token": "",
"version": CONSTANT.MINI_VERSION,
},
data: {
code: res.code,
},
success: function(res) {
wx.removeStorageSync(CONSTANT.TOKEN);
if (21020000 === res.data.status) {
wx.setStorageSync(CONSTANT.TOKEN, res.data.data);
console.log("already refresh token");
fetchApi(url, url, params, method);
}
}
});
}
});
}
// 41020003表示未授权了直接跳转到授权页(请求授权获取用户信息)
else if (41020003 == res.data.status) {
wx.redirectTo({
url: "/pages/accredit/accredit"
});
} else {
resolve(res.data);
}
},
fail: function(res) {
reject(res.data);
console.log("network fail.", res);
},
complete: function(res) {
resolve(res.data);
// console.log('complete', res);
}
});
});
};
function setlocation(baseURL, url, method) {
wx.request({
url: `${baseURL}${url}`,
method: method,
success: function (res) {
return res.data;
},
fail: function () {
doFail();
},
})
};
module.exports = {
// 定义各种api的方法
register(params) {
return fetchApi(baseURL, '/api/index', params, 'GET');
},
setlocation() {
return fetchApi(baseURL, '/filter', '11', 'GET','true');
},
}
在这里面的module.exports我们可以定义我们要封装的各种接口,和各种异常的统一处理机制,如果大家有兴趣了解ES6 Promise用法,可以移步
异步机制-Promise用法小结
我在这里就不多赘述了
页面引用组件并通过定义的api进行赋值
index.json
很简单,在json里引入我们封装的筛选组件
{
"usingComponents": {
"filter": "../../components/filter/filter"
}
}
index.wxml
这里非常简单,只需要一行代码即可搞定,是不是看起来清爽许多?
filter dropDownMenuFirstData ="{{filterFirst}}"></filter>
index.js
在js里面,我们就要对自定义组件进行赋值了,
dropDownMenuFirstData
组件的这个属性,就是点击按钮展示的父级和子集数据,其他属性也大同小异,我就只写一种来举例
var api = require("../../api/api")
Page({
data: {
filterFirst:[],
},
首先在index.js里面引入我们封装的api
然后在初始属性中初始化我们的参数
注意:传入的参数要和组件里面定义的类型一致
我在组件里面定义的是array,自然要初始化为数组
onLoad: function () {
var that = this;
api.setlocation().then(res => {
var firstValue =res.data;
console.log(res.data);
this.setData({
filterFirst:[firstValue]
})
})
},
在load里面对组件进行赋值,赋值根据实际情况决定,大家也可以不写在onload里面
**api.setlocation()**这是调用我们之前封装好的接口
**then(res => {**这里是接收Promise.resolve的返回值
**filterFirst:[firstValue]**这是对array对象进行赋值,
注意,这里要构造array对象,我先给大家展示一下数组结构
[
{"title" :"嘟嘟喵",
"childModel":[{"title" :"嘟嘟喵起床",
"id" :"ddmqc"},{"title" :"嘟嘟喵睡觉",
"id" :"ddmsj"},{"title" :"嘟嘟喵要抱",
"id" :"ddmyc"}],
"id" :"dudum"
},
{"title" :"小兔子",
"childModel":[{"title" :"小兔子起床",
"id" :"xtzqc"}],
"id" :"xtz"
},
{"title" :"爬爬龟",
"childModel":[{"title" :"爬爬龟起床",
"id" :"papgqc"}],
"id" :"papg"
}
]
这就是展示需要的数组结构,大家在后端构造好传入前端即可
到现在,我们的筛选已经实现了二级联动和从数据库取值的操作了!!
完结撒花