修改商户地图展示的上拉操作,以及图标切换

ymt-db-dev
游梦婷 1 year ago
parent 44e3047a9f
commit b43f9a8acb
  1. 41
      components/touchbox/readme.md
  2. 244
      components/touchbox/touchbox.vue
  3. 286
      pages/tabBar/category/category.vue

@ -0,0 +1,41 @@
# you-touchbox
对nvue做了些兼容处理,但还不成熟,nvue下transition失效的问题无法解决,请大佬指点(现阶段不建议在nvue中使用本插件,问题多多,nvue中遇到问题可以反馈,我尽力实现需求)
***所有像素值参数都不要传单位**
***一切计算以`可使用窗口高度`为基准**,即`uni.getSystemInfoSync().windowHeight`
***上拉框盒子高度默认为`可使用窗口高度`**,可以通过`customStyle`属性设置
**属性**
| 参数 | 说明 | 类型 | 默认值 |
| -------------- | :----------------------- | ---------------------------------- | ------------------------------------------------------------ |
| customStyle | 自定义样式 | String\|Object | -<br />border-radius若要兼容nvue请使用<br />border-top-left-radius,border-top-right-radius分开写 |
| initTop | 初始top值 | Number\|String\|<br />'min'\|'max' | 默认值为'min',<br />initTop为首次加载时,上拉框显示的高度,<br />所以一般设置为与maxTop或minTop一致,<br />参数可传百分比,像素值,字符串'min''max'<br />max为与maxTop一致,<br />min为与minTop一致<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的顶部位置往下偏移 |
| maxTop | 最高top值 | Numbe\|String | 默认为可使用窗口的顶部位置,<br />参数可传百分比和像素值,<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的顶部位置往下偏移 |
| minTop | 最低top值 | Number\|String | 默认为可用区域50%,<br />参数可传百分比和像素值,<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的底部位置往上的偏移 |
| auto | 是否开启自动复位 | Boolean | true,开启时松手会自动复位到最高最低状态 |
| limit | 是否开启滑动范围限制 | Boolean | true,开启时滑动范围不可超过maxTop和minTop |
| customSafeArea | 自定义navbar、tabbar高度 | Object | 如果使用了自定义navbar和tabbar,可以手动设置安全区域 |
| h5Top | customSafeArea的属性 | Number | -<br />H5的自定义navbar高度 |
| mpTop | customSafeArea的属性 | Number\|'menuBtn' | -<br />小程序的自定义navbar高度<br />特殊值字符串menuBtn的效果为微信小程序原生navbar的高度<br /> |
| bottom | customSafeArea的属性 | Number | -<br />自定义tabbar高度<br />因为H5和小程序的navbar高度不一致才需要分开配置,而tabbar一般是一致的,所以不区分 |
| zIndex | 上拉框z-index | Number\|String | 100 |
| disable | 禁用滑动 | Boolean | false |
**事件**
| 事件名 | 说明 | 参数 |
| -------------- | ------------------------------------------------------------ | -------------------------------- |
| get-end-detail | 获取滑动结束时top信息对象<br />maxTop:最大高度top<br />minTop:最小高度top<br />curTop:当前高度top | Function({maxTop,minTop,curTop}) |
**方法**
此方法要通过ref手动改调用
| 方法名 | 说明 | 参数 |
| --------- | ------------------------------------------------------------ | ----------------- |
| setBottom | 手动设置上拉框高度,参数值传百分比和像素值(不带单位),<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的底部位置往上的偏移 | Function(value) |

