<template> <view class="uni-searchbar"> <view :style="{borderRadius:radius+'px',backgroundColor: bgColor}" class="uni-searchbar__box" @click="searchClick"> <view class="uni-searchbar__box-icon-search"> <slot name="searchIcon"> <uni-icons color="#c0c4cc" size="18" type="search" /> </slot> </view> <input v-if="show || searchVal" :focus="showSync" :disabled="readonly" :placeholder="placeholderText" :maxlength="maxlength" class="uni-searchbar__box-search-input" confirm-type="search" type="text" v-model="searchVal" @confirm="confirm" @blur="blur" @focus="emitFocus" /> <text v-else class="uni-searchbar__text-placeholder">{{ placeholder }}</text> <view v-if="show && (clearButton==='always'||clearButton==='auto'&&searchVal!=='') &&!readonly" class="uni-searchbar__box-icon-clear" @click="clear"> <slot name="clearIcon"> <uni-icons color="#c0c4cc" size="20" type="clear" /> </slot> </view> </view> <text @click="cancel" class="uni-searchbar__cancel" v-if="cancelButton ==='always' || show && cancelButton ==='auto'">{{cancelTextI18n}}</text> </view> </template> <script> import { initVueI18n } from '@dcloudio/uni-i18n' import messages from './i18n/index.js' const { t } = initVueI18n(messages) /** * SearchBar 搜索栏 * @description 搜索栏组件,通常用于搜索商品、文章等 * @tutorial https://ext.dcloud.net.cn/plugin?id=866 * @property {Number} radius 搜索栏圆角 * @property {Number} maxlength 输入最大长度 * @property {String} placeholder 搜索栏Placeholder * @property {String} clearButton = [always|auto|none] 是否显示清除按钮 * @value always 一直显示 * @value auto 输入框不为空时显示 * @value none 一直不显示 * @property {String} cancelButton = [always|auto|none] 是否显示取消按钮 * @value always 一直显示 * @value auto 输入框不为空时显示 * @value none 一直不显示 * @property {String} cancelText 取消按钮的文字 * @property {String} bgColor 输入框背景颜色 * @property {Boolean} focus 是否自动聚焦 * @property {Boolean} readonly 组件只读,不能有任何操作,只做展示 * @event {Function} confirm uniSearchBar 的输入框 confirm 事件,返回参数为uniSearchBar的value,e={value:Number} * @event {Function} input uniSearchBar 的 value 改变时触发事件,返回参数为uniSearchBar的value,e=value * @event {Function} cancel 点击取消按钮时触发事件,返回参数为uniSearchBar的value,e={value:Number} * @event {Function} clear 点击清除按钮时触发事件,返回参数为uniSearchBar的value,e={value:Number} * @event {Function} blur input失去焦点时触发事件,返回参数为uniSearchBar的value,e={value:Number} */ export default { name: "UniSearchBar", emits: ['input', 'update:modelValue', 'clear', 'cancel', 'confirm', 'blur', 'focus'], props: { placeholder: { type: String, default: "" }, radius: { type: [Number, String], default: 5 }, clearButton: { type: String, default: "auto" }, cancelButton: { type: String, default: "auto" }, cancelText: { type: String, default: '取消' }, bgColor: { type: String, default: "#F8F8F8" }, maxlength: { type: [Number, String], default: 100 }, value: { type: [Number, String], default: "" }, modelValue: { type: [Number, String], default: "" }, focus: { type: Boolean, default: false }, readonly: { type: Boolean, default: false } }, data() { return { show: false, showSync: false, searchVal: '' } }, computed: { cancelTextI18n() { return this.cancelText || t("uni-search-bar.cancel") }, placeholderText() { return this.placeholder || t("uni-search-bar.placeholder") } }, watch: { // #ifndef VUE3 value: { immediate: true, handler(newVal) { this.searchVal = newVal if (newVal) { this.show = true } } }, // #endif // #ifdef VUE3 modelValue: { immediate: true, handler(newVal) { this.searchVal = newVal if (newVal) { this.show = true } } }, // #endif focus: { immediate: true, handler(newVal) { if (newVal) { if(this.readonly) return this.show = true; this.$nextTick(() => { this.showSync = true }) } } }, searchVal(newVal, oldVal) { this.$emit("input", newVal) // #ifdef VUE3 this.$emit("update:modelValue", newVal) // #endif } }, methods: { searchClick() { if(this.readonly) return if (this.show) { return } this.show = true; this.$nextTick(() => { this.showSync = true }) }, clear() { this.$emit("clear", { value: this.searchVal }) this.searchVal = "" }, cancel() { if(this.readonly) return this.$emit("cancel", { value: this.searchVal }); this.searchVal = "" this.show = false this.showSync = false // #ifndef APP-PLUS uni.hideKeyboard() // #endif // #ifdef APP-PLUS plus.key.hideSoftKeybord() // #endif }, confirm() { // #ifndef APP-PLUS uni.hideKeyboard(); // #endif // #ifdef APP-PLUS plus.key.hideSoftKeybord() // #endif this.$emit("confirm", { value: this.searchVal }) }, blur() { // #ifndef APP-PLUS uni.hideKeyboard(); // #endif // #ifdef APP-PLUS plus.key.hideSoftKeybord() // #endif this.$emit("blur", { value: this.searchVal }) }, emitFocus(e) { this.$emit("focus", e.detail) } } }; </script> <style lang="scss"> $uni-searchbar-height: 36px; .uni-searchbar { /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: row; position: relative; padding: 10px; // background-color: #fff; } .uni-searchbar__box { /* #ifndef APP-NVUE */ display: flex; box-sizing: border-box; /* #endif */ overflow: hidden; position: relative; flex: 1; justify-content: center; flex-direction: row; align-items: center; height: $uni-searchbar-height; padding: 5px 8px 5px 0px; } .uni-searchbar__box-icon-search { /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: row; // width: 32px; padding: 0 8px; justify-content: center; align-items: center; color: #B3B3B3; } .uni-searchbar__box-search-input { flex: 1; font-size: 14px; color: #333; } .uni-searchbar__box-icon-clear { align-items: center; line-height: 24px; padding-left: 8px; /* #ifdef H5 */ cursor: pointer; /* #endif */ } .uni-searchbar__text-placeholder { font-size: 14px; color: #B3B3B3; margin-left: 5px; } .uni-searchbar__cancel { padding-left: 10px; line-height: $uni-searchbar-height; font-size: 14px; color: #333333; /* #ifdef H5 */ cursor: pointer; /* #endif */ } </style>