学习项目页面完善

This commit is contained in:
FrancisHu 2024-08-06 13:28:37 +08:00
parent 7e30e148a9
commit e041599b7c
31 changed files with 5717 additions and 1247 deletions

View File

@ -0,0 +1,244 @@
<template>
<view class="filter-wrapper" :style="{ height: height + 'rpx', top: top,'border-top':border?'1rpx solid #f2f2f2':'none' }" @touchmove.stop.prevent="discard">
<view class="inner-wrapper">
<view class="mask" :class="showMask ? 'show' : 'hide'" @tap="tapMask"></view>
<view class="navs">
<view class="c-flex-align" :class="{ 'c-flex-center': index > 0, actNav: index === actNav }" v-for="(item, index) in navData" :key="index" @click="navClick(index)">
<view v-for="(child, childx) in item" :key="childx" v-if="child.select">{{ child.text }}</view>
<image src="https://i.loli.net/2020/07/15/QsHxlr1gbSImvWt.png" mode="" class="icon-triangle" v-if="index === actNav"></image>
<image src="https://i.loli.net/2020/07/15/xjVSvzWcH9NO7al.png" mode="" class="icon-triangle" v-else></image>
</view>
<view class="date-wrapper">
<picker mode="date" @change="handleDate">
<view class="date c-flex-align" :style="{ height: height + 'rpx' }" @click="dateClick">
<view>{{ selDate }}</view>
<image src="https://i.loli.net/2020/07/15/xjVSvzWcH9NO7al.png" mode="" class="icon-triangle"></image>
</view>
</picker>
</view>
</view>
<scroll-view scroll-y="true" class="popup" :class="popupShow ? 'popupShow' : ''">
<view class="item-opt c-flex-align" :class="item.select ? 'actOpt' : ''" v-for="(item, index) in navData[actNav]" :key="index" @click="handleOpt(index)">
{{ item.text }}
</view>
</scroll-view>
</view>
</view>
</template>
<script>
// import { getCurDateTime } from '@/libs/utils.js';
export default {
props: {
height: {
type: Number,
default: 108
},
top: {
type: String,
default: 'calc(var(--window-statsu-bar) + 44px)'
},
border: {
type: Boolean,
default: false
},
filterData: {
//
type: Array,
default: () => {
return [];
}
// default: () => {
// return [
// [{ text: '', value: '' }, { text: '1', value: 1 }, { text: '2', value: 2 }, { text: '3', value: 3 }],
// [{ text: '', value: '' }, { text: '1', value: 1 }, { text: '2', value: 2 }, { text: '3', value: 3 }]
// ];
// }
},
defaultIndex: {
//,
type: Array,
default: () => {
return [0];
}
}
},
data() {
return {
navData: [],
popupShow: false,
showMask: false,
actNav: null,
selDate: '选择日期',
selIndex: [] //
};
},
created() {
this.navData = this.filterData;
this.selIndex = this.defaultIndex;
this.keepStatus();
},
mounted() {
// this.selDate = getCurDateTime().formatDate;
},
methods: {
keepStatus() {
this.navData.forEach(itemnavData => {
itemnavData.map(child => {
child.select = false;
});
return itemnavData;
});
for (let i = 0; i < this.selIndex.length; i++) {
let selindex = this.selIndex[i];
this.navData[i][selindex].select = true;
}
},
navClick(index) {
if (index === this.actNav) {
this.tapMask();
return;
}
this.popupShow = true;
this.showMask = true;
this.actNav = index;
},
handleOpt(index) {
this.selIndex[this.actNav] = index;
this.keepStatus();
setTimeout(() => {
this.tapMask();
}, 100);
let data = [];
let res = this.navData.forEach(item => {
let sel = item.filter(child => child.select);
data.push(sel);
});
console.log(data);
this.$emit('onSelected', data);
},
dateClick() {
this.tapMask();
},
tapMask() {
this.showMask = false;
this.popupShow = false;
this.actNav = null;
},
handleDate(e) {
let d = e.detail.value;
this.selDate = d;
this.$emit('dateChange', d);
},
discard() {}
}
};
</script>
<style lang="scss" scoped>
page {
font-size: 28rpx;
}
.c-flex-align {
display: flex;
align-items: center;
}
.c-flex-center {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.filter-wrapper {
position: fixed;
left: 0;
width: 750rpx;
z-index: 999;
.inner-wrapper {
// position: relative;
.navs {
position: relative;
height: 110rpx;
padding: 0 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #fff;
border-bottom: 2rpx solid #f5f6f9;
color: #8b9aae;
z-index: 999;
box-sizing: border-box;
& > view {
flex: 1;
height: 100%;
flex-direction: row;
z-index: 999;
}
.date {
justify-content: flex-end;
}
.actNav {
color: #4d7df9;
font-weight: bold;
}
}
.mask {
z-index: 666;
position: fixed;
top: calc(var(--status-bar-height) + 44px);
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0);
transition: background-color 0.15s linear;
&.show {
background-color: rgba(0, 0, 0, 0.4);
}
&.hide {
display: none;
}
}
.popup {
position: relative;
max-height: 500rpx;
background-color: #fff;
border-bottom-left-radius: 20rpx;
border-bottom-right-radius: 20rpx;
overflow: scroll;
z-index: 999;
transition: all 1s linear;
opacity: 0;
display: none;
.item-opt {
height: 100rpx;
padding: 0 40rpx;
color: #8b9aae;
border-bottom: 2rpx solid #f5f6f9;
}
.actOpt {
color: #4d7df9;
font-weight: bold;
position: relative;
&::after {
content: '✓';
font-weight: bold;
font-size: 36rpx;
position: absolute;
right: 40rpx;
}
}
}
.popupShow {
display: block;
opacity: 1;
}
}
.icon-triangle {
width: 16rpx;
height: 16rpx;
margin-left: 10rpx;
}
}
</style>

View File

@ -4,20 +4,82 @@
<view
v-for="(item, index) in statusList"
:key="item.id"
:class="[ { active: statusCount === item.id } ]"
:class="[ { active: totalStatus.statusCount === item.id } ]"
@click="chooseStatus(item.id)"
>
{{ item.text }}
</view>
</view>
<uni-easyinput prefixIcon="search" v-model="searchIpt" placeholder="请输入项目名称" @iconClick="toggleSearch"></uni-easyinput>
<view class="drops">
<u-dropdown ref="uDrop">
<u-dropdown-item v-model="learnType" title="学习类型" :options="learnTypeRange"></u-dropdown-item>
<u-dropdown-item v-model="outDateStatus" title="逾期状态" :options="outDateStatusRange"></u-dropdown-item>
<u-dropdown-item v-model="qualStatus" title="合格状态" :options="qualStatusRange"></u-dropdown-item>
<u-dropdown-item v-model="signupStatus" title="报名状态" :options="signupStatusRange"></u-dropdown-item>
</u-dropdown>
<uni-easyinput
prefixIcon="search"
v-model="totalStatus.keyword"
placeholder="请输入项目名称"
@iconClick="toggleSearch"
></uni-easyinput>
<zb-dropdown-menu style="width: 100%">
<zb-dropdown-item
name="first"
:options="learnTypeRange"
v-model="totalStatus.learnType"
@change="statusChange"
></zb-dropdown-item>
<zb-dropdown-item
name="two"
:options="outDateStatusRange"
v-model="totalStatus.outDateStatus"
@change="statusChange"
></zb-dropdown-item>
<zb-dropdown-item
name="three"
:options="qualStatusRange"
v-model="totalStatus.qualStatus"
@change="statusChange"
></zb-dropdown-item>
<zb-dropdown-item
name="four"
:options="signupStatusRange"
v-model="totalStatus.signupStatus"
@change="statusChange"
></zb-dropdown-item>
</zb-dropdown-menu>
<view class="project-cont">
<view
v-for="(item, index) in projList"
:key="item.id"
class="single-proj"
>
<h4 class="img">
<image :src="item.img"></image>
</h4>
<view class="proj-detail">
<view class="detail-upper">
<h5 style="font-size: 16px">{{ item.title }}</h5>
<l-starRate v-model="item.star" :disabled="true"></l-starRate>
<view class="icons">
<uni-icons color="#c0c0c0" type="eye-filled"></uni-icons><span>3</span>
<uni-icons color="#c0c0c0" type="chat-filled" style="margin-left: 5rpx"></uni-icons><span>3</span>
<uni-icons color="#c0c0c0" type="hand-up-filled" style="margin-left: 5rpx"></uni-icons><span>3</span>
</view>
</view>
<view class="detail-lower">
<view class="avatar">
<image :src="item.avatar"></image>
</view>
<view class="progress">
<span>{{ item.user }}</span>
<view class="bar">
<liu-progressbar
:progress="item.percent"
color="#000"
:height="'10rpx'"
bgColor="#1989FA"
:textInside="false"
/>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
@ -26,43 +88,119 @@
export default {
data() {
return {
statusCount: 0,
statusList: [
{ text: '全部', id: 0 },
{ text: '已完成', id: 1 },
{ text: '未完成', id: 2 },
],
searchIpt: '',
//
learnType: 1,
outDateStatus: 1,
qualStatus: 1,
signupStatus: 1,
//
totalStatus: {
statusCount: 0,
keyword: '',
learnType: '',
outDateStatus: '',
qualStatus: '',
signupStatus: ''
},
//
learnTypeRange: [
{ label: '不学', value: 1 },
{ label: '要学', value: 2 },
{ text: '学习类型', value: '' },
{ text: '不学', value: 1 },
{ text: '要学', value: 2 },
],
outDateStatusRange: [
{ label: '临期', value: 1 },
{ label: '过期', value: 2 },
{ text: '逾期状态', value: '' },
{ text: '临期', value: 1 },
{ text: '过期', value: 2 },
],
qualStatusRange: [
{ label: '合格', value: 1 },
{ label: '不及格', value: 2 },
{ text: '合格状态', value: '' },
{ text: '合格', value: 1 },
{ text: '不及格', value: 2 },
],
signupStatusRange: [
{ label: '报了', value: 1 },
{ label: '没报', value: 2 },
{ text: '报名状态', value: '' },
{ text: '报了', value: 1 },
{ text: '没报', value: 2 },
],
//
projList: [
{
id: 1,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 5,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 71
},
{
id: 2,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 3,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 33
},
{
id: 3,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 2,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 94
},
{
id: 4,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 4,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 76
},
{
id: 5,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 1,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 63
},
{
id: 6,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 5,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 52
},
{
id: 7,
img: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '应急抢险',
star: 4,
avatar: '/static/avatar.jpg',
user: '管理员',
percent: 18
},
]
}
},
methods: {
chooseStatus(count) {
this.statusCount = count
this.totalStatus.statusCount = count
console.log(this.totalStatus)
},
toggleSearch() {
console.log(this.searchIpt)
console.log(this.totalStatus)
},
statusChange(item) {
console.log(this.totalStatus)
}
}
}
@ -76,7 +214,7 @@
height: 100vh;
background-color: #F8F8F8;
box-sizing: border-box;
padding: 0 20px;
padding: 0 10px;
.status-secs{
@ -112,6 +250,122 @@
}
.project-cont{
width: 100%;
height: 10rpx;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.single-proj{
width: 49%;
height: 30vh;
margin-bottom: 1vh;
border-radius: 10px;
overflow: hidden;
display: flex;
flex-direction: column;
background-color: #fff;
.img{
width: 100%;
height: 45%;
image{
width: 100%;
height: 100%;
}
}
.proj-detail{
flex: 1;
display: flex;
flex-direction: column;
.detail-upper{
width: 100%;
height: 65%;
border-bottom: 1px solid #DFDFDF;
box-sizing: border-box;
padding: 5px;
display: flex;
flex-direction: column;
justify-content: space-around;
.icons{
font-size: 12px;
color: #C0C0C0;
display: flex;
align-items: center;
span{
padding-left: 5rpx;
}
}
}
.detail-lower{
flex: 1;
box-sizing: border-box;
padding: 5px;
display: flex;
.avatar{
width: 20%;
height: 100%;
border-radius: 50%;
overflow: hidden;
image{
width: 100%;
height: 100%;
}
}
.progress{
flex: 1;
box-sizing: border-box;
padding-left: 5rpx;
font-size: 12px;
display: flex;
flex-direction: column;
justify-content: space-around;
.bar{
flex: 1;
}
}
}
}
}
}
}
</style>