@ -0,0 +1,244 @@
<template>
<view class="you-touchbox" :class="{touchend:isTouchEnd}" @touchstart="onTouchStart"
@touchmove.stop.prevent="onTouchmove" @touchend="onTouchend"
:style="{top: top + distance + 'px',zIndex,height:maxTop*windowHeight+'px'}">
<view class="you-touchbox-content" :style="customStyle" @click.stop.prevent>
<view class="touch-line-box">
<view class="touch-line"></view>
</view>
<slot></slot>
</view>
</view>
</template>
<script>
export default {
name: "touchbox",
props: {
//
disable: {
type: Boolean,
default: false
},
zIndex: {
type: [Number, String],
default: 100
},
//
customStyle: [String, Object],
//
customSafeArea: {
type: Object,
default () {
return {
h5Top: null,
wxTop: null,
bottom: null
}
}
},
// top
maxTop: {
type: [Number, String],
default: 1
},
// top
minTop: {
type: [Number, String],
default: 0.5
},
// top
initTop: {
type: [Number, String],
default: 'min'
},
//
auto: {
type: Boolean,
default: true
},
//
limit: {
type: Boolean,
default: true
}
},
data() {
return {
windowHeight: null, // 使
windowTop: null,
touchStartY: null, // Y
top: null, // top
max: null, // maxTop
min: null, // minTop
distance: 0, //
isTouchEnd: false, // Flag
boundary: null, // 线
startTime: null, //
};
},
mounted() {
let {
windowHeight, // 使
windowTop // 使
} = uni.getSystemInfoSync()
this.windowHeight = windowHeight
this.windowTop = windowTop
let {
h5Top,
wxTop,
bottom
} = this.customSafeArea
// H5
// #ifndef MP
if (h5Top) {
this.windowHeight -= h5Top
windowTop += h5Top
}
// #endif
if (bottom) this.windowHeight -= bottom
// top
if (this.maxTop <= 1) this.max = this.windowHeight * (1 - +this.maxTop)
else this.max = +this.maxTop
// top
if (this.minTop <= 1) this.min = this.windowHeight * (1 - +this.minTop)
else this.min = this.windowHeight - (+this.minTop)
// top
if (['min', 'max'].includes(this.initTop)) this.top = this.initTop === 'min' ? this.min : this.max
else if (this.initTop <= 1) this.top = this.windowHeight * (1 - +this.initTop)
else this.top = +this.initTop
//
// #ifdef MP
if (wxTop) {
this.max += wxTop === 'menuBtn' ? uni.getMenuButtonBoundingClientRect().bottom + 10 : wxTop
this.top += wxTop
}
// #endif
// H5
// #ifndef MP
this.max += windowTop
this.min += windowTop
this.top += windowTop
// #endif
this.boundary = (this.max + this.min) / 2 // 线
},
methods: {
setBottom(value) {
if (this.auto) this.isTouchEnd = true
if (value <= 1) this.top = this.windowHeight * (1 - +value)
else this.top = (this.windowHeight - +value)
// #ifndef MP
this.top += this.windowTop
// #endif
},
onTouchStart(e) {
if (this.disable) return
this.isTouchEnd = false // Flag
// #ifndef APP-NVUE
this.top = e.currentTarget.offsetTop // toptop
// #endif
// #ifdef APP-NVUE
this.touchStartY = e.touches[0].screenY // Y
// #endif
// #ifndef APP-NVUE
this.touchStartY = e.touches[0].clientY // Y
// #endif
this.startTime = Date.now() //
},
onTouchmove(e) {
if (this.disable) return
// #ifdef APP-NVUE
let distance = e.touches[0].screenY - this.touchStartY //
// #endif
// #ifndef APP-NVUE
let distance = e.touches[0].clientY - this.touchStartY //
// #endif
if (this.limit) { //
let nowTop = this.top + distance // top
if (nowTop < this.max || nowTop > this.min) {
// toptoptoptop
// toptoptoptop
this.top = nowTop < this.max ? this.max : this.min
this.distance = 0 //
// #ifdef APP-NVUE
this.touchStartY = e.touches[0].screenY // Y
// #endif
// #ifndef APP-NVUE
this.touchStartY = e.touches[0].clientY // Y
// #endif
return
}
}
this.distance = distance //
},
onTouchend(e) {
if (this.disable) return
this.top = this.top + this.distance // top
if (this.auto) { //
this.isTouchEnd = true // Flag
let time = (Date.now() - this.startTime) / 1000 // -
let speed = Math.abs(this.distance) / time // /
if (speed > 800) { // 800px/
this.top = this.distance > 0 ? this.min : this.max // top
// return this.distance = 0 //
} else {
if (this.top < this.boundary) this.top = this.max // top线toptop
else this.top = this.min // top线toptop
}
}
// top
this.$emit('get-end-detail', {
minTop: this.min,
maxTop: this.max,
curTop: this.top
})
this.distance = 0 //
}
}
}
</script>
<style lang="scss" scoped>
.you-touchbox {
position: fixed;
left: 0;
right: 0;
bottom: 0;
}
.touchend {
transition-property: top;
transition-duration: .6s;
}
.you-touchbox-content {
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
/* #ifndef APP-NVUE */
height: 100%;
/* #endif */
background-color: #fff;
}
.touch-line-box {
padding: 5px 0 10px;
/* #ifdef APP-NVUE */
align-items: center;
/* #endif */
}
.touch-line {
/* #ifndef APP-NVUE */
margin: 0 auto;
/* #endif */
width: 45px;
height: 5px;
border-radius: 25px;
background: rgba(51, 51, 51, 0.2);
}
</style>

@ -1,123 +1,18 @@
<template>
<view class="map-container">
<!-- #ifdef H5 -->
<map id="myMap" style="width: 100%; height: 10vh;" :style="{height:mapheight}" :latitude="latitude"
:longitude="longitude" :markers="marker" :scale="scale" @markertap="markertap" @callouttap='callouttap'>
<cover-view class="cover-view-loca" :style='{bottom:coverbottom}' @click="onControltap">
<cover-image class="cover-image" src="../../../static/img/dispos.png"></cover-image>
</cover-view>
<!-- 一级分类 -->
<cover-view class="width100 cover-views mart15">
<scroll-view class="width90 cover-view-cont" scroll-x="true">
<cover-view class="cover-view-head font14" :class="[typeid == item.id ? 'onclick' : '']"
v-for="(item,index) in goodsFirstClassList" :key="index" @click="changeType(item)">{{item.name}}
</cover-view>
</scroll-view>
<!-- 二级分类 -->
<cover-view class="width100 mart15 backcorfff cover-viewchage alijus fotct"
style="border-radius: 22px;">
<!-- :class="[selectFirst == 1? 'onchange' : '']" -->
<cover-view class="font14 width30w fotct onchange text1"
@click="changeChilerType()">{{selectFirstName}}
<image mode="widthFix" class="margle" style="width: 8px;" :src="imagewxUrl+imgadres2"></image>
</cover-view>
<cover-view class="font14 width30w onchange" @click="changeChilerdistance()">{{distanceName}}
<image mode="widthFix" class="margle" style="width: 8px;" :src="imagewxUrl+imgadres2"></image>
</cover-view>
<cover-view class="font14 width30w">
<!-- 全部
<image mode="widthFix" class="margle" style="width: 8px;" :src="imagewxUrl+imgadres2"></image> -->
</cover-view>
</cover-view>
</cover-view>
<!-- // -->
<cover-view class="change-cont" v-if="selectChiler == 1 || selectChilerdistance == 1">
<cover-view class="width100 backcorfff"></cover-view>
</cover-view>
<!-- // -->
<cover-view class="change-optiac paddbotm20" v-if="selectChiler == 1">
<scroll-view scroll-y="true" class="width100 height260">
<cover-view class="width90 bor-botm1 paddtop15 paddbotm15 alijusstart"
v-for="(item,index) in goodsSendotClassList" :key="item.id" @click="changeFirstcont(item)">
<cover-view class="width90w font14"
:class="[selectFirst == item.id? 'onchange' : '']">{{item.name}}</cover-view>
<image class="icon20" src="../../../static/img/changed.png" mode="widthFix"
v-if="selectFirst == item.id"></image>
</cover-view>
</scroll-view>
</cover-view>
<!-- 二级距离 -->
<cover-view class="change-optiac paddbotm20" v-if="selectChilerdistance == 1">
<scroll-view scroll-y="true" class="width100 height260">
<cover-view class="width90 bor-botm1 paddtop15 paddbotm15 alijusstart"
v-for="(item,index) in distanceList" :key="index" @click="changeDistance(item)">
<cover-view class="width90w font14"
:class="[ distance== item.id? 'onchange' : '']">{{item.title}}</cover-view>
<image class="icon20" src="../../../static/img/changed.png" mode="widthFix"
v-if="distance == item.id"></image>
</cover-view>
</scroll-view>
</cover-view>
<view class="map-container" :style="{height:mapheight+'px'}">
<!-- 未打开筛选前 -->
<cover-view class="cover-view-foot" v-if="isSelected == 1">
<cover-view class="line-view" @click="updateSelected(2)"></cover-view>
<cover-view class="paddtop10 fcor666 font13 width100" @click="updateSelected(2)">点击发现更多商户</cover-view>
<cover-view class="input-box">
<input placeholder="搜索商品" v-model="searchName" placeholder-style="color:#c0c0c0;"
@click="updateSelected(2)" />
</cover-view>
</cover-view>
<!-- 打开筛选后 -->
<cover-view class="cover-view-foot-behind" v-if="isSelected == 2">
<cover-view class="line-view" @click="updateSelected(1)"></cover-view>
<cover-view class="paddtop10 fcor666 font13 width100" @click="updateSelected(1)">点击发现更多商户</cover-view>
<cover-view class="input-box">
<input placeholder="搜索商品" v-model="searchName" placeholder-style="color:#c0c0c0;"
@input="getMapStore()" />
</cover-view>
<scroll-view class="scoroll-cont width94 mart10" scroll-y="true">
<cover-view v-if="marker.length == 0 " class="mart30 fotct font14 fcor666 fotct width100">
<image mode="widthFix" style="width: 70vw;" :src="imagewxUrl+imgadres3"></image>
</cover-view>
<cover-view class="width96 height80 bor-botm1 alijusstart" v-for="(box,i) in marker" :key="i"
@click="seeloaction(box)">
<template v-if="box.id != 0">
<image mode="widthFix" :src="box.logo" class="recontleft flleft border-r"
@error="imgerror($event, i )" style="width: 50px;flex-shrink: 0;">
</image>
<cover-view class="fotlt paddleft5 flex-1">
<cover-view class="text2 width100 font16 fontwig6">
{{box.callout.content}}
</cover-view>
<cover-view class="height22">
<cover-view class="width70 flleft text1 font13 fcor999">
{{box.callout.address}}
</cover-view>
<cover-view class="width30 flright font13 fcor666 fotrt">
<image mode="aspectFit" :src="imagewxUrl+imgadres4" class="marglerig" style="width: 10px;height:10px"></image>
{{box.distance}}km
</cover-view>
</cover-view>
</cover-view>
</template>
</cover-view>
</scroll-view>
</cover-view>
<map id="myMap" style="width: 100%; height: 10vh;" :style="{height:mapheight+'px'}" :latitude="latitude"
:longitude="longitude" :markers="marker" :scale="scale" @markertap="markertap" @callouttap='callouttap'>
</map>
<!-- #endif -->
<!-- #ifdef MP -->
<map id="myMap" style="width: 100%; height: 10vh;" :style="{height:mapheight}" :latitude="latitude"
:longitude="longitude" :markers="marker" :scale="scale" @markertap="markertap" @callouttap='callouttap'>
<cover-view class="cover-view-loca" :style='{bottom:coverbottom}' @click="onControltap">
<cover-image class="cover-image" src="../../../static/img/dispos.png"></cover-image>
</cover-view>
<!-- :style='{bottom:coverbottom}' -->
<view class="cover-view-loca" @click="onControl">
<image class="cover-image" src="../../../static/img/dispos.png"></image>
</view>
<!-- 一级分类 -->
<view class="width100 cover-views mart15">
<scroll-view class="width90 cover-view-cont" scroll-x="true">
<view class="cover-view-head font14" :class="[typeid == item.id ? 'onclick' : '']"
<view class="width100 classify-one ">
<scroll-view class="width90 view-cont" scroll-x="true">
<view class="view-head font14" :class="[typeid == item.id ? 'onclick' : '']"
v-for="(item,index) in goodsFirstClassList" :key="index" @click="changeType(item)">{{item.name}}
</view>
</scroll-view>
@ -125,20 +20,21 @@
<view class="width100 mart15 backcorfff cover-viewchage alijus fotct" style="border-radius: 22px;">
<!-- :class="[selectFirst == 1? 'onchange' : '']" -->
<view class="font14 width30w fotct onchange text1" @click="changeChilerType()">{{selectFirstName}}
<image mode="aspectFit" class="margle" style="width: 8px;height:8px;" :src="imagewxUrl+imgadres2"></image>
<text :class="' margle ic-drec '+(selectChiler == 1?'icon-ymt to-blod-up':'icon-ymt to-blod-down')"></text>
<!-- <image mode="aspectFit" class="margle" style="width: 8px;height:8px;" :src="imagewxUrl+imgadres2"></image> -->
</view>
<view class="font14 width30w onchange" @click="changeChilerdistance()">{{distanceName}}
<image mode="aspectFit" class="margle" style="width: 8px;height:8px;" :src="imagewxUrl+imgadres2"></image>
<text :class="' margle ic-drec '+(selectChilerdistance == 1?'icon-ymt to-blod-up':'icon-ymt to-blod-down')"></text>
<!-- <image mode="aspectFit" class="margle" style="width: 8px;height:8px;" :src="imagewxUrl+imgadres2"></image> -->
</view>
<view class="font14 width30w">
<!-- 全部
<image mode="widthFix" class="margle" style="width: 8px;" :src="imagewxUrl+imgadres2"></image> -->
</view>
</view>
</view>
<!-- // -->
<view class="change-cont" v-if="selectChiler == 1 || selectChilerdistance == 1">
<view class="width100 backcorfff"></view>
</view>
<!-- // -->
<view class="change-optiac paddbotm20" v-if="selectChiler == 1">
@ -164,32 +60,29 @@
</view>
</scroll-view>
</view>
<!-- 未打开筛选前 -->
<view class="cover-view-foot" v-if="isSelected == 1">
<view class="line-view" @click="updateSelected(2)"></view>
<view class="paddtop10 fcor666 font13 width100" @click="updateSelected(2)">点击发现更多商户</view>
<view class="input-box">
<input placeholder="搜索商品" v-model="searchName" placeholder-style="color:#c0c0c0;"
@click="updateSelected(2)" />
</view>
<!-- // -->
<view class="change-cont" v-if="selectChiler == 1 || selectChilerdistance == 1">
<view class="width100 backcorfff"></view>
</view>
<!-- 打开筛选后 -->
<view class="cover-view-foot-behind" v-if="isSelected == 2">
<view class="line-view" @click="updateSelected(1)"></view>
<view class="paddtop10 fcor666 font13 width100" @click="updateSelected(1)">点击发现更多商户</view>
<touchbox ref="touchBox" :maxTop="maxTop" minTop="0.2" :auto="true" customStyle="border-radius:25px;"
:disable="isTouchDisable" @get-end-detail="getEndDetail">
<view class="cover-view-foot-behind" >
<view class="paddtop10 fcor666 font13 width100">点击发现更多商户</view>
<view class="input-box">
<input placeholder="搜索商品" v-model="searchName" placeholder-style="color:#c0c0c0;"
@input="getMapStore()" />
</view>
<scroll-view class="scoroll-cont width94 mart10" scroll-y="true">
<scroll-view class="scoroll-cont width94 mart10" :scroll-y="isScrollY">
<view v-if="marker.length == 0 " class="mart30 fotct font14 fcor666 fotct width100">
<image mode="widthFix" style="width: 70vw;" :src="imagewxUrl+imgadres3"></image>
</view>
<view class="width96 height80 bor-botm1 alijusstart" v-for="(box,i) in marker" :key="i"
<view class="" v-for="(box,i) in marker" :key="i"
@click="seeloaction(box)">
<template v-if="box.id != 0">
<view v-if="box.id != 0" class="width96 height80 bor-botm1 alijusstart" >
<image mode="widthFix" :src="box.logo" class="recontleft flleft border-r"
@error="imgerror($event, i )" style="width: 50px;flex-shrink: 0;">
</image>
@ -207,12 +100,14 @@
</view>
</view>
</view>
</template>
</view>
</view>
</scroll-view>
</view>
</map>
<!-- #endif -->
</touchbox>
</view>
</template>
<script>
@ -220,10 +115,12 @@
getIndustry,
getMapStore
} from '../../../Utils/Api.js';
import touchbox from '@/components/touchbox/touchbox.vue'
let app = getApp();
export default {
data() {
return {
mapheight:null,
latitude: '', //
longitude: '', //
mapContext: null,
@ -284,35 +181,44 @@
distance: '3',
distanceName: '3km',
searchName: '', //
typeplat: 1 //
typeplat: 1, //
maxTop: 0.7,
isTouchDisable: false, //
isScrollY:false,
}
},
onLoad() {
this.onControltap();
},
onReady() {
this.mapContext = uni.createMapContext('myMap');
console.log(this.mapContext)
},
onShow() {
// this.latitude = app.globalData.latitude;
// this.longitude = app.globalData.longitude;
/* this.onControltap(); */
},
computed: {
mapheight() {
let data = ''
if (this.bottomData) {
if (this.upTop) {
data = '50px'
} else {
data = '200px'
}
} else {
data = '100vh'
}
return data
components:{
touchbox,
},
onReady() {
this.mapContext = uni.createMapContext('myMap');
this.mapheight = uni.getSystemInfoSync().windowHeight - uni.getSystemInfoSync().windowTop - uni
.getSystemInfoSync().windowBottom
// console.log(uni.getSystemInfoSync())
},
computed: {
// mapheight() {
// let data = ''
// if (this.bottomData) {
// if (this.upTop) {
// data = '50px'
// } else {
// data = '200px'
// }
// } else {
// data = '100vh'
// }
// return data
// },
coverbottom() {
let data = ''
if (this.bottomData) {
@ -325,6 +231,15 @@
},
methods: {
getEndDetail({
minTop,
maxTop,
curTop
}) {
// console.log(minTop, maxTop, curTop);
if (curTop == maxTop) this.isScrollY = true
else this.isScrollY = false
},
//
getIndustry() {
getIndustry().then(res => {
@ -553,6 +468,23 @@
})
},
//
onControl(){
if(this.mapContext&&this.latitude&&this.longitude){
let that = this;
this.mapContext.moveToLocation({
latitude: that.latitude,
longitude: that.longitude,
success(res){
// console.log(res,"")
}
})
}else{
// console.log(this.mapContext,this.latitude,this.longitude)
this.onControltap();
}
},
onControltap() {
uni.showLoading({
title: '定位中'
@ -576,7 +508,7 @@
})
}
console.log(this.longitude, this.latitude, "this.longitude,this.latitude")
// console.log(this.longitude, this.latitude, "this.longitude,this.latitude")
this.getIndustry();
},
fail() {
@ -668,27 +600,35 @@
}
}
</script>
<style lang='less' scoped>
<style lang='scss' scoped>
image{will-change: transform}
.ic-drec{
font-size: 24rpx !important;
width: 10px;
height: 10px;
line-height: 10px;
color: #333;
}
.map-container {
position: relative;
overflow: hidden;
.cover-views {
.classify-one{
position: absolute;
z-index: 99999;
top:15px;
}
.cover-view-cont {
.view-cont {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
white-space: nowrap;
}
.cover-view-head {
.view-head {
height: 35px;
line-height: 35px;
background-color: #fff;
@ -727,7 +667,7 @@
background-size: 60px 60px;
background-position: center center;
position: absolute;
bottom: 100px;
bottom: 20%;
right: 16px;
}
@ -749,7 +689,7 @@
.change-cont {
position: absolute;
z-index: 99999999;
z-index:999;
top: 100px;
background-color: #333;
width: 100%;
@ -759,8 +699,8 @@
.change-optiac {
position: absolute;
z-index: 99999999;
top: 100px;
z-index: 9999;
top: 99px;
width: 100%;
background-color: #fff;
height: 260px;
@ -768,18 +708,14 @@
.cover-view-foot-behind {
text-align: center;
height: calc(100% - 110px);
height: calc(100% - 20px);
background-color: #fff;
position: absolute;
z-index: 999999;
bottom: 0px;
width: 100%;
border-radius: 18px 18px 0 0;
}
}
.scoroll-cont {
height: calc(100% - 80px);
height: calc(100% - 73px);
}
.line-view {
@ -796,7 +732,7 @@
margin-left: 5%;
margin-top: 5px;
text-align: left;
height: 70rpx;
height: 35px;
background-color: #f0f0f0;
border-radius: 22px;
position: relative;

Loading…
Cancel
Save