调整ui
This commit is contained in:
105
components/DatePicker/DateFilter.vue
Normal file
105
components/DatePicker/DateFilter.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<view class="date-filter">
|
||||
|
||||
<!-- 开始日期 -->
|
||||
<view class="filter-item" @click="$refs.startPicker.open(startDate)">
|
||||
<text class="label">开始日期</text>
|
||||
<text class="value">{{ startDate || '请选择' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="divider"></view>
|
||||
|
||||
<!-- 结束日期 -->
|
||||
<view class="filter-item" @click="$refs.endPicker.open(endDate)">
|
||||
<text class="label">结束日期</text>
|
||||
<text class="value">{{ endDate || '请选择' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 开始日期选择器 -->
|
||||
<DatePicker
|
||||
v-model="startDate"
|
||||
ref="startPicker"
|
||||
@confirm="selectStart"
|
||||
/>
|
||||
|
||||
<!-- 结束日期选择器 -->
|
||||
<DatePicker
|
||||
v-model="endDate"
|
||||
ref="endPicker"
|
||||
@confirm="selectEnd"
|
||||
/>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DatePicker from './DatePicker.vue';
|
||||
|
||||
export default {
|
||||
name: 'DateFilter',
|
||||
components: { DatePicker },
|
||||
|
||||
props: {
|
||||
start: { type: String, default: '' },
|
||||
end: { type: String, default: '' }
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
startDate: this.start,
|
||||
endDate: this.end
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** 选择开始日期 */
|
||||
selectStart(e) {
|
||||
this.startDate = e;
|
||||
this.$emit('update:start', e);
|
||||
this.$emit('change', { start: this.startDate, end: this.endDate });
|
||||
},
|
||||
|
||||
/** 选择结束日期 */
|
||||
selectEnd(e) {
|
||||
this.endDate = e;
|
||||
this.$emit('update:end', e);
|
||||
this.$emit('change', { start: this.startDate, end: this.endDate });
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.date-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
padding-left: 30rpx;
|
||||
color: #333;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 2rpx;
|
||||
height: 40rpx;
|
||||
background: #e5e5e5;
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
</style>
|
||||
232
components/DatePicker/DatePicker.vue
Normal file
232
components/DatePicker/DatePicker.vue
Normal file
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<view v-if="visible" class="picker-overlay" @click.stop="close">
|
||||
<view class="picker-container" @click.stop>
|
||||
<view class="picker-header">
|
||||
<text class="cancel" @click="close">取消</text>
|
||||
<text class="title">请选择日期</text>
|
||||
<text class="confirm" @click="confirm">确定</text>
|
||||
</view>
|
||||
|
||||
<view class="picker-columns">
|
||||
<!-- 年 -->
|
||||
<scroll-view
|
||||
class="column"
|
||||
scroll-y
|
||||
:scroll-top="scrollPos[0]"
|
||||
@scroll="onScroll(0,$event)"
|
||||
>
|
||||
<view
|
||||
v-for="(y,i) in years"
|
||||
:key="i"
|
||||
class="item"
|
||||
:class="{active:selected[0]===i}"
|
||||
@click="select(0,i)"
|
||||
>
|
||||
{{y}}年
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 月 -->
|
||||
<scroll-view
|
||||
class="column"
|
||||
scroll-y
|
||||
:scroll-top="scrollPos[1]"
|
||||
@scroll="onScroll(1,$event)"
|
||||
>
|
||||
<view
|
||||
v-for="(m,i) in months"
|
||||
:key="i"
|
||||
class="item"
|
||||
:class="{active:selected[1]===i}"
|
||||
@click="select(1,i)"
|
||||
>
|
||||
{{m}}月
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 日 -->
|
||||
<scroll-view
|
||||
class="column"
|
||||
scroll-y
|
||||
:scroll-top="scrollPos[2]"
|
||||
@scroll="onScroll(2,$event)"
|
||||
>
|
||||
<view
|
||||
v-for="(d,i) in days"
|
||||
:key="i"
|
||||
class="item"
|
||||
:class="{active:selected[2]===i}"
|
||||
@click="select(2,i)"
|
||||
>
|
||||
{{d}}日
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: { value: String },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
years: [],
|
||||
months: Array.from({ length: 12 }, (_, i) => i + 1),
|
||||
days: [],
|
||||
selected: [0, 0, 0],
|
||||
scrollPos: [0, 0, 0], // 小程序 scroll-view 只能用 scroll-top 来滚动
|
||||
itemH: 40,
|
||||
scrollTimer: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open(val) {
|
||||
this.visible = true;
|
||||
const currentYear = new Date().getFullYear();
|
||||
this.years = Array.from({ length: currentYear - 1980 + 1 }, (_, i) => 1980 + i);
|
||||
const date = val ? new Date(val) : new Date();
|
||||
const y = date.getFullYear();
|
||||
const m = date.getMonth() + 1;
|
||||
const d = date.getDate();
|
||||
|
||||
this.selected = [
|
||||
this.years.indexOf(y),
|
||||
m - 1,
|
||||
0 // 先占位,待 days 生成后再修正
|
||||
];
|
||||
|
||||
this.updateDays(() => {
|
||||
this.selected[2] = Math.min(d - 1, this.days.length - 1);
|
||||
this.updateScrollPos();
|
||||
});
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
},
|
||||
|
||||
confirm() {
|
||||
const y = this.years[this.selected[0]];
|
||||
const m = this.selected[1] + 1;
|
||||
const d = this.selected[2] + 1;
|
||||
const dateStr = `${y}-${String(m).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
|
||||
|
||||
this.$emit("input", dateStr);
|
||||
this.$emit("confirm", dateStr);
|
||||
this.close();
|
||||
},
|
||||
|
||||
// 点击选择项
|
||||
select(col, idx) {
|
||||
this.selected.splice(col, 1, idx);
|
||||
|
||||
if (col === 0 || col === 1) {
|
||||
this.updateDays(() => {
|
||||
if (this.selected[2] >= this.days.length) {
|
||||
this.selected[2] = this.days.length - 1;
|
||||
}
|
||||
this.updateScrollPos();
|
||||
});
|
||||
} else {
|
||||
this.updateScrollPos();
|
||||
}
|
||||
},
|
||||
|
||||
// 滚动事件处理(兼容小程序)
|
||||
onScroll(col, e) {
|
||||
if (!e.detail) return;
|
||||
const top = e.detail.scrollTop;
|
||||
|
||||
if (this.scrollTimer) clearTimeout(this.scrollTimer);
|
||||
|
||||
this.scrollTimer = setTimeout(() => {
|
||||
const idx = Math.round(top / this.itemH);
|
||||
|
||||
this.selected.splice(col, 1, idx);
|
||||
|
||||
if (col === 0 || col === 1) {
|
||||
this.updateDays(() => {
|
||||
if (this.selected[2] >= this.days.length) {
|
||||
this.selected[2] = this.days.length - 1;
|
||||
}
|
||||
this.updateScrollPos();
|
||||
});
|
||||
} else {
|
||||
this.updateScrollPos();
|
||||
}
|
||||
}, 120);
|
||||
},
|
||||
|
||||
// 更新 scroll-top,使选中项居中
|
||||
updateScrollPos() {
|
||||
this.scrollPos = [
|
||||
this.selected[0] * this.itemH,
|
||||
this.selected[1] * this.itemH,
|
||||
this.selected[2] * this.itemH,
|
||||
];
|
||||
},
|
||||
|
||||
updateDays(callback) {
|
||||
const year = this.years[this.selected[0]];
|
||||
const month = this.selected[1] + 1;
|
||||
const max = new Date(year, month, 0).getDate();
|
||||
|
||||
this.days = Array.from({ length: max }, (_, i) => i + 1);
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (callback) callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.picker-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.4);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
z-index: 999;
|
||||
}
|
||||
.picker-container {
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
border-radius: 16px 16px 0 0;
|
||||
}
|
||||
.picker-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.cancel { color: #999; }
|
||||
.confirm { color:#007aff; }
|
||||
.title { font-weight:bold; }
|
||||
|
||||
.picker-columns {
|
||||
display: flex;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.column {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.item {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
color:#666;
|
||||
}
|
||||
|
||||
.item.active {
|
||||
color:#007aff;
|
||||
font-weight:bold;
|
||||
font-size:18px;
|
||||
}
|
||||
</style>
|
||||
295
components/gallery/AssetGallery.vue
Normal file
295
components/gallery/AssetGallery.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<view class="house-gallery">
|
||||
<!-- 图片轮播 -->
|
||||
<u-swiper
|
||||
:list="swiperList"
|
||||
:current="current"
|
||||
height="1200rpx"
|
||||
>
|
||||
<template #default="{ item, index }">
|
||||
<view class="slide-item">
|
||||
<image :src="item.url" mode="aspectFill" class="slide-img" />
|
||||
|
||||
<!-- VR 按钮 -->
|
||||
<view v-if="item.type === 'vr'" class="vr-btn" @click.stop="openVR">
|
||||
VR
|
||||
</view>
|
||||
|
||||
<!-- 视频按钮 -->
|
||||
<view v-if="item.type === 'video'" class="video-btn" @click.stop="playVideo">
|
||||
▶
|
||||
</view>
|
||||
|
||||
<!-- 图片索引 -->
|
||||
<view class="slide-index">{{ index + 1 }}/{{ swiperList.length }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-swiper>
|
||||
|
||||
<!-- 广告遮罩栏 -->
|
||||
<view v-if="adVisible && adImage" class="ad-mask" @click="onAdClick">
|
||||
<image :src="adImage" mode="aspectFill" class="ad-img" />
|
||||
<view class="ad-close" @click.stop="adVisible = false">×</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部 Tab -->
|
||||
<view class="gallery-tab">
|
||||
<view
|
||||
class="gallery-tab-item"
|
||||
v-for="(item, i) in tabs"
|
||||
:key="i"
|
||||
:id="'tab-' + i"
|
||||
:class="{ active: activeTab === i }"
|
||||
@click="onTabClick(i)"
|
||||
>
|
||||
{{ item.label }}
|
||||
<text v-if="item.count">({{ item.count }})</text>
|
||||
</view>
|
||||
|
||||
<!-- 滑块动画 -->
|
||||
<view
|
||||
class="tab-line"
|
||||
:style="{ width: lineStyle.width + 'px', left: lineStyle.left + 'px' }"
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<!-- 视频弹窗 -->
|
||||
<u-popup v-model="videoVisible" mode="center" border-radius="20">
|
||||
<video
|
||||
:src="videoUrl"
|
||||
autoplay
|
||||
controls
|
||||
style="width: 600rpx; height: 400rpx;"
|
||||
></video>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "AssetGallery",
|
||||
props: {
|
||||
vrImage: String,
|
||||
videoCover: String,
|
||||
videoUrl: String,
|
||||
insideImages: Array,
|
||||
planImages: Array,
|
||||
adImage: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
current: 0,
|
||||
videoVisible: false,
|
||||
adVisible: true,
|
||||
tabs: [],
|
||||
indexMap: [],
|
||||
lineStyle: { width: 0, left: 0 }
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => this.updateTabLine(), 50);
|
||||
});
|
||||
},
|
||||
|
||||
watch: {
|
||||
activeTab() {
|
||||
this.$nextTick(() => this.updateTabLine());
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
swiperList() {
|
||||
let list = [];
|
||||
this.tabs = [];
|
||||
this.indexMap = [];
|
||||
let idx = 0;
|
||||
|
||||
if (this.vrImage) {
|
||||
this.tabs.push({ key: "vr", label: "VR", count: 1 });
|
||||
this.indexMap.push(idx);
|
||||
list.push({ type: "vr", url: this.vrImage });
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (this.videoCover) {
|
||||
this.tabs.push({ key: "video", label: "视频", count: 1 });
|
||||
this.indexMap.push(idx);
|
||||
list.push({ type: "video", url: this.videoCover });
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (this.insideImages?.length > 0) {
|
||||
this.tabs.push({ key: "inside", label: "内部图", count: this.insideImages.length });
|
||||
this.indexMap.push(idx);
|
||||
list.push(...this.insideImages.map((img) => ({ type: "inside", img })));
|
||||
idx += this.insideImages.length;
|
||||
}
|
||||
|
||||
if (this.planImages?.length > 0) {
|
||||
this.tabs.push({ key: "plan", label: "平面图", count: this.planImages.length });
|
||||
this.indexMap.push(idx);
|
||||
list.push(...this.planImages.map((url) => ({ type: "plan", url })));
|
||||
idx += this.planImages.length;
|
||||
}
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
activeTab() {
|
||||
for (let i = 0; i < this.indexMap.length; i++) {
|
||||
const start = this.indexMap[i];
|
||||
const end = this.indexMap[i + 1] ?? 99999;
|
||||
if (this.current >= start && this.current < end) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onAdClick() {
|
||||
this.$emit("ad-click");
|
||||
},
|
||||
|
||||
onSwiperChange(e) {
|
||||
this.current = e.detail.current;
|
||||
},
|
||||
|
||||
onTabClick(i) {
|
||||
this.current = this.indexMap[i];
|
||||
},
|
||||
|
||||
openVR() {
|
||||
this.$emit("open-vr");
|
||||
},
|
||||
|
||||
playVideo() {
|
||||
this.videoVisible = true;
|
||||
},
|
||||
|
||||
updateTabLine() {
|
||||
const index = this.activeTab;
|
||||
if (this.tabs.length === 0) return;
|
||||
|
||||
const id = `#tab-${index}`;
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(id)
|
||||
.boundingClientRect((rect) => {
|
||||
if (!rect) return;
|
||||
this.lineStyle = { width: rect.width, left: rect.left };
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.house-gallery {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 轮播 */
|
||||
.slide-item {
|
||||
width: 100%;
|
||||
height: 1200rpx;
|
||||
position: relative;
|
||||
}
|
||||
.slide-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
.vr-btn,
|
||||
.video-btn {
|
||||
position: absolute;
|
||||
bottom: 40rpx;
|
||||
right: 40rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
.video-btn {
|
||||
font-size: 50rpx;
|
||||
}
|
||||
.slide-index {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
right: 20rpx;
|
||||
padding: 4rpx 8rpx;
|
||||
background: rgba(0,0,0,0.5);
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
/* 广告遮罩 */
|
||||
.ad-mask {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
background: rgba(0,0,0,0.35);
|
||||
padding: 0 20rpx;
|
||||
z-index: 9;
|
||||
}
|
||||
.ad-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
.ad-close {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 20rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(0,0,0,0.55);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 40rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
/* Tab bar */
|
||||
.gallery-tab {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
background: rgba(255,255,255,0.9);
|
||||
border-top: 1rpx solid #eee;
|
||||
height: 90rpx;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
z-index: 10;
|
||||
}
|
||||
.gallery-tab-item {
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
.gallery-tab-item.active {
|
||||
color: #2979ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.tab-line {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 4rpx;
|
||||
background: #2979ff;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
</style>
|
||||
@@ -6,8 +6,8 @@
|
||||
<view class="nav-content">
|
||||
<!-- 左侧返回 -->
|
||||
<view class="nav-left">
|
||||
<u-icon name="arrow-left" size="44" color="#333" @click="onBack"></u-icon>
|
||||
<u-icon name="home" size="44" color="#333" @click="goHome"></u-icon>
|
||||
<u-icon name="arrow-left" size="44" color="#333" @click="onBack" v-if="showBack"></u-icon>
|
||||
<u-icon name="home" size="44" color="#333" @click="goHome" v-if="showHome"></u-icon>
|
||||
</view>
|
||||
|
||||
<!-- 中间标题 -->
|
||||
@@ -51,6 +51,14 @@ export default {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
showBack: {
|
||||
type: Boolean,
|
||||
default: true // 左侧返回按钮默认显示
|
||||
},
|
||||
showHome: {
|
||||
type: Boolean,
|
||||
default: true // 回首页按钮默认显示
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
139
components/navbar/indexNavbar.vue
Normal file
139
components/navbar/indexNavbar.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<view
|
||||
class="index-navbar"
|
||||
:style="{ height: navHeight + 'px' }"
|
||||
>
|
||||
<view class="nav-content" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<!-- 左侧返回 -->
|
||||
<view class="nav-left">
|
||||
<u-icon name="arrow-left" size="44" color="#333" @click="onBack" v-if="showBack"></u-icon>
|
||||
<u-icon name="home" size="44" color="#333" @click="goHome" v-if="showHome"></u-icon>
|
||||
</view>
|
||||
|
||||
<!-- 中间标题 -->
|
||||
<view class="nav-title">{{ title }}</view>
|
||||
|
||||
<!-- 右侧按钮(位于胶囊左侧) -->
|
||||
<view
|
||||
class="nav-right"
|
||||
:style="{ marginRight: menuRightGap + 'px' }"
|
||||
>
|
||||
<view
|
||||
v-for="(btn, index) in rightButtons"
|
||||
:key="index"
|
||||
class="nav-btn"
|
||||
@click="btn.onClick && btn.onClick()"
|
||||
>
|
||||
<u-icon
|
||||
:name="btn.icon"
|
||||
:color="btn.color || '#333'"
|
||||
:size="btn.size || 40"
|
||||
></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'indexNavbar',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
rightButtons: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
back: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
showBack: {
|
||||
type: Boolean,
|
||||
default: false // 左侧返回按钮默认显示
|
||||
},
|
||||
showHome: {
|
||||
type: Boolean,
|
||||
default: false // 回首页按钮默认显示
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusBarHeight: 0,
|
||||
navHeight: 0,
|
||||
menuRightGap: 0, // 胶囊按钮与右侧边距
|
||||
navContentHeight:0
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const menuButton = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null;
|
||||
|
||||
if (menuButton) {
|
||||
this.statusBarHeight = systemInfo.statusBarHeight;
|
||||
this.navContentHeight = menuButton.height; // 只算胶囊按钮区域高度
|
||||
this.navHeight = this.statusBarHeight + this.navContentHeight; // 总高度
|
||||
this.menuRightGap = systemInfo.screenWidth - menuButton.right + 8;
|
||||
} else {
|
||||
this.statusBarHeight = systemInfo.statusBarHeight;
|
||||
this.navContentHeight = 44; // 默认内容高度
|
||||
this.navHeight = this.statusBarHeight + this.navContentHeight;
|
||||
this.menuRightGap = 16;
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
onBack() {
|
||||
if (this.back) {
|
||||
this.back();
|
||||
} else {
|
||||
uni.navigateBack();
|
||||
}
|
||||
},
|
||||
goHome(){
|
||||
uni.reLaunch({
|
||||
url:'../index/index'
|
||||
})
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.index-navbar {
|
||||
background-color: none;
|
||||
|
||||
.nav-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
width: 50rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.nav-btn {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
99
components/searchBar/SearchBar.vue
Normal file
99
components/searchBar/SearchBar.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<view class="search-bar" :style="{ backgroundColor: backgroundColor,border:border}">
|
||||
<view v-if="showChoseCity" class="location-chose" @click="$emit('chooseCity')" :style="{fontSize:fontSize,color:fontColor}">
|
||||
{{ city || '选择' }}
|
||||
<u-icon name="arrow-down-fill" class="choseIcon" size="15" :color="fontColor" :style="{marginLeft:'2rpx'}" />
|
||||
</view>
|
||||
<view class="search-input" @click="$emit('search')">
|
||||
<u-icon v-if="searchIconShowLeft" name="search" size="40" :color="fontColor" class="search-icon-left" />
|
||||
<text class="placeholder" :style="{fontSize:fontSize,color:fontColor}">{{ placeholder }}</text>
|
||||
<u-icon v-if="!searchIconShowLeft" name="search" size="40" :color="fontColor" class="search-icon-right" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SearchBar',
|
||||
props: {
|
||||
city: {
|
||||
type: String,
|
||||
default: '宜昌市'
|
||||
},
|
||||
showChoseCity: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fontSize: {
|
||||
type: String,
|
||||
default: '30rpx'
|
||||
},
|
||||
searchIconShowLeft: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
fontColor:{
|
||||
type: String,
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: 'rgba(255,255,255,0.6)' ,
|
||||
},
|
||||
border: {
|
||||
type: String,
|
||||
default: 'border: 1px solid #FFFFFF' ,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '搜索小区/城市/门店'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.choseIcon {
|
||||
margin-left: 5rpx;
|
||||
}
|
||||
.search-bar {
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 10rpx;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.location-chose {
|
||||
font-family: Noto Sans S Chinese;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 83.5rpx;
|
||||
padding: 25rpx 30rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
font-family: Noto Sans S Chinese;
|
||||
font-weight: 400;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-icon-right {
|
||||
|
||||
}
|
||||
|
||||
.search-icon-left {
|
||||
margin-right: 5%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user