88 lines
3.8 KiB
Plaintext
88 lines
3.8 KiB
Plaintext
<template>
|
|
<view class="search-bar" v-if="mode==='readonly'" :style="{ paddingRight: internalCapsuleRight + 'px' }">
|
|
<view class="search-box" @click="onClick">
|
|
<image class="icon" src="/static/icons/search.png" />
|
|
<text class="placeholder">{{ placeholder }}</text>
|
|
</view>
|
|
<view class="right-slot">
|
|
<slot name="right"></slot>
|
|
<view v-if="showActionButton" class="action-btn" @click.stop="onActionClick">搜索</view>
|
|
<image v-if="showCamera" class="camera-icon" src="/static/icons/camera.png" @click.stop="$emit('camera')" />
|
|
</view>
|
|
</view>
|
|
|
|
<view class="search-bar" v-else :style="{ paddingRight: internalCapsuleRight + 'px' }">
|
|
<view class="search-box">
|
|
<image class="icon" src="/static/icons/search.png" />
|
|
<input class="search-input" :placeholder="placeholder" v-model="internalValue" @input="onInput" @confirm="onConfirm" />
|
|
</view>
|
|
<view class="right-slot">
|
|
<slot name="right"></slot>
|
|
<view v-if="showActionButton" class="action-btn" @click.stop="onActionClick">搜索</view>
|
|
<image v-if="showCamera" class="camera-icon" src="/static/icons/camera.png" @click.stop="$emit('camera')" />
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script lang="uts">
|
|
import { getNavMetrics } from '@/utils/navUtils.uts'
|
|
export default {
|
|
props: {
|
|
placeholder: { type: String, default: '搜索商品、店铺…' },
|
|
mode: { type: String, default: 'readonly' }, // 'readonly' | 'input'
|
|
autoNavigate: { type: Boolean, default: true },
|
|
capsuleRight: { type: [Number, String], default: 0 },
|
|
showActionButton: { type: Boolean, default: true },
|
|
showCamera: { type: Boolean, default: false },
|
|
value: { type: String, default: '' }
|
|
},
|
|
created() {
|
|
// 计算默认的胶囊右侧预留
|
|
try {
|
|
const metrics = getNavMetrics()
|
|
// 如果传入 props capsuleRight 为 0 或空,则使用自动计算值
|
|
this.internalCapsuleRight = (this.capsuleRight && Number(this.capsuleRight) > 0) ? Number(this.capsuleRight) : (metrics.navRightReserve || 0)
|
|
} catch (e) {
|
|
this.internalCapsuleRight = (this.capsuleRight && Number(this.capsuleRight) > 0) ? Number(this.capsuleRight) : 0
|
|
}
|
|
},
|
|
data() { return { internalValue: this.value, internalCapsuleRight: 0 } },
|
|
watch: {
|
|
value(newVal) { this.internalValue = newVal }
|
|
},
|
|
methods: {
|
|
onClick() {
|
|
this.$emit('click')
|
|
if (this.mode === 'readonly' && this.autoNavigate) {
|
|
try { uni.navigateTo({ url: '/pages/mall/consumer/search' }) } catch (e) {}
|
|
}
|
|
},
|
|
onActionClick() {
|
|
// 优先触发 action 事件,包含当前输入或占位词
|
|
const payload = (this.internalValue && this.internalValue.length > 0) ? this.internalValue : this.placeholder
|
|
this.$emit('action', payload)
|
|
},
|
|
onInput(e) {
|
|
const val = e && e.detail ? e.detail.value : (e || '')
|
|
this.internalValue = val
|
|
this.$emit('update:value', val)
|
|
this.$emit('input', val)
|
|
},
|
|
onConfirm(e) {
|
|
const confirmed = e && e.detail ? e.detail.value : this.internalValue
|
|
this.$emit('confirm', confirmed)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.search-bar { display:flex; align-items:center; padding:12rpx 16rpx; background:transparent }
|
|
.search-box { flex:1; display:flex; align-items:center; background:#ffffff; border-radius:999rpx; padding:10rpx 12rpx; box-shadow:0 2rpx 8rpx rgba(0,0,0,0.04); height:44rpx; border:1rpx solid rgba(0,0,0,0.05) }
|
|
.icon { width:36rpx; height:36rpx; margin-right:12rpx }
|
|
.placeholder { color:#b8b8b8; font-size:26rpx; padding-right:6rpx }
|
|
.search-input { flex:1; height:40rpx; font-size:26rpx; color:#222; padding:0 }
|
|
.right-slot { margin-left:12rpx; display:flex; align-items:center }
|
|
.action-btn { background:#ff5000; color:#fff; padding:10rpx 20rpx; border-radius:16rpx; font-size:26rpx; font-weight:500 }
|
|
.camera-icon { width:28rpx; height:28rpx; margin-left:8rpx }
|
|
</style> |