290 lines
7.4 KiB
Plaintext
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> |