View File

@ -21,6 +21,7 @@
<uni-forms
:modelValue="pwdForm"
ref="uPwdForm"
:rules="pwdRules"
>
<uni-forms-item name="username">
<uni-easyinput type="text" v-model="pwdForm.username" placeholder="请输入用户名" />
@ -46,6 +47,7 @@
<uni-forms
:modelValue="codeForm"
ref="uCodeForm"
:rules="codeRules"
>
<uni-forms-item name="phone">
<uni-easyinput placeholder="请输入手机号码" type="number" v-model="codeForm.phone"
@ -180,11 +182,11 @@
}
},
},
onReady() {
/*onReady() {
// onReady
this.$refs.uPwdForm.setRules(this.pwdRules)
this.$refs.uCodeForm.setRules(this.codeRules)
},
},*/
}
</script>

BIN
static/avatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

View File

@ -0,0 +1,7 @@
## 1.0.12022-08-19
修复一些bug
## 1.0.02021-07-21
* 发布uni_modules版本请下载uni_modules版本非uni_modules版本停止更新
* 修复 子组件修改父组件数据问题,注意,数据非双向绑定
* 优化 点击遮罩层等未选择菜单关闭菜单情况不触发confirm回调
* 新增 三列形式的菜单 详细请下载示例查看data.js

View File

