Files
2026-09-24 16:25:22 +08:00

290 lines
7.4 KiB
Plaintext

<script lang="ts" setup>
import { ref, computed, watch, onMounted } from "vue"
import { getDefaultColor } from "../../core/util/xCoreColorUtil.uts"
import { checkIsCssUnit } from "../../core/util/xCoreUtil.uts"
import { xConfig } from "../../config/xConfig.uts"
/**
* @name 搜索栏 xSearch
* @description 可定制化强
* @page /pages/daohang/search
* @category 导航组件
* @constant 平台兼容
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
*/
defineOptions({ name: "xSearch" })
const i18n = xConfig.i18n
export type xSearchPropsType = {
/** 输入框圆角 */
round: string,
/** 是否显示清除图标 */
showClear: boolean,
/** 双向绑定的输入值 */
modelValue: string,
/** 输入框提示语 */
placeholder: string,
/** 搜索图标和清除图标的颜色 */
iconColor: string,
/** 搜索条背景 */
color: string,
/** 取消的文本色 */
cancelFontColor: string,
/** 暗黑模式下的搜索条背景,空值取:sheetDarkColor */
darkColor: string,
/** 输入框的背景 */
inputBgColor: string,
/** 输入框的字体颜色 */
fontColor: string,
/** 边框style: [width, style, color] */
border: string[],
/** 暗黑模式下边框颜色 */
darkBorderColor: string,
/** 输入框的提示样式 */
placeholderStyle: string,
/** 是否显示右侧取消按钮 */
showCancel:boolean
}
const props = withDefaults(defineProps<xSearchPropsType>(), {
round: "8",
showClear: true,
modelValue: "",
placeholder: "",
iconColor: "#bfbfbf",
color: "#ffffff",
cancelFontColor: "#000000",
darkColor: "",
inputBgColor: "#f5f5f5",
fontColor: "#333333",
border: (): string[] => [] as string[],
darkBorderColor: "",
placeholderStyle: "",
showCancel:true
})
const emits = defineEmits<{
/** 取消时触发 */
(e: 'cancel', str: string): void
/** 清空时触发 */
(e: 'clear', str: string): void
/** 点击右侧文本时触发 */
(e: 'rightClick', str: string): void
/** 输入法确认搜索时触发 */
(e: 'confirm', str: string): void
/** 输入时触发 */
(e: 'input', str: string): void
/** 等同 v-model */
(e: 'update:modelValue', str: string): void
}>()
// 响应式数据
const nowValue = ref<string>("")
const foucsIng = ref<boolean>(false)
// 计算属性
const _placeholderStyle = computed((): string => props.placeholderStyle)
const _round = computed((): string => checkIsCssUnit(props.round, xConfig.unit))
const _showClear = computed((): boolean => props.showClear)
const _placeholder = computed((): string => {
if (props.placeholder == '') return i18n.t("tmui4x.search.placeholder")
return props.placeholder
})
const _iconColor = computed((): string => getDefaultColor(props.iconColor))
const _color = computed((): string => {
if (xConfig.dark == 'dark') {
if (props.darkColor == "") {
return xConfig.sheetDarkColor
}
return getDefaultColor(props.darkColor)
}
return getDefaultColor(props.color)
})
const _inputBgColor = computed((): string => {
if (xConfig.dark == 'dark') return xConfig.inputDarkColor
return getDefaultColor(props.inputBgColor)
})
const _cancelFontColor = computed((): string => getDefaultColor(props.cancelFontColor))
const _fontColor = computed((): string => {
if (xConfig.dark == 'dark') return '#ffffff'
return getDefaultColor(props.fontColor)
})
const _border = computed((): string => {
let borderstr = props.border
if (borderstr.length != 3) return "none"
let lastColor = borderstr[borderstr.length - 1]
if (xConfig.dark == 'dark') {
if (props.darkBorderColor == "") {
lastColor = getDefaultColor(xConfig.borderDarkColor)
} else {
lastColor = props.darkBorderColor
}
}
return `${borderstr[0]} ${borderstr[1]} ${lastColor}`
})
// 监听 props.modelValue 变化
watch((): string => props.modelValue, (newValue: string) => {
if (newValue === nowValue.value) return
nowValue.value = newValue
})
onMounted(() => {
nowValue.value = props.modelValue
})
// 方法
function confirm() {
emits('confirm', nowValue.value)
}
function inputHndler(evt: InputEvent) {
// @ts-ignore
nowValue.value = evt.detail.value
emits('input', nowValue.value)
emits('update:modelValue', nowValue.value)
}
function raightCellClick() {
emits('rightClick', nowValue.value)
}
function clearHandler() {
nowValue.value = ""
emits('update:modelValue', "")
emits('clear', "")
foucsIng.value = false
}
function cancel() {
nowValue.value = ""
emits('cancel', "")
emits('update:modelValue', "")
foucsIng.value = false
}
function blur() {
if (nowValue.value.length == 0) {
foucsIng.value = false
}
}
function foucus() {
foucsIng.value = true
}
</script>
<template>
<view class="xSearch" :style="{backgroundColor:_color}">
<view class="xSearchLeft">
<!--
@slot 左插槽
-->
<slot name="left"></slot>
</view>
<view class="xSearchCenter" :style="{borderRadius:_round,backgroundColor:_inputBgColor,border:_border}">
<!--
输入框内的左插槽
-->
<slot name="inputLeft"></slot>
<x-icon style="margin: 0 12px;" :color="_iconColor" name="search-2-line" font-size="16"></x-icon>
<input :style="{color:_fontColor}" @focus="foucus" @blur="blur" @input="inputHndler" confirm-type="search"
:value="nowValue" @confirm="confirm" :placeholder-style="_placeholderStyle" :placeholder="_placeholder"
class="xSearchCenterInput" type="text" />
<view @click="clearHandler" v-if="_showClear&&nowValue.length>0" class="xSearchclear"
style="padding: 0 12px;">
<x-icon :color="_iconColor" name="close-circle-fill"></x-icon>
</view>
<!--
输入框内右插槽
-->
<slot name="inputRight"></slot>
</view>
<view
v-if="props.showCancel"
:class="[(nowValue.length>0||foucsIng)?'xSearchRightTextOn':'xSearchRightTextOff']"
@click="cancel"
class="xSearchRightText">
<!--
取消按钮的文本插槽
-->
<slot name="cacel">
<x-text :color="_cancelFontColor">
<!-- 取消 -->
{{i18n.t("tmui4x.search.cancel")}}
</x-text>
</slot>
</view>
<view class="xSearchRight" @click="raightCellClick">
<!--
右插槽
-->
<slot name="right">
</slot>
</view>
</view>
</template>
<style scoped>
.xSearchCenterInput {
flex: 1;
font-size: 16px;
}
.xSearch {
width: 100%;
position: relative;
height: 48px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
overflow: hidden;
}
.xSearchCenter {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
height: 38px;
flex: 1;
}
.xSearchLeft {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
.xSearchRight {
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.xSearchRightText {
transition-duration: 200ms;
transition-property: opacity, transform, width;
transition-timing-function: linear;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
/* #ifdef WEB */
cursor: pointer;
/* #endif */
}
.xSearchRightTextOn {
opacity: 1;
transform: scale(1) translateX(0px);
width: 60px;
pointer-events: auto;
}
.xSearchRightTextOff {
opacity: 0;
transform: scale(0) translateX(60px);
width: 0px;
pointer-events: none;
}
</style>