最近要做一个公司管理用的小程序,其中审批工作流涉及人员选择,官方的picker不支持多选,无法满足场景使用需求。网上找了一遍,最后找到一篇(@华子_tm)兄弟写的简书文章实现了。贴了代码很详细。
遇到问题
1.复制代码试运行功能基本正常,但是开发工具有个报错,
意思是说cover-view不支持嵌套chekbox,查了官方文档的cover-view(可覆盖的原生组件包括 map、video、canvas、camera、live-player、live-pusher ,只支持嵌套 cover-view、cover-image,可在 cover-view 中使用 button),感觉局限性很大。然后就不想用cover-view了,全部改为view。
2.修改为view之后,就没报错了,但是有个页面中用到textarea,textarea的内容会显示文字至于最顶层, 跟选择人员组件的会重叠文字。网上很多人在说这个,textarea显示到顶层问题无法解决,然后还是乖乖的用回cover-view,把checkbox删掉换成cover-image,自己实现一个类似checkbox的功能就好了。(汗,一开始就这样不好嘛。走弯路了)
增加属性
1.增加了一个单选和多选的属性(mul)。单选的时候选中就会自动关闭选择组件
2.增加了一个禁用属性(pick_disable),等于1的时候不可点击。
3.增加一个选择类型属性(chooseType),暂时未用到
组件代码
picker-multiple.js的 代码片
.
Component({
properties:{
list: {
type: Array,
value :[],
observer() {
this.init();
}
},
rootText:{
type: String,
value : 'root'
},
children:{
type: String,
value: 'children'
},
selected:{
type: Array,
value: []
},
mul:{
type: Boolean,
value: true
},
dataIndex:{
type: Number,
value: 0
},
chooseType:{
type: Number,
value: 0
},
pick_disable:{
type: Number,
value: 0
},
},
data:{
showPicker: false,
firstShow: false,
outlist: [],
path: [],
current: {},
isRoot: true,
tselected: []
},
methods:{
// 展示picker
showPicker() {
console.log(this.properties.selected);
if(this.properties.pick_disable != 1){
this.init();
if (!this.data.firstShow) {
this.setData({
firstShow: true
})
}
this.setData({
showPicker: true,
})
}
},
// 隐藏picker
hidePicker() {
this.setData({
showPicker: false
})
},
// 取消按钮事件
cancal() {
this.hidePicker();
},
// 确定按钮事件
sure() {
this.hidePicker();
this.triggerEvent('click', {
selected: this.data.tselected,
dataIndex: this.properties.dataIndex,
chooseType:this.properties.chooseType
});
// this.triggerEvent('click', { value: user });
},
init(){
this.data.tselected = JSON.parse(JSON.stringify(this.properties.selected));
this.toRoot();
},
toRoot(){
// console.log(this.properties.list)
this.properties.list.forEach((item)=>{
item.itemShow='';
item.itemTrans='';
})
this.setData({
outlist: JSON.parse(JSON.stringify(this.properties.list)),
current:{},
isRoot: true,
path:[]
})
},
intoNextPath(e){
var caninto = e.currentTarget.dataset.caninto;
// console.log(e.currentTarget.dataset)
if(!caninto){
return
}
var item = e.currentTarget.dataset.item;
var index = e.currentTarget.dataset.index;
var path = this.data.path;
path.push(index);
item = this.initUser(item)
this.setData({
path: path,
current: item,
outlist: item[this.properties.children]==undefined?[]:item[this.properties.children],
isRoot: false
});
this.scrollTop();
},
backLastPath(e){
var path = this.data.path;
var floor = path.length;
if (floor <= 1){
this.toRoot()
}else{
path.pop();
console.log('back:' + path)
var list = JSON.parse(JSON.stringify(this.properties.list));
var item = {};
path.forEach((index) =>{
item = list[index];
list = item[this.properties.children]
})
var isRoot = false;
if (this.data.path.length <= 0){
isRoot = true;
}
// console.log(item)
item = this.initUser(item);
this.setData({
path: path,
current: item,
outlist: list,
isRoot: isRoot
})
}
this.scrollTop();
},
openContent(e){
var index = e.currentTarget.dataset.index;
var itemShow = this.data.outlist[index].itemShow
if (itemShow == null || itemShow == ''){
this.setData({
['outlist[' + index + '].itemShow']: 'item-show',
['outlist[' + index + '].itemTrans']:'item-trans90'
})
}else{
this.setData({
['outlist[' + index + '].itemShow']: '',
['outlist[' + index + '].itemTrans']: ''
})
}
},
checkboxChange(e) {
var id=e.currentTarget.dataset.id;
var checked=e.currentTarget.dataset.checked;
var newChecked=!checked;
let checkarr =[];
if(this.properties.mul){
checkarr=this.data.tselected;
}
const items = this.data.current;
var values =[];
if (newChecked && !this.properties.mul) {
values.push(id);
}else{
for (let i = 0, lenI = items.userlist.length; i < lenI; ++i) {
if(parseInt(items.userlist[i].id)!=id&&items.userlist[i].checked){
values.push(items.userlist[i].id);
}else{
if(newChecked){
values.push(id);
}
}
}
}
// const values = e.detail.value;
for (let i = 0, lenI = items.userlist.length; i < lenI; ++i) {
items.userlist[i].checked = false
if(checkarr.indexOf(items.userlist[i].id) > -1) {
checkarr.splice(checkarr.indexOf(items.userlist[i].id), 1);
}
for (let j = 0, lenJ = values.length; j < lenJ; ++j) {
if (parseInt(items.userlist[i].id) === parseInt(values[j])) {
items.userlist[i].checked = true;
if(!checkarr.includes(values[j])) {
checkarr.push(values[j]);
}
break
}
}
}
this.setData({
current: items,
tselected: checkarr
})
if(!this.properties.mul&&checkarr.length!=0){
this.sure();
}
},
initUser(dept){
var selected = this.data.tselected;
var userlist = dept.userlist;
userlist.forEach((user) => {
user.checked = false;
for(let j = 0, lenJ = selected.length; j < lenJ; ++j) {
if (parseInt(selected[j]) == parseInt(user.id)) {
user.checked = true;
}
}
})
dept.userlist = userlist
return dept
},
scrollTop(){
setTimeout(function () {
wx.pageScrollTo({
scrollTop: 0,
duration: 300
})
}.bind(this), 200)
}
}
})
picker-multiple.wxml的 代码片
.
<view bindtap='showPicker'>
<slot><text class='showtext'>选择人员</text></slot>
</view>
<cover-view class='{{ showPicker ? ".shade-container" : "hide-container" }}' wx:if='{{ firstShow }}'>
<cover-view class='left-shade' bindtap='hidePicker'></cover-view>
<cover-view class='right-choose'>
<cover-view class='picker-container'>
<cover-view class="title padder">
<cover-view wx:if="{{ isRoot }}">
<cover-view class="padder-l">{{ rootText }}</cover-view>
</cover-view>
<cover-view wx:else>
<cover-view class="icon">
<cover-image class="image" mode="heightFix" src="/static/images/icon/left-arrow.png" bindtap="backLastPath">
</cover-image>
</cover-view>
<cover-view class="padder-l">{{ current.name }}</cover-view>
</cover-view>
</cover-view>
<cover-view bindchange="checkboxChange">
<cover-view class="padder-l-md padder-r-md item-group">
<block wx:for="{{current.userlist}}" wx:key="id">
<cover-view wx:if="{{index != 0}}" class="line"></cover-view>
<cover-view data-checked="{{item.checked}}" bindtap="checkboxChange" data-id="{{item.id}}" class="item">
<cover-view class="checkbox-item">
<cover-view class="checkbox"></cover-view>
<cover-image wx:if="{{item.checked}}" class="checked" src="/static/images/icon/checked.png">
</cover-image>
<cover-view class="checkbox-label">{{item.name}}</cover-view>
</cover-view>
</cover-view>
</block>
</cover-view>
<cover-view wx:for="{{ outlist }}" wx:key="index" class="padder-l-md cell-group">
<cover-view wx:if="{{index != 0 || current.userlist.length>0}}" class="line"></cover-view>
<cover-view class="cell {{ (current == null || !current.userlist.length) && index == 0 ? 'cell-group':'' }}"
bindtap='intoNextPath' data-item="{{item}}"
data-caninto="{{ item.children.length > 0 || item.userlist.length > 0 }}" data-index="{{ index }}">
<cover-view class="left_text">{{ item.name }}</cover-view>
<cover-view class="icon cell_righticon" wx:if="{{ item.children.length > 0 || item.userlist.length > 0 }}">
<cover-image class="image" mode="heightFix" src="/static/images/icon/right-arrow.png"
bindtap="backLastPath">
</cover-image>
</cover-view>
</cover-view>
</cover-view>
</cover-view>
</cover-view>
<cover-view class="line"></cover-view>
<cover-view class='button-container'>
<cover-view class='sure' bindtap='sure'>确定</cover-view>
<cover-view class='cancal' bindtap='cancal'>取消</cover-view>
</cover-view>
</cover-view>
</cover-view>
picker-multiple.wxss的 代码片
.
.shade-container {
height: 100%;
width: 100%;
}
.showPicker {
width: 100%;
height: 80rpx;
line-height: 80rpx;
font-size: 30rpx;
background-color: paleturquoise;
text-align: center;
}
.showtext{
font-size: 32rpx;
color: rgb(32, 154, 224);
}
.shade-container {
position: fixed;
height: 100%;
width: 100%;
top: 0;
right: -200%;
display: flex;
justify-content: space-around;
transform: translateX(-200%);
transition: all 0.5s ease;
z-index: 9999;
}
.hide-container {
position: fixed;
height: 100%;
width: 100%;
top: 0;
right: -200%;
z-index: 9999;
display: flex;
justify-content: space-between;
transform: translateX(100%);
transition: all 0.5s ease-in;
}
.left-shade {
width: 30%;
background-color: rgba(0, 0, 0, 0.5);
height: 100%;
}
.right-choose {
width: 70%;
height: 100%;
background-color: #fff;
padding: 40rpx;
}
.picker-container {
height: calc(100% - 230rpx);
overflow-x: hidden;
overflow-y: scroll;
}
.picker-container::-webkit-scrollbar {
display: none;
}
.title{
font-size: 36rpx;
font-weight: bold;
border-bottom: 1px solid #dddee1
}
.tran-icon{
color: #5cadff;
}
.padder{
padding: 10px;
}
.padder-l{
height: 50rpx;
line-height: 50rpx;
padding-left: 10px;
display: inline-block;
}
.padder-l-sm{
padding-left: 5px;
}
.padder-l-md{
padding-left: 15rpx;
}
.padder-r-md{
padding-right: 15rpx;
}
.cell-group{
border: 0px !important;
position: relative;
}
.left_icon{
position: absolute;
top: 18rpx;
left: 0;
}
.left_text{
margin-left: 45rpx;
}
.b-t{
border-top: 1px solid #e9eaec!important;
}
.cell{
padding: 20rpx 10rpx;
}
.cell_righticon{
position: absolute;
right: 0rpx;
top: 15rpx;
}
.item-group .item:last-child{
border: 0px !important;
}
.item{
padding: 15px 0;
padding-left: 30rpx;
}
.item-show{
display: block;
}
.item-trans90{
transform:rotate(90deg);
-ms-transform:rotate(90deg); /* Internet Explorer */
-moz-transform:rotate(90deg); /* Firefox */
-webkit-transform:rotate(90deg); /* Safari 和 Chrome */
-o-transform:rotate(90deg); /* Opera */
}
.button-container {
width: 100%;
height: 100rpx;
padding-top: 30rpx;
display: flex;
justify-content: space-between;
font-size: 24rpx;
text-align: center;
/* border-top: 2rpx solid #eaeaea; */
}
.cancal {
width: 150rpx;
height: 80rpx;
line-height: 80rpx;
border: 2rpx solid #ddd;
border-radius: 8rpx;
}
.sure {
width: 150rpx;
height: 80rpx;
line-height: 80rpx;
border: 2rpx solid rgb(132, 235, 132);
border-radius: 8rpx;
}
.icon{
display: inline-block;
width: 50rpx;
height: 50rpx;
}
.image{
width: 50rpx;
height: 50rpx;
}
.line{
height: 1px;
width: 100%;
background-color: #eaeaea;
}
.checkbox-item{
height: 50rpx;
line-height: 50rpx;
}
.checkbox{
width: 50rpx;
height: 50rpx;
border: 1px solid #eaeaea;
position: absolute;
}
.checked{
width: 56rpx;
height: 56rpx;
}
.checkbox-label{
height: 50rpx;
line-height: 50rpx;
margin-left: 70rpx;
}
wx-cover-image{ position: absolute; width: 100%; height: 100%; }