@ -0,0 +1,896 @@
<template>
<view class="HMfilterDropdown" :class="{'setDropdownBottom':maskVisibility}" :style="{'top':menuTop+'rpx'}" @touchmove.stop.prevent="discard" @tap.stop="discard">
<!-- 顶部菜单 -->
<view class="nav">
<block v-for="(item,index) in menu" :key="index">
<view class="first-menu" :class="{'on':showPage==index}" @tap="togglePage(index)">
<text class="name">{{item.name}}</text>
<text class="iconfont triangle" :style="'transform:rotate('+triangleDeg[index]+'deg);'"></text>
</view>
</block>
</view>
<!-- 遮罩层 -->
<view class="mask" :class="{'show':isShowMask,'hide':maskVisibility!=true}" @tap="hideMenu(false)"></view>
<block v-for="(page,page_index) in subData" :key="page_index">
<view class="sub-menu-class" :class="{'show':showPage==page_index,'hide':pageState[page_index]!=true}">
<!-- 多级菜单 -->
<block v-if="(page.type=='hierarchy'||page.type=='hierarchy-column')&& page.submenu.length>0">
<!-- 第一级菜单 -->
<scroll-view class="sub-menu-list" :class="{'first':activeMenuArr[page_index].length>1,'alone':activeMenuArr[page_index].length<=1}"
:scroll-y="true" :scroll-into-view="'first_id'+firstScrollInto">
<block v-for="(sub,index) in page.submenu" :key="sub.value">
<view class="sub-menu" :id="'first_id'+index" :class="{'on':activeMenuArr[page_index][0]==index}" @tap="selectHierarchyMenu(page_index,index,null,null)">
<view class="menu-name">
<text>{{sub.name}}</text>
<text class="iconfont selected"></text>
</view>
</view>
</block>
</scroll-view>
<block v-if="page.type=='hierarchy'">
<block v-for="(sub,index) in page.submenu" :key="sub.value">
<!-- 第二级菜单 -->
<scroll-view class="sub-menu-list not-first" :scroll-y="true" v-if="activeMenuArr[page_index][0]==index&&sub.submenu.length>0"
:scroll-into-view="'second_id'+secondScrollInto">
<block v-for="(sub_second,second_index) in sub.submenu" :key="sub_second.value">
<view class="sub-menu" :id="'second_id'+second_index" :class="{'on':activeMenuArr[page_index][1]==second_index}">
<view class="menu-name" @tap="selectHierarchyMenu(page_index,activeMenuArr[page_index][0],second_index,null)">
<text>{{sub_second.name}}</text>
<text class="iconfont selected"></text>
</view>
<!-- 第三级菜单 -->
<view class="more-sub-menu" v-if="sub_second.submenu&&sub.submenu.length>0&&sub_second.submenu.length>0">
<block v-for="(sub2,sub2_index) in sub_second.submenu" :key="sub2.value">
<text v-if="sub_second.showAllSub || (sub2_index<8)" :class="{'on':activeMenuArr[page_index][1]==second_index&&activeMenuArr[page_index][2]==sub2_index}"
@tap.stop="selectHierarchyMenu(page_index,activeMenuArr[page_index][0],second_index,sub2_index)">{{sub2.name}}</text>
<text v-if="sub_second.showAllSub!=true && sub2_index==8 && sub_second.submenu.length>9" @tap.stop="showMoreSub(second_index)">更多<text
class="iconfont triangle"></text></text>
</block>
</view>
</view>
</block>
</scroll-view>
</block>
</block>
<!-- 二三级菜单都是行形态 -->
<block v-else-if="page.type=='hierarchy-column'">
<!-- 第二级菜单 -->
<block v-for="(sub,index) in page.submenu" :key="index">
<scroll-view class="sub-menu-list not-first" :scroll-y="true" v-if="activeMenuArr[page_index][0]==index&&sub.submenu.length>0"
:scroll-into-view="'second_id'+secondScrollInto">
<block v-for="(sub_second,second_index) in sub.submenu" :key="second_index">
<view class="sub-menu" :id="'second_id'+second_index" :class="{'on':activeMenuArr[page_index][1]==second_index}">
<view class="menu-name" @tap="selectHierarchyMenu(page_index,activeMenuArr[page_index][0],second_index,null)">
<text>{{sub_second.name}}</text>
</view>
</view>
</block>
</scroll-view>
</block>
<!-- 第三级菜单 -->
<block v-for="(sub,index) in page.submenu">
<block v-for="(sub_second,second_index) in sub.submenu">
<scroll-view class="sub-menu-list not-first third" :scroll-y="true" v-if="activeMenuArr[page_index][0]==index&&activeMenuArr[page_index][1]==second_index&&sub_second.submenu.length>0"
:scroll-into-view="'third_id'+thirdScrollInto"
>
<block v-for="(sub2,sub2_index) in sub_second.submenu" :key="sub2_index">
<view class="sub-menu" :id="'third_id'+sub2_index" :class="{'on':activeMenuArr[page_index][2]==sub2_index}">
<view class="menu-name" @tap="selectHierarchyMenu(page_index,activeMenuArr[page_index][0],second_index,sub2_index)">
<text>{{sub2.name}}</text>
</view>
</view>
</block>
</scroll-view>
</block>
</block>
</block>
</block>
<!-- 多选筛选 -->
<block v-if="page.type=='filter'">
<view class="filter">
<scroll-view class="menu-box" :scroll-y="true">
<view class="box" v-for="(box,box_index) in page.submenu" :key="box_index">
<view class="title">{{box.name}}</view>
<view class="labels">
<view v-for="(label,label_index) in box.submenu" :key="label_index" @tap="selectFilterLabel(page_index,box_index,label_index)"
:class="{'on':label.selected}">{{label.name}}</view>
</view>
</view>
</scroll-view>
<view class="btn-box">
<view class="reset" @tap="resetFilterData(page_index)">重置</view>
<view class="submit" @tap="setFilterData(page_index)">确定</view>
</view>
</view>
</block>
<!-- 单选筛选 -->
<block v-if="page.type=='radio'">
<view class="filter">
<scroll-view class="menu-box" :scroll-y="true">
<view class="box" v-for="(box,box_index) in page.submenu" :key="box_index">
<view class="title">{{box.name}}</view>
<view class="labels">
<view v-for="(label,label_index) in box.submenu" :key="label_index" @tap="selectRadioLabel(page_index,box_index,label_index)"
:class="{'on':label.selected}">{{label.name}}</view>
</view>
</view>
</scroll-view>
<view class="btn-box">
<view class="reset" @tap="resetFilterData(page_index)">重置</view>
<view class="submit" @tap="setFilterData(page_index)">确定</view>
</view>
</view>
</block>
</view>
</block>
</view>
</template>
<script>
export default {
name: 'HM-filterDropdown',
data() {
return {
menuData:[],
subData: [], //
menu: [], //
showPage: -1, ///
pageState: [], //
activeMenuArr: [], //UI
shadowActiveMenuArr: [], //
defaultActive:[],
triangleDeg: [], //
isShowMask: false, ///
maskVisibility: false, ///
//
firstScrollInto: 0,
secondScrollInto: 0,
thirdScrollInto:0,
componentTop:0 ,//top
isReadNewSelect:false
}
},
props: {
menuTop:{
value: Number,
default: false
},
filterData: {
value: Array,
default: []
},
defaultSelected:{
value: Array,
default: []
},
updateMenuName:{
value: Boolean,
default: true
},
dataFormat:{
value: String,
default: 'Array'
}
},
watch: {
filterData: {
handler(newVal) {
console.log('watch filterData');
this.menuData = JSON.parse(JSON.stringify(newVal));
this.initMenu(); //filterData
},
immediate: true,
deep: true
},
defaultSelected(newVal) {
if(newVal.length==0){
return;
}
this.defaultActive = JSON.parse(JSON.stringify(newVal));
this.activeMenuArr = JSON.parse(JSON.stringify(newVal));
this.shadowActiveMenuArr = JSON.parse(JSON.stringify(newVal));
if(this.updateMenuName){
this.setMenuName();
}
}
},
methods: {
initMenu() {
let tmpMenuActiveArr=[];
let tmpMenu=[];
for (let i = 0; i < this.menuData.length; i++) {
let tmpitem = this.menuData[i];
tmpMenu.push({
//namemenu.name,filter""menu.name
name: tmpitem.name || (tmpitem.type == "filter" ? "筛选" : tmpitem.submenu[0].name),
type: tmpitem.type
});
//-ui
tmpMenuActiveArr.push(this.processActive(tmpitem));
//
this.triangleDeg.push(0);
//
this.pageState.push(false);
//
tmpitem = this.processSubMenu(tmpitem);
this.menuData[i] = tmpitem;
}
this.menu = tmpMenu;
//
tmpMenuActiveArr = this.defaultActive.length>0?this.defaultActive:this.activeMenuArr.length>0?this.activeMenuArr:tmpMenuActiveArr;
this.defaultActive = [];
this.activeMenuArr.splice(0,this.activeMenuArr.length,...JSON.parse(JSON.stringify(tmpMenuActiveArr)));
// this.activeMenuArr = JSON.parse(JSON.stringify(tmpMenuActiveArr));
this.shadowActiveMenuArr = JSON.parse(JSON.stringify(tmpMenuActiveArr));
//
this.subData = this.menuData;
//
if(this.updateMenuName){
this.setMenuName();
}
},
setMenuName(){
for(var i=0;i<this.activeMenuArr.length;i++){
let row = this.activeMenuArr[i];
if(this.subData[i].type=='hierarchy' || this.subData[i].type=='hierarchy-column'){
if (typeof(row[0]) == 'number'){
let tmpsub = this.subData[i].submenu[row[0]];
if(row.length>1){
tmpsub = tmpsub.submenu[row[1]]||tmpsub;
if(row.length>2){
tmpsub = tmpsub.submenu[row[2]]||tmpsub;
}
}
this.menu[i].name = tmpsub.name;
}else{
this.menu[i].name = this.subData[i].name;
}
}
}
},
//
showMoreSub(index) {
this.subData[this.showPage].submenu[this.activeMenuArr[this.showPage][0]].submenu[index].showAllSub = true;
this.$forceUpdate();
},
//
selectHierarchyMenu(page_index, level1_index, level2_index, level3_index) {
console.log('selectHierarchyMenu');
//
if (level2_index == null && level3_index == null && this.shadowActiveMenuArr[page_index].length>0 && this.shadowActiveMenuArr[page_index][0] == level1_index) {
this.activeMenuArr.splice(page_index, 1, JSON.parse(JSON.stringify(this.shadowActiveMenuArr[page_index])));
}
/////////
let tmpArr = new Array(this.activeMenuArr[page_index].length).fill(null);
this.activeMenuArr[page_index].splice(0, this.activeMenuArr[page_index].length, ...tmpArr);
////////
this.activeMenuArr[page_index].splice(0, 1, level1_index);
let tmpMemu = this.subData[page_index].submenu[level1_index];
if(tmpMemu.submenu.length==0){
this.selectedMemu(page_index, level1_index, level2_index, level3_index);
}else if(level2_index!=null){
this.activeMenuArr[page_index].splice(1, 1, level2_index);
tmpMemu = tmpMemu.submenu[level2_index];
if(tmpMemu.submenu.length==0 || (this.menu[page_index].type == 'hierarchy' && level3_index==null)){
this.selectedMemu(page_index, level1_index, level2_index, level3_index);
}else if(level3_index!=null){
this.activeMenuArr[page_index].splice(2, 1, level3_index);
tmpMemu = tmpMemu.submenu[level3_index];
this.selectedMemu(page_index, level1_index, level2_index, level3_index);
}
}
},
selectedMemu(page_index, level1_index, level2_index, level3_index){
let sub = this.subData[page_index].submenu[level1_index].submenu[level2_index];
if(this.updateMenuName){
this.menu[page_index].name = (level3_index != null && sub.submenu[level3_index].name) || (level2_index != null && sub.name) || this.subData[page_index].submenu[level1_index].name;
}
this.shadowActiveMenuArr[page_index] = JSON.parse(JSON.stringify(this.activeMenuArr[page_index]));
this.hideMenu(true);
},
//
setFilterData(page_index) {
this.shadowActiveMenuArr[page_index] = JSON.parse(JSON.stringify(this.activeMenuArr[page_index]));
this.hideMenu(true);
},
//ui
resetFilterData(page_index) {
let tmpArr = [];
let level = this.shadowActiveMenuArr[page_index].length;
while (level > 0) {
tmpArr.push([]);
let box = this.subData[page_index].submenu[level - 1].submenu;
for (let i = 0; i < box.length; i++) {
this.subData[page_index].submenu[level - 1].submenu[i].selected = false;
}
level--;
}
this.activeMenuArr[page_index] = JSON.parse(JSON.stringify(tmpArr));
this.$forceUpdate();
},
//label-UI
selectFilterLabel(page_index, box_index, label_index) {
let find_index = this.activeMenuArr[page_index][box_index].indexOf(label_index);
if (find_index > -1) {
this.activeMenuArr[page_index][box_index].splice(find_index, 1);
this.subData[page_index].submenu[box_index].submenu[label_index].selected = false;
} else {
this.activeMenuArr[page_index][box_index].push(label_index);
this.subData[page_index].submenu[box_index].submenu[label_index].selected = true;
}
this.$forceUpdate();
},
//label-UI
selectRadioLabel(page_index, box_index, label_index) {
let activeIndex = this.activeMenuArr[page_index][box_index][0];
if(activeIndex == label_index){
this.subData[page_index].submenu[box_index].submenu[activeIndex].selected = false;
this.activeMenuArr[page_index][box_index][0] = null;
}else{
if(activeIndex!=null && activeIndex<this.subData[page_index].submenu[box_index].submenu.length){
this.subData[page_index].submenu[box_index].submenu[activeIndex].selected = false;
}
this.subData[page_index].submenu[box_index].submenu[label_index].selected = true;
this.activeMenuArr[page_index][box_index][0] = label_index;
}
this.$forceUpdate();
},
//
togglePage(index) {
if(this.isToggleing){return;}
this.isToggleing = true;
if (index == this.showPage) {
this.hideMenu();
} else {
this.showMenu(index)
}
setTimeout(()=>{
this.isToggleing = false;
},150)
},
//hide
hideMenu(isTriggerConfirm){
this.hideMenuLayer(true);
this.hideMaskLayer();
this.showPage = -1;
if(isTriggerConfirm){
this.confirm()
}
},
showMenu(index){
if(this.showPage>-1){
this.hideMenuLayer(false);
}
this.showMenuLayer(index);
this.showMaskLayer();
},
//hide
hideMaskLayer() {
this.isShowMask = false;
setTimeout(() => {
this.maskVisibility = false;
}, 200);
},
//show
showMaskLayer() {
this.maskVisibility = true;
this.$nextTick(() => {
setTimeout(()=>{
this.isShowMask = true;
},0)
})
},
//hide
hideMenuLayer(isAnimation) {
this.triangleDeg[this.showPage] = 0;
let tmpIndex = this.showPage;
if (isAnimation) {
setTimeout(() => {
this.pageState.splice(tmpIndex, 1, false);
}, 200);
} else {
this.pageState.splice(tmpIndex, 1, false)
}
this.firstScrollInto = null;
this.secondScrollInto = null;
},
//show
showMenuLayer(index) {
this.processPage(index);
this.pageState.splice(index, 1, true);
this.$nextTick(() => {
setTimeout(()=>{
this.showPage = index;
},0)
})
this.triangleDeg[index] = 180;
},
confirm() {
let index = JSON.parse(JSON.stringify(this.shadowActiveMenuArr));
let value = JSON.parse(JSON.stringify(this.shadowActiveMenuArr));
//
index.forEach((item, i) => {
if (typeof(item[0]) == 'object') {
//
item.forEach((s, j) => {
if(s!=null){
s.sort((val1, val2) => {
return val1 - val2;
});
item[j] = s;
s.forEach((v, k) => {
value[i][j][k] = (v==null||v>=this.subData[i].submenu[j].submenu.length)?null:this.subData[i].submenu[j].submenu[v].value;
if(this.subData[i].type == 'radio' && value[i][j][k] == null){
value[i][j] = [];
index[i][j] = [];
}
});
}
});
}else{
let submenu = this.subData[i].submenu[item[0]];
value[i][0] = submenu.value;
if(value[i].length>=2 && item[1]!=null){
if(submenu.submenu.length>0){
submenu = submenu.submenu[item[1]];
value[i][1] = submenu.hasOwnProperty('value')?submenu.value:null;
}else{
value[i][1] = null
}
if(value[i].length>=3 && item[2]!=null){
if(submenu.submenu.length>0){
submenu = submenu.submenu[item[2]];
value[i][2] = submenu.hasOwnProperty('value')?submenu.value:null;
}else{
value[i][2] = null;
}
}
}
}
index[i] = item;
});
//
this.$emit('confirm', {
index: index,
value: value
});
},
reloadActiveMenuArr(){
for (let i = 0; i < this.menuData.length; i++) {
let tmpitem = this.menuData[i];
let tmpArr = this.processActive(tmpitem);
tmpitem = this.processSubMenu(tmpitem);
if(this.activeMenuArr[i].length!=tmpArr.length){
this.menuData[i] = tmpitem;
this.activeMenuArr.splice(i, 1, JSON.parse(JSON.stringify(tmpArr)));
this.shadowActiveMenuArr.splice(i, 1, JSON.parse(JSON.stringify(tmpArr)));
}
}
this.subData = this.menuData;
this.$forceUpdate();
},
processPage(index) {
//check UI,UI
this.reloadActiveMenuArr();
//UI
this.activeMenuArr.splice(index, 1, JSON.parse(JSON.stringify(this.shadowActiveMenuArr[index])));
if (this.menu[index].type == 'filter') {
//
let level = this.shadowActiveMenuArr[index].length;
for (let i = 0; i < level; i++) {
let box = this.subData[index].submenu[i].submenu;
for (let j = 0; j < box.length; j++) {
if (this.shadowActiveMenuArr[index][i].indexOf(j) > -1) {
this.subData[index].submenu[i].submenu[j].selected = true;
} else {
this.subData[index].submenu[i].submenu[j].selected = false;
}
}
}
} else if (this.menu[index].type == 'hierarchy') {
this.$nextTick(() => {
setTimeout(() => {
//
this.firstScrollInto = parseInt(this.activeMenuArr[index][0]);
this.secondScrollInto = parseInt(this.activeMenuArr[index][1]);
}, 0);
})
}else if (this.menu[index].type == 'hierarchy-column') {
this.$nextTick(() => {
setTimeout(() => {
//
this.firstScrollInto = parseInt(this.activeMenuArr[index][0]);
this.secondScrollInto = parseInt(this.activeMenuArr[index][1]);
this.thirdScrollInto = parseInt(this.activeMenuArr[index][2]);
}, 0);
})
} else if (this.menu[index].type == 'radio') {
//
let level = this.shadowActiveMenuArr[index].length;
for (let i = 0; i < level; i++) {
let box = this.subData[index].submenu[i].submenu;
for (let j = 0; j < box.length; j++) {
if (this.shadowActiveMenuArr[index][i].indexOf(j) > -1) {
this.subData[index].submenu[i].submenu[j].selected = true;
} else {
this.subData[index].submenu[i].submenu[j].selected = false;
}
}
}
}
},
processActive(tmpitem) {
let tmpArr = []
if ((tmpitem.type == 'hierarchy'||tmpitem.type == 'hierarchy-column')&&tmpitem.hasOwnProperty('submenu')&&tmpitem.submenu.length>0) {
let level = this.getMaxFloor(tmpitem.submenu);
while (level > 0) {
tmpArr.push(null);
level--;
}
} else if (tmpitem.type == 'filter') {
let level = tmpitem.submenu.length;
while (level > 0) {
tmpArr.push([]);
level--;
}
} else if (tmpitem.type == 'radio') {
let level = tmpitem.submenu.length;
while (level > 0) {
tmpArr.push([]);
level--;
}
}
return tmpArr;
},
processSubMenu(menu) {
if (menu.hasOwnProperty('submenu') && menu.submenu.length > 0) {
for (let i = 0; i < menu.submenu.length; i++) {
menu.submenu[i] = this.processSubMenu(menu.submenu[i]);
}
} else {
menu.submenu = [];
}
return menu;
},
//
getMaxFloor(treeData) {
let floor = 0
let max = 0
function each(data, floor) {
data.forEach(e => {
max = floor > max ? floor : max;
if (e.hasOwnProperty('submenu') && e.submenu.length > 0) {
each(e.submenu, floor + 1)
}
})
}
each(treeData, 1)
return max;
},
discard() {
}
}
}
</script>
<style lang="scss">
.HMfilterDropdown {
flex-shrink: 0;
width: 100%;
position: fixed;
// position: sticky;
z-index: 997;
flex-wrap: nowrap;
display: flex;
flex-direction: row;
top: var(--window-top);
left:0;
// top:100px;
overflow-y: hidden;
&.setDropdownBottom{
// height: 345px;
bottom: 0;
}
view {
display: flex;
flex-wrap: nowrap;
}
}
.region {
flex: 1;
height: 44px;
}
.nav {
width: 100%;
height: 44px;
border-bottom: solid 1rpx #eee;
z-index: 12;
background-color: #ffffff;
flex-direction: row;
.first-menu {
width: 100%;
font-size: 13px;
color: #757575;
flex-direction: row;
align-items: center;
justify-content: center;
transition: color .2s linear;
&.on {
color: #ec652b;
.iconfont {
color: #ec652b;
}
}
.name {
height: 20px;
text-align: center;
text-overflow: clip;
overflow: hidden;
}
.iconfont {
width: 13px;
height: 13px;
align-items: center;
justify-content: center;
transition: transform .2s linear, color .2s linear;
}
}
}
.sub-menu-class {
width: 100%;
position: absolute;
left: 0;
transform: translate3d(0, - 100%, 0);
max-height: 345px;
background-color: #ffffff;
z-index: 11;
box-shadow: 0 5px 5px rgba(0, 0, 0, .1);
overflow: hidden;
flex-direction: row;
transition: transform .15s linear;
&.hide {
display: none;
}
&.show {
transform: translate3d(0, calc(44px + 1rpx), 0);
}
}
.sub-menu-list {
width: 100%;
height: 345px;
flex-direction: column;
.sub-menu {
min-height: 44px;
font-size: 13px;
flex-direction: column;
padding-right: 15px;
>.menu-name {
height: 44px;
flex-direction: row;
align-items: center;
justify-content: space-between;
>.iconfont {
display: none;
font-size: 18px;
color: #ec652b;
}
}
}
&.first {
flex-shrink: 0;
width: 236rpx;
background-color: #f0f0f0;
.sub-menu {
padding-left: 15px;
&.on {
background-color: #fff;
}
}
box-shadow: 5rpx 0 5rpx rgba($color: #000000, $alpha: 0.1);
}
&.alone {
max-height: 345px;
min-height: 170px;
height: auto;
.sub-menu {
min-height: calc(44px - 1rpx);
margin-left: 15px;
border-bottom: solid 1rpx #e5e5e5;
&.on {
color: #ec652b;
>.menu-name {
>.iconfont {
display: block;
}
}
}
}
}
&.third{
// box-shadow: 5rpx 0 20rpx rgba($color: #000000, $alpha: 0.2) inset;
}
&.not-first {
box-shadow: 5rpx 0 5rpx rgba($color: #000000, $alpha: 0.1);
.sub-menu {
min-height: calc(44px - 1rpx);
margin-left: 15px;
border-bottom: solid 1rpx #e5e5e5;
>.menu-name {
height: calc(44px - 1rpx);
>.iconfont {
display: none;
font-size: 18px;
color: #ec652b;
}
}
&.on {
color: #ec652b;
>.menu-name {
>.iconfont {
display: block;
}
}
}
.more-sub-menu {
flex-direction: row;
flex-wrap: wrap;
padding-bottom: 9px;
>text {
height: 30px;
border-radius: 3px;
background-color: #f5f5f5;
color: #9b9b9b;
margin-bottom: 6px;
margin-right: 6px;
text-align: center;
line-height: 30px;
border: solid #f5f5f5 1rpx;
flex: 0 0 calc(33.33% - 6px);
overflow: hidden;
font-size: 12px;
&:nth-child(3n) {
margin-right: 0;
}
&.on {
border-color: #f6c8ac;
color: #ec652b;
}
.iconfont {
color: #9b9b9b;
}
}
}
}
}
}
.filter {
width: 100%;
height: 345px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
.menu-box {
width: 698rpx;
height: calc(345px - 75px);
flex-shrink: 1;
.box {
width: 100%;
padding-top: 16px;
flex-direction: column;
.title {
width: 100%;
font-size: 13px;
color: #888;
}
.labels {
flex-direction: row;
flex-wrap: wrap;
.on {
border-color: #ec652b;
background-color: #ec652b;
color: #fff;
}
>view {
box-sizing: border-box;
width: calc((698rpx - 30rpx * 3) / 4);
height: 30px;
border: solid 1rpx #adadad;
border-radius: 2px;
margin-right: 30rpx;
margin-top: 8px;
font-size: 12px;
flex-direction: row;
justify-content: center;
align-items: center;
&:nth-child(4n) {
margin-right: 0;
}
}
}
}
}
.btn-box {
flex-shrink: 0;
width: 698rpx;
height: 75px;
flex-direction: row !important;
align-items: center;
justify-content: space-between;
>view {
width: 320rpx;
height: 40px;
border-radius: 40px;
border: solid 1rpx #ec652b;
align-items: center;
justify-content: center;
}
.reset {
color: #ec652b;
}
.submit {
color: #fff;
background-color: #ec652b;
}
}
}
.mask {
z-index: 10;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0);
transition: background-color .15s linear;
&.show {
background-color: rgba(0, 0, 0, 0.5);
}
&.hide {
display: none;
}
}
/* 字体图标 */
@font-face {
font-family: "HM-FD-font";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALAAAsAAAAABpQAAAJzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgp4gQIBNgIkAwwLCAAEIAWEbQc5G8sFERWMIbIfCbbzqA4hp7InSBibVsYGb4J42o82b3e/nJlHMw/NHbGOlwKJRCRpwzPtpAECCOZubdqxjYpQLMlVg+70/08edrgQOtx2ukpVyApZn+dyehPoQObHo3O85rYx9vOjXoBxQIHugW2yIkqIW2QXcScu4jwE8CSWbKSmrqUHFwOaJoCsLM5P4haSGIxRcRHshrUGucLCVcfqI3AZfV/+USguKCwNmtsxVztDxU/n55C+3W0Z4QQpEOTNFqCBbMCAjDUWB9CIwWk87aa70cYgqLkyd3dEmm+18R8eKATEBrV7A5CulBT8dKiWOYZk412XNcDdKSEKSGODnyKIDl+dmVt9/Dx4pu/xyeutkMlHISGPTsPCnoTNP9nOT6wTtDdlO6dPr47efvj942lkYuQzrhMKEjq9N6y98P3340gmlJ/RStUD6F31CAEEPtUW94/7rf+7XgaAz57X0ZHXAGsFFwVgw38yALuMb0IBbVyNamFYEw4oKMDTj3AHRQP5Pt4dci9VwSVkRNQh5r7CLskZadhsWHhRDBsXczk8ZYk3ewnCxmQeQKa3BOHvA8XXO2j+vqRhf7CE+sPmn4anvoL29JLa4qqaUQkmoK+QG2osCckq7txi2leK86aIPyJ3eQZ8xytXYmyQ51jQndJAxIJlqiGSLsOqImiZCjTiZCJt6Lq26U2OoXqwUo0hRaAE0K5AziANy/uLVeXzWyjVqyjcoeupjxDr5MMDn8MDkLG9Aenu5ZrOSSoghAUsRmogkkahSoWAtnlUARnCkY3It0Iu7mWhdmd9Z/19BwBP6GidEi0G56opckXTGZVSPxgAAAA=');
}
.iconfont {
font-family: "HM-FD-font" !important;
font-size: 13px;
font-style: normal;
color: #757575;
&.triangle {
&:before {
content: "\e65a";
}
}
&.selected {
&:before {
content: "\e607";
}
}
}
</style>

View File

@ -0,0 +1,82 @@
{
"id": "HM-filterDropdown",
"displayName": "下拉式筛选菜单",
"version": "1.0.1",
"description": "商城团购常用的下拉式筛选菜单最多支持3级子菜单支持多选/单选筛选",
"keywords": [
"",
"筛选",
"下拉菜单",
"filter",
"多选",
"单选"
],
"repository": "",
"engines": {
"HBuilderX": "^3.5.0"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "u",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "n",
"IE": "n",
"Edge": "n",
"Firefox": "n",
"Safari": "n"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
}
}

View File

@ -0,0 +1,36 @@
> 组件兼容APP-VUE、H5、MP-WEIXIN其他端未做兼容测试不支持。
> 遇到问题或有建议可以[加入QQ群(147157269)](https://shang.qq.com/wpa/qunwpa?idkey=0d4297636dde21703e0e6eb69b9fdde90725625ea7fca51ba0d440837eac9d92)反馈
> 如果觉得组件不错,<font color=#f00>给五星鼓励鼓励</font>咯!
<img src="http://hmsmscode.hmwh.me/menu.png" width="214" height="221" />
安卓扫码下载体验
##使用说明
在页面中使用组件
```
<HM-filterDropdown :filterData="filterData" :defaultSelected ="filterDropdownValue" @confirm="confirm"></HM-filterDropdown>
```
###传入数据格式等更多的说明请下载示例查看,有数据对照注释更容易明白。
##属性说明
|属性名 |类型 |说明 |
|-- |-- |-- |
|filterData|Object |必选,菜单数据,数据格式请下载示例查看 |
|defaultSelected|Array |可选,默认选中子菜单数据,需要传入跟``@confirm``输出的index相同的结构数据如不确定可以先传入数据看下输出的结果 |
|updateMenuName|Boolean |可选,选择子菜单是否自动修改对应的顶部菜单文字,可取值:``true``/``false``,默认值:``true`` |
|menuTop|Number |可选菜单到顶部距离单位rpx一般用于页面有自己写的标题栏或搜索栏时默认值:0 |
|@confirm|EventHandle |用户选择完毕/收起菜单触发confirm事件event= {value,index} |
###传入数据格式等更多的说明请下载示例查看,有数据对照注释更容易明白。
####偷偷的打广告
定制模板开发uniapp、H5+APP、wap2app、PHP付费咨询指导有需要加QQ。
<table><tr><td bgcolor=#8f9396 >
<center><font color=#8f9396>QQ:565766672</font> <font color=#fff>(刮刮卡)</font></center>
</td></tr></table>

View File

@ -0,0 +1,2 @@
## 1.0.02023-05-21
1.0.0

View File

@ -0,0 +1,89 @@
<template>
<view class="rate-box">
<block v-for="(item,index) in starNum" :key="index">
<view class="l-icons icon-xingxing star" :class="[hollow&&(index+1>value)?'icon-xingxing1':'icon-xingxing']"
:style="{color:index+1 <= value ? activeColor : unActiveColor}" @click="change(index)"></view>
</block>
</view>
</template>
<script>
export default {
name: 'lStarRate',
model: {
prop: 'value',
event: 'input'
},
props: {
//
starNum: {
type: Number,
default: 5
},
//
value: {
type: Number,
default: 0
},
//
activeColor: {
type: String,
default: '#F2CB51'
},
//
unActiveColor: {
type: String,
default: '#B2B2B2'
},
//
hollow: {
type: Boolean,
default: false
},
//
disabled: {
type: Boolean,
default: false
},
},
methods:{
change(index){
if(this.disabled) return
this.$emit('input',index+1)
}
}
};
</script>
<style lang="scss" scoped>
@font-face {
font-family: 'l-icons';
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAT4AA0AAAAAB4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAE3AAAABoAAAAciBprQUdERUYAAAS8AAAAHgAAAB4AKQALT1MvMgAAAaAAAABDAAAAVj1YSN1jbWFwAAAB+AAAAEIAAAFCAA/qlmdhc3AAAAS0AAAACAAAAAj//wADZ2x5ZgAAAkgAAADwAAABZLMTdXtoZWFkAAABMAAAADAAAAA2FZKISmhoZWEAAAFgAAAAHQAAACQHYgOFaG10eAAAAeQAAAARAAAAEgx6AHpsb2NhAAACPAAAAAwAAAAMAEYAsm1heHAAAAGAAAAAHgAAACABEQBPbmFtZQAAAzgAAAFJAAACiCnmEVVwb3N0AAAEhAAAAC0AAABHLO3vkXjaY2BkYGAA4t2/VF7G89t8ZeBmYQCBm9ZKMnC6ikGMuYXpP5DLwcAEEgUAHPQJOXjaY2BkYGBu+N/AEMPCAALMLQyMDKiABQBQwgLwAAAAeNpjYGRgYGBlcGZgYgABEMkFhAwM/8F8BgAPigFhAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PXj17zdzwv4EhhrmBoQEozAiSAwD/YA2wAHjaY2GAABYIrmKoAgACggEBAAAAeNpjYGBgZoBgGQZGBhCwAfIYwXwWBgUgzQKEQP6z1///A8lX//9LSkJVMjCyMcCYDIxMQIKJARUwMgx7AAA/9QiLAAAAAAAAAAAAAABGALJ42mNgZKhiEGNuYfrPoMnAwGimps+ox6jPqKbEz8jHCMLyjHJAmk1czMie0cxInlHMDChrZs6cJyaosI+NlzmU34I/lImPdb+CoHgXCyujIosYtzTfKlYBtlWyuqwKjKwsjNvFTdlkGDnZ1srKrmXjZJRhMxVvZxFgA+rgYI9iYoriV1TYzybAwsDABHeLBIMT0DUg29VBTjEHucvcjtGeUVyOUZ6JaFcybefnZ5HuFdEX6ZVm5uMvniemxuXmzqUmNs+FeOfHCeiKzfPi4vKaJ6YrUCDOIiM8YYKwDIu4OMRbrOtkZdex4vMWACzGM5B42n2QPU4DMRCFn/MHJBJCIKhdUQDa/JQpEyn0CKWjSDbekGjXXnmdSDkBLRUHoOUYHIAbINFyCl6WSZMia+3o85uZ57EBnOMbCv/fJe6EFY7xKFzBETLhKvUX4Rr5XbiOFj6FG9R/hJu4VQPhFi7UGx1U7YS7m9JtywpnGAhXcIon4Sr1lXCN/CpcxxU+hBvUv4SbGONXuIVrZakM4WEwQWCcQWOKDeMCMRwskjIG1qE59GYSzExPN3oRO5s4GyjvV2KXAx5oOeeAKe09t2a+Sif+YMuB1JhuHgVLtimNLiJ0KBtfLJzV3ahzsP2e7ba02L9rgTXH7FENbNT8Pdsz0khsDK+QkjXyMrekElOPaGus8btnKdbzXgiJTrzL9IjHmjR1OvduaeLA4ufyjBx9tLmSPfeoHD5jWQh5v91OxCCKXYY/k9hxGQAAAHjaY2BigAAuMMnIgA5YwaJMjEyMzPzJ+Tk5qcklmfl58WmZOTlcCD4Ak9QKlAAAAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAQAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPRNayUZGA0AM8UETgAA) format('woff');
font-weight: normal;
font-style: normal;
}
/* icon默认样式 */
.l-icons {
font-family: 'l-icons';
font-size: 30rpx;
color: #333333;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
.icon-xingxing:before {
content: "\e6ea";
}
.icon-xingxing1:before {
content: "\e6eb";
}
.rate-box {
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,84 @@
{
"id": "l-starRate",
"displayName": "五星评价 星星评价 评价",
"version": "1.0.0",
"description": "五星评价 星星评价 评价 可设置星星总数 仅测过小程序其他自测",
"keywords": [
"l-starRate",
"五星评价",
"星星评价",
"评价",
"五星评论"
],
"repository": "",
"engines": {
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
}
}
}
}
}

View File

@ -0,0 +1,20 @@
# l-starRate
# ## 使用方法
配置easycom规则后自动按需引入无需`import`组件,直接引用即可。
```html
<template>
<l-starRate v-model="star" :disabled="false"></l-starRate>
</template>
```
## 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|:---:|:---:|:---:|---|
| value | Number | 0 | 选中星星数量 v-model双向绑定 |
| starNum | Number | 5 | 星星总数 |
| activeColor | String | #F2CB51 | 选中颜色 |
| unActiveColor | String | #B2B2B2 | 未选中时的颜色 |
| hollow | Boolean | false | 是否空心 |
| disabled | Boolean | false | 禁用点击 |

View File

@ -0,0 +1,8 @@
## 1.0.32023-06-10
增加插件预览二维码
## 1.0.22023-04-14
增加示例
## 1.0.12023-03-30
优化功能
## 1.0.02023-03-14
初版发布

View File

@ -0,0 +1,126 @@
<template>
<view>
<view class="progress-bar" :style="{height: height,backgroundColor:dsColor}" v-if="textInside">
<view class="progress" :style="{width: progressWidth, backgroundColor: bgColor,borderRadius: borderRadius}">
</view>
<span class="percentage" :style="{color:color,fontSize:fontSize }">{{ percentage }}%</span>
</view>
<view class="card-item" v-else>
<view class="progress-bar1" :style="{height: height,backgroundColor:dsColor}">
<view class="progress1"
:style="{width: progressWidth, backgroundColor: bgColor,borderRadius: borderRadius}">
</view>
</view>
<view class="percentage1" :style="{color:color,fontSize:fontSize }">{{ percentage }}%</view>
</view>
</view>
</template>
<script>
export default {
props: {
//
textInside: {
type: Boolean,
default: true
},
//
progress: {
type: Number,
required: true,
validator: (value) => value >= 0 && value <= 100,
default: 50
},
//
color: {
type: String,
default: '#FFFFFF'
},
//
fontSize: {
type: String,
default: '24rpx'
},
//
bgColor: {
type: String,
default: '#5cb85c'
},
//
dsColor: {
type: String,
default: '#f2f2f2'
},
//
height: {
type: String,
default: '28rpx'
},
//
borderRadius: {
type: String,
default: '8rpx'
}
},
computed: {
progressWidth() {
return `${this.progress}%`
},
percentage() {
return Math.round(this.progress)
}
}
};
</script>
<style scoped>
.progress-bar {
position: relative;
width: 100%;
background-color: #f2f2f2;
border-radius: 16rpx;
}
.percentage {
position: absolute;
top: 50%;
left: 50%;
color: #666;
transform: translate(-50%, -50%);
font-size: 24rpx;
user-select: none;
z-index: 1;
}
.progress {
position: absolute;
top: 0;
left: 0;
height: 100%;
}
.card-item {
display: flex;
align-items: center;
justify-content: space-between;
}
.progress-bar1 {
position: relative;
width: 90%;
background-color: #f2f2f2;
border-radius: 16rpx;
}
.percentage1 {
color: #666;
font-size: 24rpx;
}
.progress1 {
position: absolute;
top: 0;
left: 0;
height: 100%;
}
</style>

View File

@ -0,0 +1,6 @@
### 1、本插件可免费下载使用
### 2、未经许可严禁复制本插件派生同类插件上传插件市场
### 3、未经许可严禁在插件市场恶意复制抄袭本插件进行违规获利;
### 4、对本软件的任何使用都必须遵守这些条款违反这些条款的个人或组织将面临法律追究。

View File

@ -0,0 +1,83 @@
{
"id": "liu-progressbar",
"displayName": "进度条组件",
"version": "1.0.3",
"description": "自定义进度条组件,支持设置文字内显、当前进度、文字颜色、文字大小、进度条颜色、进度条底色、进度条高度、进度条圆角弧度",
"keywords": [
"进度条",
"百分比",
"进度"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "u"
},
"App": {
"app-vue": "u",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@ -0,0 +1,44 @@
### liu-progressbar适用于uni-app项目的进度条组件
### 本组件目前兼容微信小程序、H5
### 本组件支持自定义,支持设置文字内显、当前进度、文字颜色、文字大小、进度条颜色、进度条底色、进度条高度、进度条圆角弧度
# --- 扫码预览、关注我们 ---
## 扫码关注公众号,查看更多插件信息,预览插件效果!
![](https://uni.ckapi.pro/uniapp/publicize.png)
### 使用方式
``` html
<view class="title">文字内显</view>
<liu-progressbar :progress="70" color="#FFFFFF" :height="'40rpx'" />
<view class="title">文字外显</view>
<liu-progressbar :textInside="false" :progress="70" color="#333333" :height="'40rpx'" />
<view class="title">自定义高度</view>
<liu-progressbar :progress="70" color="#FFFFFF" :height="'25rpx'" />
<view class="title">自定义圆角弧度</view>
<liu-progressbar :progress="70" color="#FFFFFF" :height="'40rpx'" :borderRadius="'40rpx'" />
<view class="title">自定义进度条颜色</view>
<liu-progressbar :progress="70" bgColor="red" color="#FFFFFF" :height="'40rpx'" />
<view class="title">自定义底色</view>
<liu-progressbar :progress="70" dsColor="red" color="#FFFFFF" :height="'40rpx'" />
```
### 属性说明
| 名称 | 类型 | 默认值 | 描述 |
| ----------------------------|---------------- | ---------------------- | ---------------|
| textInside | Boolean | true | 文字是否内显
| progress | Number | 50 | 当前进度
| color | String | #FFFFFF | 文字颜色
| fontSize | String | 24rpx | 文字大小
| bgColor | String | #5cb85c | 进度条颜色
| dsColor | String | #f2f2f2 | 进度条底色颜色
| height | String | 28rpx | 进度条高度
| borderRadius | String | 8rpx | 进度条圆角弧度

View File

@ -0,0 +1,2 @@
## 1.0.22023-09-19
改为uni_modules规范

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

View File

@ -0,0 +1,666 @@
<template>
<view class="">
<view class="screen">
<view class="screen-item" @tap="showModel" :class="{'active' : modelFlag}">
<text class="text">{{modelStr ? modelStr : '类型'}}</text>
<image v-if="modelFlag" :src="require('./top.png')"></image>
<image v-else :src="require('./bottom.png')"></image>
</view>
<view class="screen-item" :class="{'actives' : nearbyFlag}" @tap="showNearby">
<text>{{nearbyStr}}</text>
<image v-if="nearbyFlag" :src="require('./top.png')"></image>
<image v-else :src="require('./bottom.png')"></image>
</view>
<view @tap="showSearch" class="screen-item" :class="{'actives' : searchFlag}">
<text>{{searchStr}}</text>
<image v-if="searchFlag" :src="require('./top.png')"></image>
<image v-else :src="require('./bottom.png')"></image>
</view>
<view class="screen-item" :class="{'actives' : screenFlag}" @tap="showScreen">
<text>筛选</text>
<image v-if="screenFlag" :src="require('./top.png')"></image>
<image v-else :src="require('./bottom.png')"></image>
</view>
</view>
<view @tap="close" @touchmove.stop.prevent
:class="modelFlag || nearbyFlag || searchFlag || screenFlag ? 'pupop-model' : 'pupop-models'"></view>
<!-- 筛选类型 -->
<view class="pupop">
<view class="popup-box" :animation="modelAnimationData">
<scroll-view class="modelscroll" enhanced :show-scrollbar="false" :scroll-y="true">
<view class="modelscroll-item" v-for="(item, index) in modelList" :key="index">
<view class="title">{{item.title}}</view>
<view class="itembox">
<view @tap="changeModel({title: item.title, value: itemName.value})" class="item"
:class="itemName.flag ? 'itemActive' : ''" v-for="(itemName, idx) in item.children"
:key="idx">{{itemName.name}}</view>
</view>
</view>
</scroll-view>
<view class="btns">
<view class="btn-item" @tap="searchReset">重置</view>
<view class="btn-item" @tap="searchFinish">完成</view>
</view>
</view>
</view>
<!-- 附近 -->
<view class="pupop">
<view class="popup-box" :animation="disAnimationData">
<scroll-view class="popupboxbox" :scroll-y="true" enhanced :show-scrollbar="false">
<view class="popupbox-item">
<view class="title">
范围
</view>
<view class="itembox">
<view @tap="changeDis({type: 'distince', id: item.id})" class="item"
:class="item.id == distince ? 'active' : ''" v-for="(item, index) in disList"
:key="index">{{item.name}}</view>
</view>
</view>
<view class="popupbox-item">
<view class="title">行政区</view>
<view class="itembox">
<view class="item" :class="item.id == city ? 'active' : ''"
@tap="changeDis({type: 'city', id: item.id})" v-for="(item, index) in cityList"
:key="index">
<view>{{item.name}}</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 排序 -->
<view class="pupop">
<view class="popup-box" :animation="searchAnimationData">
<view class="sortbox">
<view @tap="changesSearch(index)" class="sort-item" :class="index == searchIndex ? 'active' : ''"
v-for="(item, index) in searchList" :key="index">{{item.name}}</view>
</view>
</view>
</view>
<!-- 筛选 -->
<view class="pupop">
<view class="popup-box" :animation="labelAnimationData">
<scroll-view class="popupboxbox" :scroll-y="true" enhanced :show-scrollbar="false">
<view class="popupbox-item">
<view class="title">标签</view>
<view class="itembox">
<view @tap="changeLabel(item)" class="item" :class="item.flag ? 'active' : ''"
v-for="(item, index) in labelList" :key="index">{{item.name}}</view>
</view>
</view>
</scroll-view>
<view class="btns">
<view class="btn-item" @tap="searchReset">重置</view>
<view class="btn-item" @tap="searchFinish">完成</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
modelFlag: false,
modelStr: '',
models: [],
nearbyFlag: false,
nearbyStr: '附近',
searchFlag: false,
searchStr: '智能排序',
screenFlag: false,
distince: '',
city: '',
labels: [],
searchIndex: 0,
location: '',
modelAnimationData: {},
disAnimationData: {},
searchAnimationData: {},
labelAnimationData: {}
}
},
props: {
modelList: {
type: Array,
default: () => []
},
disList: {
type: Array,
default: () => []
},
cityList: {
type: Array,
default: () => []
},
searchList: {
type: Array,
default: () => []
},
labelList: {
type: Array,
default: () => []
},
},
methods: {
//
showModel() {
if (this.modelFlag) {
this.modelFlag = false
} else {
this.searchFlag = false
this.nearbyFlag = false
this.screenFlag = false
this.modelFlag = true
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
},
changeModel(e) {
var value = e.value
var models = this.models
if (models.indexOf(value) > -1) {
models.splice(models.indexOf(value), 1)
} else {
models.push(value)
}
this.models = models
this.activeModel()
},
onModelClose() {
this.modelFlag = false
},
activeModel() {
var modelList = this.modelList
modelList.forEach(item => {
item.children.forEach(list => {
if (this.models.indexOf(list.value) > -1) {
list.flag = true
} else {
list.flag = false
}
})
})
this.$emit("update:modelList", [...modelList]);
},
searchReset() {
if (this.modelFlag) {
this.modelFlag = false
this.modelStr = ''
this.models = []
this.activeModel()
} else {
this.screenStr = ''
this.labels = []
this.classs = []
this.discounts = []
this.screenFlag = false
this.labelModel()
this.discountModel()
this.classModel()
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
var result = this.getResult()
this.$emit('searchFinish', result)
},
searchFinish() {
if (this.modelFlag) {
var modelStr = ''
var models = this.models
var modelList = this.modelList
modelList.forEach(item => {
item.children.forEach(list => {
if (models.indexOf(list.value) > -1) {
modelStr = modelStr + `${item.title}/${list.name}`
}
})
})
this.modelFlag = false
this.modelStr = modelStr
} else {
this.screenFlag = false
this.screenStr = 11111
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
var result = this.getResult()
this.$emit('searchFinish', result)
},
showSearch() {
if (this.searchFlag) {
this.searchFlag = false
} else {
this.searchFlag = true
this.modelFlag = false
this.screenFlag = false
this.nearbyFlag = false
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
},
showNearby() {
if (this.nearbyFlag) {
this.nearbyFlag = false
} else {
this.searchFlag = false
this.modelFlag = false
this.screenFlag = false
this.nearbyFlag = true
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
},
changeDis(e) {
var type = e.type
var value = e.id
if (type == 'distince') {
this.location = ''
var disList = this.disList
var nearbyStr = ''
disList.forEach(item => {
if (item.id == value) {
nearbyStr = item.name
}
})
this.nearbyStr = nearbyStr
this.city = ''
} else {
var nearbyStr = ''
var cityList = this.cityList
cityList.forEach(item => {
if (item.id == value) {
nearbyStr = item.name
}
})
this.nearbyStr = nearbyStr
this.distince = ''
}
this.nearbyFlag = false
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
this[type] = value
var result = this.getResult()
this.$emit('searchFinish', result)
},
showScreen() {
if (this.screenFlag) {
this.screenFlag = false
} else {
this.searchFlag = false
this.nearbyFlag = false
this.screenFlag = true
this.modelFlag = false
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
},
labelModel() {
var labelList = this.labelList
labelList.forEach(item => {
if (this.labels.indexOf(item.name) > -1) {
item.flag = true
} else {
item.flag = false
}
})
this.$emit("update:labelList", [...labelList]);
},
discountModel() {
var discountList = this.discountList
discountList.forEach(item => {
if (this.discounts.indexOf(item.value) > -1) {
item.flag = true
} else {
item.flag = false
}
})
this.discountList = [...discountList]
},
//
changeActive(type) {
var active = '-1000px'
if (this[type]) {
active = 0
}
var animation = uni.createAnimation({
duration: 200,
timingFunction: 'linear'
})
animation.top(active).step()
if (type == 'modelFlag') {
this.modelAnimationData = animation.export()
} else if (type == 'nearbyFlag') {
this.disAnimationData = animation.export()
} else if (type == 'searchFlag') {
this.searchAnimationData = animation.export()
} else if (type == 'screenFlag') {
this.labelAnimationData = animation.export()
}
},
changesSearch(index) {
var searchList = this.searchList
if (this.searchIndex == index) {
return
} else {
this.searchFlag = false
this.searchStr = searchList[index].name
this.searchIndex = index
}
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
var result = this.getResult()
this.$emit('searchFinish', result)
},
changeLabel(item) {
var value = item.name
var labels = this.labels
if (labels.indexOf(value) > -1) {
labels.splice(labels.indexOf(value), 1)
} else {
labels.push(value)
}
this.labels = labels
this.labelModel()
},
getResult() {
var obj = {}
var modelStr = this.modelStr
if (modelStr) {
var models = this.models
if (models.length) {
obj.models = models.join(',')
}
}
var distince = this.distince
var city = this.city
if (distince) {
obj.distince = distince
} else if (city) {
obj.areaCode = city
}
obj.searchIndex = this.searchIndex + 1
if (this.screenStr) {
var labels = this.labels
if (labels.length) {
obj.labels = labels.join(',')
}
}
return obj
},
close() {
this.searchFlag = false
this.nearbyFlag = false
this.screenFlag = false
this.modelFlag = false
this.changeActive('modelFlag')
this.changeActive('nearbyFlag')
this.changeActive('screenFlag')
this.changeActive('searchFlag')
},
changeData() {
}
}
}
</script>
<style lang="scss" scoped>
.screen {
display: flex;
align-items: center;
justify-content: space-between;
padding: 27upx 30upx;
background: #fff;
position: relative;
z-index: 10000;
}
.screen .screen-item {
position: relative;
display: flex;
align-items: center;
font-size: 30upx;
line-height: 30upx;
font-weight: 500;
color: #666;
}
.screen .active {
font-weight: 700;
color: #333;
}
.screen .screen-item image {
width: 16upx;
height: 12upx;
margin-left: 6upx;
}
.screen .screen-item .text {
width: 122upx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.screen .actives text {
font-weight: 700;
color: #333;
}
.pupop {
position: absolute;
left: 0;
top: 56upx;
.popup-box {
position: absolute;
width: calc(100vw - 64upx);
padding: 0 32upx;
left: 0;
top: -1000px;
z-index: 99;
background: #fff;
padding-bottom: 20px;
padding-top: 12upx;
.pupop-btn {
height: 40px;
display: flex;
align-items: center;
padding: 0 30upx;
justify-content: space-between;
}
}
}
.popup-box {}
.popupboxActive {
padding-bottom: 40upx;
}
.popup-box .btns {
display: flex;
align-items: center;
padding: 30upx 0;
justify-content: space-between;
}
.popup-box .btns .btn-item {
flex: 1;
text-align: center;
width: 40%;
height: 97upx;
line-height: 97upx;
border-radius: 97upx;
font-size: 30upx;
color: #333;
background: #F9F9F9;
font-weight: 400;
}
.popup-box .btns .btn-item:nth-child(2) {
color: #fff;
background: #05DB9B;
}
.popup-box .modelscroll {}
.popup-box .modelscroll .modelscroll-item .title {
font-weight: 700;
color: #323333;
padding-top: 27upx;
font-size: 32upx;
margin-bottom: 31upx;
}
.popup-box .modelscroll .modelscroll-item .itembox {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
.popup-box .modelscroll .modelscroll-item .itembox .item {
width: 319upx;
height: 80upx;
border-radius: 80upx;
text-align: center;
line-height: 80upx;
font-size: 30upx;
color: #333;
background: #F5F5F5;
margin-bottom: 22upx;
}
.popup-box .modelscroll .modelscroll-item .itembox .itemActive {
color: #05DB9B;
background: #E0FCF6;
}
.popup-box .sortbox {
padding: 12upx 0 41upx;
}
.popup-box .sortbox .sort-item {
font-size: 30upx;
line-height: 30upx;
color: #646666;
padding: 41upx 0;
font-weight: 400;
}
.popup-box .sortbox .active {
color: #323333;
font-weight: 500;
}
.popupboxbox {
// height: 640upx;
}
.popupboxbox .title {
color: #323333;
font-size: 32upx;
font-weight: 700;
margin-bottom: 30upx;
padding-top: 31upx;
display: flex;
align-items: center;
justify-content: space-between;
}
.popupboxbox .title_right {
display: flex;
align-items: center;
color: #05DB9B;
line-height: 30upx;
font-weight: 500;
}
.popupboxbox .title_right image {
margin-right: 7upx;
width: 23upx;
height: 30upx;
}
.popupboxbox .itembox {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.popupboxbox .itembox .item {
width: 220upx;
height: 70upx;
text-align: center;
line-height: 70upx;
border-radius: 70upx;
font-size: 30upx;
margin-bottom: 22upx;
color: #333;
background: #F5F5F5;
margin-right: 13upx;
}
.popupboxbox .itembox .active {
color: #05DB9B;
background: #E0FCF6;
}
.popupboxbox .itembox .item:nth-child(3),
.popupboxbox .itembox .item:nth-child(6),
.popupboxbox .itembox .item:nth-child(9),
.popupboxbox .itembox .item:nth-child(12),
.popupboxbox .itembox .item:nth-child(15),
.popupboxbox .itembox .item:nth-child(18),
.popupboxbox .itembox .item:nth-child(21),
.popupboxbox .itembox .item:nth-child(24),
.popupboxbox .itembox .item:nth-child(27),
.popupboxbox .itembox .item:nth-child(30) {
margin-right: 0;
}
.popupboxbox .itembox .item>view {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 10upx;
}
.pupop-model {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 90;
background: rgba(0, 0, 0, .5);
}
.pupop-models {
display: none !important;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

View File

@ -0,0 +1,16 @@
{
"id": "piaoyi-dropdownMenu",
"name": "piaoyi-dropdownMenu下拉菜单",
"displayName": "piaoyi-dropdownMenu下拉菜单",
"version": "1.0.2",
"description": "少有的dropdownMenu 下拉菜单,自定义数据,使用简单",
"keywords": [
"dropdownMenu",
"下拉菜单",
"自定义数据",
"动画"
],
"dcloudext": {
"type": "component-vue"
}
}

View File

@ -0,0 +1,129 @@
### dropdownMenu 下拉菜单
**使用方法:**
```
<dropdownMenu :modelList.sync="modelList" :disList="disList" :cityList="cityList" :searchList="searchList" :labelList.sync="labelList" @searchFinish="searchFinish"/>
```
```
import dropdownMenu from '@/uni_modules/piaoyi-dropdownMenu/components/piaoyi-dropdownMenu/piaoyi-dropdownMenu.vue'
export default {
components: {
dropdownMenu
},
data() {
return {
modelList: [{
title: '类型1',
children: [{
name: '类型1-1',
value: '类型1-1'
}, {
name: '类型1-2',
value: '类型1-2'
}, {
name: '类型1-3',
value: '类型1-3'
}, {
name: '类型1-4',
value: '类型1-4'
}]
}, {
title: '类型2',
children: [{
name: '类型2-1',
value: '类型2-1'
}, {
name: '类型2-2',
value: '类型2-2'
}, {
name: '类型2-3',
value: '类型2-3'
}, {
name: '类型2-4',
value: '类型2-4'
}]
}],
disList: [{
name: '附近',
id: 1
}, {
name: '3公里',
id: 3
}, {
name: '5公里',
id: 5
}, {
name: '10公里',
id: 10
}, {
name: '15公里',
id: 15
}, {
name: '20公里',
id: 20
}],
cityList: [{
id: "420102",
name: "江岸区"
},
{
id: "420103",
name: "江汉区"
}
],
searchList: [{
name: '智能排序',
value: 0
}, {
name: '距离优先',
value: 1
}],
labelList: [{
id: '标签1',
name: '标签1'
}, {
id: '标签2',
name: '标签2'
}, {
id: '标签3',
name: '标签3'
}, {
id: '标签3',
name: '标签3'
}, {
id: '标签4',
name: '标签4'
}],
}
},
methods: {
<!-- 筛选结果回调 -->
searchFinish(result) {
console.log(result)
}
}
}
```
#### 事件说明
| 事件名 | 返回值 | 描述 |
| :---------: | :----: | :------------: |
| @searchFinish | 例:{models: "类型1-1,类型1-4,类型2-1", distince: 3, searchIndex: 1, labels: "标签3,标签2,标签1,标签4"} | 筛选结果回调函数 |
#### Prop
| 参数名称 | 描述 |
| -------- | ------------------------------ |
| modelList | 标签选项数组注意prop处加上 .sync具体格式请看上面的示例 |
| disList | 距离选项数组,具体格式请看上面的示例 |
| cityList | 地区选项数组,具体格式请看上面的示例 |
| searchList | 排序规则数组,具体格式请看上面的示例 |
| labelList | 标签选项数组注意prop处加上 .sync具体格式请看上面的示例 |
| duration | 滑动动画时长 |
### 可接定制化组件开发
### 右侧有本人代表作小程序二维码,可以扫码体验
### 如使用过程中有问题或有一些好的建议欢迎加QQ群互相学习交流120594820

View File

@ -0,0 +1,25 @@
## 1.0.122023-04-18
更新
## 1.0.112023-04-10
【fix】兼容vue3 修复报错 Right-hand side of 'instanceof' is not an object
【opti】优化下方列表滚动感谢评论区大佬的意见 @touchmove.stop.prevent="moveHandle"
## 1.0.102023-01-30
feature: 增加name 属性,默认触发事件
## 1.0.92022-11-17
fix:感谢评论区大佬给的建议
## 1.0.82022-11-17
优化项目
## 1.0.72022-10-31
1、优化
## 1.0.62022-10-26
优化细节
## 1.0.52022-10-26
fix: 小程序需手动在外层进行关闭
## 1.0.42022-10-25
fix:小程序运行报错原因
## 1.0.32022-10-25
优化弹出
## 1.0.22022-10-22
修改数据
## 1.0.12022-10-22
初始化

View File

@ -0,0 +1,465 @@
<template>
<view class="zb-dropdown-item zb-dropdown-item--down" :style="[parent.style,{
zIndex:zIndex
}]"
v-show="showWrap">
<view class="zb-overlay"
@touchmove.stop.prevent="()=>{}"
:class="[{
'mask__visible':mask
}]" @click.stop="close">
</view>
<view class="zb-popup zb-popup--top zb-dropdown-item__content zb-popup-slide-top-leave-active"
:class="[{
'content--visible_Y':mask
}]">
<view style="min-height: 50px;">
<view
class="zb-cell zb-cell--clickable zb-dropdown-item__option"
v-for="item,index in options"
:key="index"
@click.stop="clickCell(item)"
>
<view class="zb-cell__title"
:class="[{
'active-cell__title':mValue===item.value
}]"
:style="[{
color:mValue===item.value?activeColor:''
}]"
>
<text>{{item.text}}</text>
</view>
<view class="zb-cell__value" v-if="mValue===item.value">
<text
class="iconfont icon-duihao active-icon"
:style="[{
color:showWrap?activeColor:''
}]"
></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name:'zb-dropdown-item',
options: {
virtualHost: true
},
props:{
value:{
type:[String,Number],
},
modelValue:{
type:[String,Number],
},
name:{
type:[String,Number],
required:true
},
options: {
type:Array,
default:()=>[]
}
},
inject: {
parent: {
default: null,
},
},
data(){
return{
zIndex:null,
activeColor:null,
mask: false,
showWrap: false,
title:null,
}
},
watch:{
// #ifndef VUE3
value:{
handler(newValue, oldValue) {
const item = this.options.find(
(option) => option.value === this.mValue
);
this.title = item.text||''
this.$emit('change', {...item});
},
},
// #endif
// #ifdef VUE3
modelValue:{
handler(newValue, oldValue) {
const item = this.options.find(
(option) => option.value === this.mValue
);
this.title = item.text||''
this.$emit('change', {...item});
},
},
// #endif
showWrap:{
handler (newLength, oldLength) {
// console.log('newLength=====',newLength)
},
immediate: true
},
options:{
handler(newValue, oldLength) {
if(newValue.length){
const match = this.options.filter(
(option) => option.value === this.mValue
);
let title = match.length ? match[0].text :'';
this.title = title
}else {
}
},
immediate: true,
deep:true
}
},
computed: {
mValue(){
return this.value!=null?this.value:this.modelValue
},
displayTitle:{
get(){
if (this.title) {
return this.title;
}
const match = this.options.filter(
(option) => option.value === this.mValue
);
let title = match.length ? match[0].text :'';
this.title = title
return title
},
set(val){
this.title = val
}
},
},
methods:{
/**
* 获取父元素实例
*/
getDropdown(name = 'zb-dropdown-menu') {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
},
clickCell(item){
this.changeStatus(this,'mask','showWrap',false)
if (item.value !== this.mValue) {
this.title = item.text
this.$emit('update:modelValue', item.value);
this.$emit('input', item.value);
}
},
changeStatus(item, param1, param2, status) {
item[param1] = status
this.watchTimer && clearTimeout(this.watchTimer)
this.watchTimer = setTimeout(() => {
item[param2] = status
}, status ? 20 : 200)
},
close(item,type){
let index = this.parent.childrenList.findIndex(item=>item.title===this.title)
this.parent.closeMask({},index)
},
moveHandle(){
return false
},
bindRelation() {
let obj = this.parent.childrenList.find(item=>{
let flag = item.name === this.name
return flag
})
if (!this.parent || obj) {
return;
}
// #ifndef H5
let obj1 = Object.assign(
this.$data,
this.$props
)
// #endif
// #ifdef H5
let obj1 = this
// #endif
const children = [...this.parent.childrenList, obj1];
this.parent.childrenList = children;
},
},
created(){
this.bindRelation()
let parentDropMenu = this.getDropdown()
this.activeColor= parentDropMenu.activeColor
this.zIndex= parentDropMenu.zIndex
},
beforeDestroy() {
if (this.parent) {
this.parent.childrenList = this.parent.childrenList.filter(
(item) => item.title !== this.title
);
}
},
}
</script>
<style lang="scss" scoped>
.zb-dropdown-item {
position: fixed;
right: 0;
left: 0;
z-index: 10;
overflow: hidden;
}
.zb-dropdown-menu {
-webkit-user-select: none;
user-select: none;
width: 100%;
}
.zb-popup {
&-slide-top-leave-active,
&-slide-left-leave-active,
&-slide-right-leave-active,
&-slide-bottom-leave-active {
transition-timing-function: ease-in;
}
}
.zb-popup-slide-top-enter,
.zb-popup-slide-top-leave-active {
transform: translate3d(0, -100%, 0);
}
.zb-popup-slide-right-enter,
.zb-popup-slide-right-leave-active {
transform: translate3d(100%, -50%, 0);
}
.zb-popup-slide-bottom-enter,
.zb-popup-slide-bottom-leave-active {
transform: translate3d(0, 100%, 0);
}
.zb-dropdown-menu__bar {
position: relative;
display: flex;
height: 48px;
background-color: #fff;
box-shadow: 0 2px 12px #6465661f;
}
.zb-dropdown-menu__item {
display: flex;
flex: 1;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
min-width: 0;
//cursor: pointer;
}
.zb-dropdown-menu__title {
position: relative;
box-sizing: border-box;
max-width: 100%;
padding: 0 8px;
color: #323233;
font-size: 15px;
line-height: 22px;
}
.zb-dropdown-menu__title::after {
position: absolute;
top: 50%;
right: -4px;
margin-top: -5px;
border: 3px solid;
border-color: transparent transparent #dcdee0 #dcdee0;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
opacity: 0.8;
content: '';
}
.zb-dropdown-menu__title--down::after {
margin-top: -1px;
-webkit-transform: rotate(135deg);
transform: rotate(135deg);
}
.zb-dropdown-menu__title--active::after {
border-color: transparent transparent currentColor currentColor;
}
.zb-dropdown-menu__bar--opened {
z-index: 11;
}
.zb-dropdown-menu__title--active {
color: #ee0a24;
}
.zb-dropdown-item--down {
bottom: 0;
}
.zb-overlay {
z-index: 2003;
position: absolute;
animation-duration: 0.2s;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
opacity: 0;
background-color: rgba(0, 0, 0, 0.7);
transition: opacity 0.3s;
}
.mask__visible {
opacity: 1;
}
.zb-popup {
position: fixed;
max-height: 100%;
overflow-y: auto;
background-color: #fff;
-webkit-transition: -webkit-transform 0.2s;
transition: -webkit-transform 0.2s;
transition: transform 0.2s;
transition: transform 0.2s, -webkit-transform 0.2s;
-webkit-overflow-scrolling: touch;
}
.zb-dropdown-item__content {
position: absolute;
max-height: 80%;
transition-duration: 0.2s;
z-index: 2006;
}
.zb-popup--top {
top: 0;
left: 0;
width: 100%;
}
.content--visible_Y {
transform: translateY(0px);
}
@keyframes zb-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes zb-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.zb-fade {
&-enter-active {
animation: 0.2s zb-fade-in both ease-out;
}
&-leave-active {
animation: 0.2s zb-fade-out both ease-in;
}
}
.zb-cell{
position: relative;
display: flex;
box-sizing: border-box;
width: 100%;
padding: 10px 16px;
overflow: hidden;
color: #323233;
font-size: 14px;
align-items: center;
line-height: 24px;
background-color: #fff;
}
.zb-cell::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
right: 16px;
bottom: 0;
left: 16px;
border-bottom: 1px solid #ebedf0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
.zb-cell--clickable{
//cursor: pointer;
}
@font-face {
font-family: "iconfont"; /* Project id 3711565 */
src:
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAJ0AAsAAAAABiwAAAIqAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACCcAooRgE2AiQDCAsGAAQgBYRnBzAbggXIrrApw71IoCYMFA7zwg8FpwSIh//2a/fNnxXFNKlm0SyaaJYoYSsJQqJ0UrcOmUPc/Z+2G0vd+VMRqtMdYw3bmbT7/5emDL2VRVgUDiFxWIyiVpkbW96eX2X9dryc+m6f/lTOAgrwA7GsfRdK96BF0/qBWi9QALuHtVTCXs+LXIXhVQe5E88I1G1Y1TvePb7uTJ8CqTtzA/Z4kDXHU5YEnYmUlmVaqwpldG8Wr0qk5xQv0efj11ZMSEoFu+3scSfufJ2zoOh0OxQfOvP10McSSiiwoiMTV93lE33RxPfVg4Ep2pkFP7rdwBe79oT419mNTTBJK8EPb6kACW6LNtwY9SBRvqOrm+TinWt8/sfn7NN08ZbovwqOnx96s+2/aiOD7zxyMyxKdbUg+AfGLUjMRoaUmwRpNCnvVq07ObrseL/fsfbAueqhamBEtGIiQ6FqisrcEkoatlBWtYO6ZTuHGwZofZFrmPNEEHp9IGl7R6HXN5W5H5QM+0NZr3/U3UTrvIa5iLYYA8EYwkfIIlWTa0kU9hKTtgy4rnCL3GQ0B7ZhlWt7WCNPsaG5SxwRAmJVwa7wGJalAs0qx0iMVEQvTJOa3mJEqupsYSggUAyEHoFMRKlRQJbi911CiVYpwCB1W2aNjIYHNoMFUHt6DQ3cySuNOwmHEAQQplTArjQLlUoK0M2zcigiDOmIorZgOiRCdWN9s/q0E1BnOymcaYXyfZulgep0AA==') format('woff2')
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-duihao:before {
content: "\eaf1";
}
.zb-cell__title, .zb-cell__value{
flex: 1;
}
.zb-cell__value{
display: flex;
align-items: center;
justify-content: flex-end;
}
.active-icon,.active-cell__title{
color: #ee0a24;
}
</style>

View File

@ -0,0 +1,410 @@
<template>
<view class="zb-dropdown-menu">
<view class="zb-dropdown-menu__bar zb-dropdown-menu__bar--opened"
:style="[barStyle]"
ref="bar">
<view class="zb-dropdown-menu__item"
@click.stop="toggleItem(index,item)"
:key="index"
v-for="item,index in childrenList">
<view class="zb-dropdown-menu__title" :class="[{
'zb-dropdown-menu__title--active':item.showWrap,
'zb-dropdown-menu__title--down':item.showWrap
}]"
:style="[{
color:item.showWrap?activeColor:'',
},titleColorStyle]"
>{{item.title}}</view>
</view>
</view>
<view>
<slot></slot>
</view>
</view>
</template>
<script>
export default {
name:'zb-dropdown-menu',
options: {
virtualHost: true
},
props:{
zIndex: [Number, String],
titleColorStyle:{
type: Object,
default: ()=>{}
},
activeColor:{
type:String,
default:'#ee0a24'
}
},
provide(){
return{
parent:this
}
},
computed:{
opened() {
return this.childrenList.some((item) => item.showWrap);
},
barStyle() {
if (this.opened&&this.isDef(this.zIndex)) {
return {
zIndex: 1 + this.zIndex,
};
}
},
},
// watch:{
// childrenList:{
// handler(val){
// console.log('=====val====ss=',val)
// },
// immediate:true
// }
// },
data() {
return {
childrenList:[],
direction: 'down',
offset: 0,
style: {
top: 0
},
showMask: true,
show: false,
mask: false,
mask1: false,
showWrapper: false,
showWrapper1: false,
watchTimer: null,
activeIndex: null,
}
},
mounted() {
this.updateOffset()
// #ifdef APP || H5
if(typeof window == 'object')window.addEventListener('click',this.close)
// #endif
},
beforeDestroy() {
this.watchTimer && clearTimeout(this.watchTimer)
// #ifdef APP || H5
if(typeof window == 'object')window.addEventListener('click',this.close)
// #endif
},
methods: {
isDef(val){
return val !== undefined && val !== null;
},
close(){
if(this.activeIndex==null)return
if(this.childrenList&&this.childrenList.length){
let obj = this.childrenList.find(item=>{
return item.showWrap
})
if(obj){
this.changeStatus(obj, 'mask', 'showWrap', false)
}
}
},
change(param1, param2, status) {
this[param1] = status
this.watchTimer && clearTimeout(this.watchTimer)
this.watchTimer = setTimeout(() => {
this[param2] = status
this.$emit('change', status)
}, status ? 5 : 200)
},
closeMask(ite,index) {
for (let i = 0; i < this.childrenList.length; i++) {
let item = this.childrenList[i]
if (i === index) {
if (!item.showWrap) {
this.changeStatus(item, 'showWrap', 'mask', true)
} else {
this.changeStatus(item, 'mask', 'showWrap', false)
}
} else {
this.$set(item,'mask',false)
this.$set(item,'showWrap',false)
}
}
},
changeStatus(item, param1, param2, status) {
// this.$set(item,param1,status)
item[param1] = status
this.watchTimer && clearTimeout(this.watchTimer)
this.watchTimer = setTimeout(() => {
// item[param2] = status
this.$set(item,param2,status)
}, status ? 20 : 200)
},
toggleItem(index) {
for (let i = 0; i < this.childrenList.length; i++) {
let item = this.childrenList[i]
if (i === index) {
if (!item.showWrap) {
this.changeStatus(item, 'showWrap', 'mask', true)
} else {
this.changeStatus(item, 'mask', 'showWrap', false)
}
} else {
item.mask = false
item.showWrap = false
}
}
// console.log('=======',this.childrenList)
this.activeIndex = index
this.updateOffset()
this.$emit('toggleItem')
},
updateOffset() {
let query = uni.createSelectorQuery().in(this);
query.select('.zb-dropdown-menu__bar').boundingClientRect(res=>{
if (this.direction === 'down') {
this.offset = res.height + uni.getSystemInfoSync().windowTop+res.top;
this.style.top = `${this.offset}px`;
} else {
this.offset = uni.getSystemInfoSync().screenHeight - res.top;
}
}).exec();
},
}
}
</script>
<style lang="scss" scoped>
.zb-dropdown-item {
position: fixed;
right: 0;
left: 0;
z-index: 10;
overflow: hidden;
}
.zb-dropdown-menu {
-webkit-user-select: none;
user-select: none;
width: 100%;
}
.zb-popup {
&-slide-top-leave-active,
&-slide-left-leave-active,
&-slide-right-leave-active,
&-slide-bottom-leave-active {
transition-timing-function: ease-in;
}
}
.zb-popup-slide-top-enter,
.zb-popup-slide-top-leave-active {
transform: translate3d(0, -100%, 0);
}
.zb-popup-slide-right-enter,
.zb-popup-slide-right-leave-active {
transform: translate3d(100%, -50%, 0);
}
.zb-popup-slide-bottom-enter,
.zb-popup-slide-bottom-leave-active {
transform: translate3d(0, 100%, 0);
}
.zb-dropdown-menu__bar {
position: relative;
display: flex;
height: 48px;
//background-color: #fff;
//box-shadow: 0 2px 12px #6465661f;
}
.zb-dropdown-menu__item {
display: flex;
flex: 1;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
min-width: 0;
//cursor: pointer;
}
.zb-dropdown-menu__title {
position: relative;
box-sizing: border-box;
max-width: 100%;
padding: 0 8px;
color: #323233;
font-size: 15px;
line-height: 22px;
}
.zb-dropdown-menu__title::after {
position: absolute;
top: 50%;
right: -4px;
margin-top: -5px;
border: 3px solid;
border-color: transparent transparent #dcdee0 #dcdee0;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
opacity: 0.8;
content: '';
}
.zb-dropdown-menu__title--down::after {
margin-top: -1px;
-webkit-transform: rotate(135deg);
transform: rotate(135deg);
}
.zb-dropdown-menu__title--active::after {
border-color: transparent transparent currentColor currentColor;
}
.zb-dropdown-menu__bar--opened {
z-index: 11;
}
.zb-dropdown-menu__title--active {
color: #ee0a24;
}
.zb-dropdown-item--down {
bottom: 0;
}
.zb-overlay {
z-index: 2003;
position: absolute;
animation-duration: 0.2s;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
opacity: 0;
background-color: rgba(0, 0, 0, 0.7);
transition: opacity 0.3s;
}
.mask__visible {
opacity: 1;
}
.zb-popup {
position: fixed;
max-height: 100%;
overflow-y: auto;
background-color: #fff;
-webkit-transition: -webkit-transform 0.2s;
transition: -webkit-transform 0.2s;
transition: transform 0.2s;
transition: transform 0.2s, -webkit-transform 0.2s;
-webkit-overflow-scrolling: touch;
}
.zb-dropdown-item__content {
position: absolute;
max-height: 80%;
transition-duration: 0.2s;
z-index: 2006;
}
.zb-popup--top {
top: 0;
left: 0;
width: 100%;
}
.content--visible_Y {
transform: translateY(0px);
}
@keyframes zb-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes zb-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.zb-fade {
&-enter-active {
animation: 0.2s zb-fade-in both ease-out;
}
&-leave-active {
animation: 0.2s zb-fade-out both ease-in;
}
}
.zb-cell{
position: relative;
display: flex;
box-sizing: border-box;
width: 100%;
padding: 10px 16px;
overflow: hidden;
color: #323233;
font-size: 14px;
align-items: center;
line-height: 24px;
background-color: #fff;
}
.zb-cell::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
right: 16px;
bottom: 0;
left: 16px;
border-bottom: 1px solid #ebedf0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
.zb-cell--clickable{
//cursor: pointer;
}
@font-face {
font-family: "iconfont"; /* Project id 3711565 */
src:
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAJ0AAsAAAAABiwAAAIqAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACCcAooRgE2AiQDCAsGAAQgBYRnBzAbggXIrrApw71IoCYMFA7zwg8FpwSIh//2a/fNnxXFNKlm0SyaaJYoYSsJQqJ0UrcOmUPc/Z+2G0vd+VMRqtMdYw3bmbT7/5emDL2VRVgUDiFxWIyiVpkbW96eX2X9dryc+m6f/lTOAgrwA7GsfRdK96BF0/qBWi9QALuHtVTCXs+LXIXhVQe5E88I1G1Y1TvePb7uTJ8CqTtzA/Z4kDXHU5YEnYmUlmVaqwpldG8Wr0qk5xQv0efj11ZMSEoFu+3scSfufJ2zoOh0OxQfOvP10McSSiiwoiMTV93lE33RxPfVg4Ep2pkFP7rdwBe79oT419mNTTBJK8EPb6kACW6LNtwY9SBRvqOrm+TinWt8/sfn7NN08ZbovwqOnx96s+2/aiOD7zxyMyxKdbUg+AfGLUjMRoaUmwRpNCnvVq07ObrseL/fsfbAueqhamBEtGIiQ6FqisrcEkoatlBWtYO6ZTuHGwZofZFrmPNEEHp9IGl7R6HXN5W5H5QM+0NZr3/U3UTrvIa5iLYYA8EYwkfIIlWTa0kU9hKTtgy4rnCL3GQ0B7ZhlWt7WCNPsaG5SxwRAmJVwa7wGJalAs0qx0iMVEQvTJOa3mJEqupsYSggUAyEHoFMRKlRQJbi911CiVYpwCB1W2aNjIYHNoMFUHt6DQ3cySuNOwmHEAQQplTArjQLlUoK0M2zcigiDOmIorZgOiRCdWN9s/q0E1BnOymcaYXyfZulgep0AA==') format('woff2')
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-duihao:before {
content: "\eaf1";
}
.zb-cell__title, .zb-cell__value{
flex: 1;
}
.zb-cell__value{
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>

View File

@ -0,0 +1,84 @@
{
"id": "zb-dropdown-menu",
"displayName": "zb-dropdown-menu 下拉筛选菜单 (多端兼容)",
"version": "1.0.12",
"description": "向下弹出的菜单列表。 ",
"keywords": [
"下拉菜单",
"DropdownMenu",
"Dropdown",
"筛选",
"下拉"
],
"repository": "",
"engines": {
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@ -0,0 +1,70 @@
# zb-dropdown-menu 向下弹出的菜单列表
### 微信=》 19550102670 拉进群
### 友情链接
#### 在线预览点击 —— [企业级、通用型中后台前端解决方案 ](http://182.61.5.190:8889/)
#### vue-admin-perfect —— [企业级、通用型中后台前端解决方案基于vue3.0+TS+Element-Plus 最新版,同时支持电脑,手机,平板)](https://github.com/zouzhibin/vue-admin-perfect)
### DropdownMenu Props 属性
| 参数 | 说明 | 类型 | 可选值 | 默认值 |是否必须|
| ------ | ------ | ------ | ------ | ------ |------ |
| active-color | 菜单标题和选项的选中态颜色 | string |-- | #ee0a24 |必须 |
| z-index | 选项数组 | 菜单栏 z-index 层级,一个页面存在多个下拉选项的时候可以通过这个设置 |number/string | -- | |
### DropdownItem Props 属性
| 参数 | 说明 | 类型 | 可选值 | 默认值 |是否必须|
| ------ | ------ | ------ | ------ | ------ |------ |
| value | 当前选中项对应的 value可以通过v-model双向绑定 | number ,string |-- | -- |必须 |
| options | 选项数组 | Option[] |-- | -- |必须 |
| name | 必须指定,判断唯一值,不能重复 | String|Number |-- | -- |必须 |
##3 DropdownItem Events
| 参数 | 说明 | 回调参数 |
| ------ | ------ | ------ | ------ | ------ |------ |
| change | 点击选项导致 value 变化时触发 | item |
### 注意 小程序没有window对象需要自己在外层进行手动关闭
```
this.$refs.dropdown.close()
```
### 使用示例
```
<zb-dropdown-menu style="width: 100%">
<zb-dropdown-item
name="first"
:options="option"
v-model="value1"
@change="change1"
></zb-dropdown-item>
<zb-dropdown-item
name="two"
:options="option2"
v-model="value2"
@change="change2"
></zb-dropdown-item>
</zb-dropdown-menu>
```
### 数据格式
```
option: [
{
text: '全部商品',
value: 0
},
{
text: '新款商品',
value: 1
},
{
text: '活动商品',
value: 2
},
],
```

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB