//serachInput组件
<template>
<view class="search-box" :style="'height:'+height+'rpx;'" :class="isBorder?'border':''">
<view class="input-box">
<text class="iconfont icon-sousuo" :style="'color:'+searchIconColor"></text>
<input :placeholder="placeholderText" class="sear-input" :style="'width:'+inputWidth+'rpx;'"
confirm-type="search" @confirm="toSearch" @input="onInput" placeholder-class="placeholder-style"
v-model="keyword"></input>
</view>
<text class="iconfont icon-sousuokuangqingchu" v-if="keyword" @tap="handleReset"></text>
</view>
</template>
<script>
export default {
name: "searchInput",
data() {
return {
keyword: ''
};
},
props: {
//placeholder文字
placeholderText: {
type: String,
default: '请输入'
},
//搜索框高度,单位rpx
height: {
type: Number,
default: 72
},
isBorder: {
type: Boolean,
default: false
},
//搜索图标颜色
searchIconColor: {
type: String,
default: '#bfbfbf'
},
//输入框宽度,单位rpx
inputWidth: {
type: Number,
default: 490
}
},
methods: {
toSearch() {
this.$emit('search', this.keyword)
},
handleReset() {
this.keyword = ''
this.$emit('reset', this.keyword)
},
onInput() {
this.$emit('input', this.keyword)
}
}
}
</script>
<style lang="scss" scoped>
.search-box {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 36rpx 0 32rpx;
border-radius: 110rpx;
background: #F5F5F5;
box-sizing: border-box;
.input-box {
display: flex;
align-items: center;
justify-content: space-between;
}
.sear-input {
margin-left: 20rpx;
font-size: 28rpx;
color: #262626;
}
.iconfont {
font-size: 40rpx;
color: #bfbfbf;
}
}
.border {
border: 2rpx solid var(--green-theme);
}
</style>
<style>
.placeholder-style {
color: var(--placeholder);
font-size: 28rpx;
}
</style>
<template>
<view class="content">
<view class="search-input">
<searchInput placeholder-text="输入城市名、拼音或首字母查询" @input="onInput" @reset="onInput"></searchInput>
</view>
<view class="all" v-if="searchValue.trim().length==0">
<view class="left">
<scroll-view :scroll-into-view="clickId" @scroll="scroll" :scroll-with-animation="false"
:scroll-y="true" style="height:calc(100vh - 96rpx)">
<view class="city-text" style="margin-top: 28rpx;">定位/最近访问</view>
<view class="vistor">
<view class="active" @click="getPosition(locationAuto)">
<text class="iconfont icon-shouhuodizhi location"></text>
{{locationAuto.areaName || '定位失败,点击重试'}}
</view>
<view class="last" @click="getDatas(location)" v-if="location.areaName">{{location.areaName}}
</view>
</view>
<view class="city-text">所有城市</view>
<view class="list_title" v-for="(items, index) in cityData" :key="index">
<view class="index" :id="'inToview'+index">{{items.name}}</view>
<view v-for="item in items.list" :key="item.areaId">
<text class="item" @click="getDatas(item)">{{item.areaName}}</text>
</view>
</view>
</scroll-view>
</view>
<view class="right">
<scroll-view :scroll-y="true" :scroll-with-animation="false" :scroll-into-view="clickToId">
<view class='index-box' @touchmove="handlerTouchMove" @touchend="handlerTouchEnd">
<view class="index" :data-id='index' v-for="(item,index) in cityData" :key="index">
<view class="alert" v-if="index===currentNum&&isTouchMove">
<text style="margin-right: 10rpx;">{{ item.name }}</text>
</view>
<view :class="['title',{active:index===currentNum}]" :id="'to'+index" @click="setId(index)">
{{item.name}}
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<scroll-view :scroll-y="true" :scroll-with-animation="false" style="height:calc(100vh - 96rpx)" v-else>
<view class="sel_item" @click="getDatas(item)" :key="item.areaId" v-for="(item, index) in selCityData">
{{item.areaName}}
</view>
<emptyTips v-if="selCityData.length===0">
<template v-slot:text>
未查到相关结果
</template>
</emptyTips>
</scroll-view>
</view>
</template>
<script>
var city = require('@/static/js/cityData.js')
var util = require("../../utils/util.js");
export default {
data() {
return {
cityData: '',
//查询结果
selCityData: [],
windowHeight: '0px',
clickId: '',
clickToId: '',
currentNum: 0,
topList: [],
isLeftClick: false,
searchValue: '',
//最近访问
location: {},
//定位
locationAuto: {},
isTouchMove: false,
arrTouchBarPosition: [],
//来源页面
from: ''
}
},
mounted() {
let that = this;
uni.getSystemInfo({
success: function(res) {
that.windowHeight = res.windowHeight * 2 - 72 + 'rpx';
}
});
this.location = uni.getStorageSync('location-visited')
this.locationAuto = uni.getStorageSync('location-auto')
that.cityData = city.cityData
setTimeout(function() {
that.getNodesInfo();
}, 100);
},
onLoad(options) {
this.from = options.from
},
methods: {
// 输入框
onInput(value) {
this.searchValue = value
console.log(this.searchValue);
var data = this.cityData
var sel = []
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].list.length; j++) {
if (data[i].list[j].areaName.indexOf(value) != -1 ||
data[i].list[j].enName.toUpperCase().indexOf(value.toUpperCase()) != -1) {
sel.push(data[i].list[j])
}
}
}
this.selCityData = sel
if (value.length == 0) {
this.selCityData.length = 0
this.cityData = city.cityData
}
},
// 字母选择联动
setId(index) {
this.clickId = "inToview" + index;
this.isLeftClick = true;
this.currentNum = index;
this.isTouchMove = true
setTimeout(() => {
this.isTouchMove = false
}, 300)
},
// 滚动监听
scroll(e) {
if (this.isLeftClick) {
this.isLeftClick = false;
return;
}
let scrollTop = e.target.scrollTop;
for (let i = 0; i < this.topList.length; i++) {
if (i === this.topList.length - 1 && scrollTop >= this.topList[i]) {
this.currentNum = i;
this.clickToId = 'to' + i
} else {
let height1 = this.topList[i];
let height2 = this.topList[i + 1];
if (scrollTop >= height1 && scrollTop < height2) {
this.currentNum = i;
this.clickToId = 'to' + i
}
}
}
},
//获取每一个分类高度
getNodesInfo() {
const query = uni.createSelectorQuery().in(this);
query.selectAll('.list_title').boundingClientRect().exec((res) => {
// console.log(res)
let nodes = res[0];
let rel = [];
nodes.map((item, index) => {
rel.push(item.top - 50);
})
this.topList = rel;
});
const that = this
wx.createSelectorQuery()
.selectAll('.index-box .index')
.boundingClientRect()
.exec(function(res) {
that.arrTouchBarPosition = res[0]; // 需要预先定义arrTouchBarPosition
});
},
getDatas(item) {
if (this.from !== "hospital") {
uni.setStorageSync('location-visited', item)
}
uni.$emit('getData', item)
uni.navigateBack({
delta: 1
})
},
handlerTouchMove(e) {
let clientY = e.touches[0].clientY;
for (let item of this.arrTouchBarPosition) {
if (clientY >= item.top && clientY <= item.bottom) {
if (item.dataset.id == this.currentNum) {
break;
}
this.clickId = "inToview" + item.dataset.id
this.isLeftClick = true;
this.currentNum = item.dataset.id;
this.isTouchMove = true
break;
}
}
},
handlerTouchEnd() {
this.isTouchMove = false
},
getPosition(location) {
if (location.areaName && location.areaName !== null) {
this.getDatas(location)
return
}
util.checkLocalPermission().then(res => {
console.log(res);
if (res === 1) {
this.locationAuto = uni.getStorageSync('location-auto')
} else if (res === 3) {
this.locationAuto = uni.getStorageSync('location-auto')
}
})
}
}
}
</script>
<style lang="scss">
.content {
position: fixed;
height: 100%;
width: 100%;
background-color: #ffffff;
.search-input {
margin: 12rpx 28rpx;
}
.city-text {
color: #8C8C8C;
font-size: 26rpx;
font-weight: 400;
margin: 0 0 20rpx 28rpx;
}
.vistor {
display: flex;
flex-wrap: wrap;
padding: 12rpx 28rpx 40rpx;
gap: 20rpx 48rpx;
.active {
border-radius: 40rpx;
border: 2rpx solid var(--green-theme);
background: rgba(54, 178, 154, 0.10);
justify-content: center;
align-items: center;
gap: 8rpx;
display: flex;
color: var(--green-theme);
font-size: 28rpx;
font-weight: 500;
height: 64rpx;
padding: 0 40rpx;
// min-width: 160rpx;
.location {
margin-right: 8rpx;
}
}
.last {
border-radius: 40rpx;
background: #F5F5F5;
display: flex;
justify-content: center;
align-items: center;
gap: 20rpx;
color: #262626;
font-size: 28rpx;
font-weight: 400;
height: 68rpx;
padding: 0 40rpx;
// min-width: 160rpx;
}
}
.list_title {
.index {
margin: 0 20rpx;
font-size: 28rpx;
font-weight: 400;
color: #595959;
background-color: #f5f5f5;
height: 48rpx;
display: flex;
align-items: center;
padding: 0 40rpx;
}
}
.all {
display: flex;
.left {
flex: 1;
.item {
width: 88%;
padding-left: 20rpx;
display: inline-block;
height: 88rpx;
line-height: 88rpx;
color: #1D2129;
font-size: 32rpx;
}
}
.right {
position: fixed;
right: 14rpx;
z-index: 99;
height: calc(100vh - 96rpx);
display: flex;
align-items: center;
.index-box {
width: 100rpx;
display: flex;
flex-direction: column;
align-items: flex-end;
.index {
width: 20rpx;
}
}
.title {
text-align: center;
padding: 8rpx 0;
color: #1d2129;
font-size: 20rpx;
}
.active {
color: var(--green-theme);
}
.alert {
position: fixed;
background-image: url('../../static/icon/home/water.png');
background-size: contain;
background-repeat: no-repeat;
right: 63rpx;
z-index: 99;
width: 120rpx;
height: 100rpx;
font-size: 48rpx;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
margin-top: -28rpx;
}
}
}
.sel_item {
height: 88rpx;
line-height: 88rpx;
padding-left: 20rpx;
}
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
}
</style>
//util.js方法
const checkLocalPermission = () => {
// 获取用户是否开启 授权获取当前的地理位置、速度的权限。
return new Promise(function(resolve, reject) {
uni.getSetting({
success(res) {
console.log(res)
// 如果没有授权
if (!res.authSetting['scope.userLocation']) {
// 则拉起授权窗口
uni.authorize({
scope: 'scope.userLocation',
success() {
//第一次点击允许后--就一直会进入成功授权的回调 就可以使用获取的方法了
http.getLocation().then(result => {
uni.setStorageSync('location-visited', result)
resolve(1)
})
},
fail(error) {
//点击了拒绝授权后--就一直会进入失败回调函数--此时就可以在这里重新拉起授权窗口
console.log('拒绝授权', error)
uni.showModal({
title: '温馨提示',
content: '未获取到您的位置,部分功能无法使用请前往设置定位功能。',
cancelText: '取消',
confirmText: '去设置',
confirmColor: "#36B29A",
cancelColor: "#262626",
success(res) {
if (res.confirm) {
uni.openSetting({
success(res) {
http.getLocation().then(
result => {
resolve(3)
})
}
})
} else if (res.cancel) {
if (!uni.getStorageSync(
'location-visited')) {
uni.setStorageSync('location-visited', {
areaId: "1101",
areaName: "北京市",
enName: "BeiJingShi",
longitude: 116.405285,
latitude: 39.904989,
areaCode: "010"
})
}
resolve(4)
}
}
});
}
})
} else {
// 有权限则直接获取
http.getLocation().then(result => {
resolve(2)
})
}
}
})
})
}
如果有疑问可私聊~