uni-search-bar.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <template>
  2. <view class="uni-searchbar">
  3. <view
  4. :style="{ borderRadius: radius + 'px', backgroundColor: bgColor }"
  5. class="uni-searchbar__box"
  6. @click="searchClick"
  7. >
  8. <view class="uni-searchbar__box-icon-search">
  9. <slot name="searchIcon">
  10. <uni-icons color="#c0c4cc" size="18" type="search" />
  11. </slot>
  12. </view>
  13. <input
  14. v-if="show || searchVal"
  15. :focus="showSync"
  16. :disabled="readonly"
  17. :placeholder="placeholderText"
  18. :maxlength="maxlength"
  19. class="uni-searchbar__box-search-input"
  20. confirm-type="search"
  21. type="text"
  22. v-model="searchVal"
  23. @confirm="confirm"
  24. @blur="blur"
  25. @focus="emitFocus"
  26. />
  27. <text v-else class="uni-searchbar__text-placeholder">{{
  28. placeholder
  29. }}</text>
  30. <view
  31. v-if="
  32. show &&
  33. (clearButton === 'always' ||
  34. (clearButton === 'auto' && searchVal !== '')) &&
  35. !readonly
  36. "
  37. class="uni-searchbar__box-icon-clear"
  38. @click="clear"
  39. >
  40. <slot name="clearIcon">
  41. <uni-icons color="#c0c4cc" size="20" type="clear" />
  42. </slot>
  43. </view>
  44. </view>
  45. <text
  46. @click="cancel"
  47. class="uni-searchbar__cancel"
  48. v-if="cancelButton === 'always' || (show && cancelButton === 'auto')"
  49. >{{ cancelTextI18n }}</text
  50. >
  51. </view>
  52. </template>
  53. <script>
  54. import { initVueI18n } from '@dcloudio/uni-i18n'
  55. import messages from './i18n/index.js'
  56. const { t } = initVueI18n(messages)
  57. /**
  58. * SearchBar 搜索栏
  59. * @description 搜索栏组件,通常用于搜索商品、文章等
  60. * @tutorial https://ext.dcloud.net.cn/plugin?id=866
  61. * @property {Number} radius 搜索栏圆角
  62. * @property {Number} maxlength 输入最大长度
  63. * @property {String} placeholder 搜索栏Placeholder
  64. * @property {String} clearButton = [always|auto|none] 是否显示清除按钮
  65. * @value always 一直显示
  66. * @value auto 输入框不为空时显示
  67. * @value none 一直不显示
  68. * @property {String} cancelButton = [always|auto|none] 是否显示取消按钮
  69. * @value always 一直显示
  70. * @value auto 输入框不为空时显示
  71. * @value none 一直不显示
  72. * @property {String} cancelText 取消按钮的文字
  73. * @property {String} bgColor 输入框背景颜色
  74. * @property {Boolean} focus 是否自动聚焦
  75. * @property {Boolean} readonly 组件只读,不能有任何操作,只做展示
  76. * @event {Function} confirm uniSearchBar 的输入框 confirm 事件,返回参数为uniSearchBar的value,e={value:Number}
  77. * @event {Function} input uniSearchBar 的 value 改变时触发事件,返回参数为uniSearchBar的value,e=value
  78. * @event {Function} cancel 点击取消按钮时触发事件,返回参数为uniSearchBar的value,e={value:Number}
  79. * @event {Function} clear 点击清除按钮时触发事件,返回参数为uniSearchBar的value,e={value:Number}
  80. * @event {Function} blur input失去焦点时触发事件,返回参数为uniSearchBar的value,e={value:Number}
  81. */
  82. export default {
  83. name: 'UniSearchBar',
  84. emits: [
  85. 'input',
  86. 'update:modelValue',
  87. 'clear',
  88. 'cancel',
  89. 'confirm',
  90. 'blur',
  91. 'focus'
  92. ],
  93. props: {
  94. placeholder: {
  95. type: String,
  96. default: ''
  97. },
  98. radius: {
  99. type: [Number, String],
  100. default: 5
  101. },
  102. clearButton: {
  103. type: String,
  104. default: 'auto'
  105. },
  106. cancelButton: {
  107. type: String,
  108. default: 'auto'
  109. },
  110. cancelText: {
  111. type: String,
  112. default: '取消'
  113. },
  114. bgColor: {
  115. type: String,
  116. default: '#F8F8F8'
  117. },
  118. maxlength: {
  119. type: [Number, String],
  120. default: 100
  121. },
  122. value: {
  123. type: [Number, String],
  124. default: ''
  125. },
  126. modelValue: {
  127. type: [Number, String],
  128. default: ''
  129. },
  130. focus: {
  131. type: Boolean,
  132. default: false
  133. },
  134. readonly: {
  135. type: Boolean,
  136. default: false
  137. }
  138. },
  139. data () {
  140. return {
  141. show: false,
  142. showSync: false,
  143. searchVal: ''
  144. }
  145. },
  146. computed: {
  147. cancelTextI18n () {
  148. return this.cancelText || t('uni-search-bar.cancel')
  149. },
  150. placeholderText () {
  151. return this.placeholder || t('uni-search-bar.placeholder')
  152. }
  153. },
  154. watch: {
  155. // #ifndef VUE3
  156. value: {
  157. immediate: true,
  158. handler (newVal) {
  159. this.searchVal = newVal
  160. if (newVal) {
  161. this.show = true
  162. }
  163. }
  164. },
  165. // #endif
  166. // #ifdef VUE3
  167. modelValue: {
  168. immediate: true,
  169. handler (newVal) {
  170. this.searchVal = newVal
  171. if (newVal) {
  172. this.show = true
  173. }
  174. }
  175. },
  176. // #endif
  177. focus: {
  178. immediate: true,
  179. handler (newVal) {
  180. if (newVal) {
  181. if (this.readonly) return
  182. this.show = true
  183. this.$nextTick(() => {
  184. this.showSync = true
  185. })
  186. }
  187. }
  188. },
  189. searchVal (newVal, oldVal) {
  190. this.$emit('input', newVal)
  191. // #ifdef VUE3
  192. this.$emit('update:modelValue', newVal)
  193. // #endif
  194. }
  195. },
  196. methods: {
  197. searchClick () {
  198. if (this.readonly) return
  199. if (this.show) {
  200. return
  201. }
  202. this.show = true
  203. this.$nextTick(() => {
  204. this.showSync = true
  205. })
  206. },
  207. clear () {
  208. this.$emit('clear', {
  209. value: this.searchVal
  210. })
  211. this.searchVal = ''
  212. },
  213. cancel () {
  214. if (this.readonly) return
  215. this.$emit('cancel', {
  216. value: this.searchVal
  217. })
  218. this.searchVal = ''
  219. this.show = false
  220. this.showSync = false
  221. // #ifndef APP-PLUS
  222. uni.hideKeyboard()
  223. // #endif
  224. // #ifdef APP-PLUS
  225. plus.key.hideSoftKeybord()
  226. // #endif
  227. },
  228. confirm () {
  229. // #ifndef APP-PLUS
  230. uni.hideKeyboard()
  231. // #endif
  232. // #ifdef APP-PLUS
  233. plus.key.hideSoftKeybord()
  234. // #endif
  235. this.$emit('confirm', {
  236. value: this.searchVal
  237. })
  238. },
  239. blur () {
  240. // #ifndef APP-PLUS
  241. uni.hideKeyboard()
  242. // #endif
  243. // #ifdef APP-PLUS
  244. plus.key.hideSoftKeybord()
  245. // #endif
  246. this.$emit('blur', {
  247. value: this.searchVal
  248. })
  249. },
  250. emitFocus (e) {
  251. this.$emit('focus', e.detail)
  252. }
  253. }
  254. }
  255. </script>
  256. <style lang="scss">
  257. $uni-searchbar-height: 36px;
  258. .uni-searchbar {
  259. /* #ifndef APP-NVUE */
  260. display: flex;
  261. /* #endif */
  262. flex-direction: row;
  263. position: relative;
  264. padding: 10px;
  265. // background-color: #fff;
  266. }
  267. .uni-searchbar__box {
  268. /* #ifndef APP-NVUE */
  269. display: flex;
  270. box-sizing: border-box;
  271. /* #endif */
  272. overflow: hidden;
  273. position: relative;
  274. flex: 1;
  275. justify-content: center;
  276. flex-direction: row;
  277. align-items: center;
  278. height: $uni-searchbar-height;
  279. padding: 5px 8px 5px 0px;
  280. }
  281. .uni-searchbar__box-icon-search {
  282. /* #ifndef APP-NVUE */
  283. display: flex;
  284. /* #endif */
  285. flex-direction: row;
  286. // width: 32px;
  287. padding: 0 8px;
  288. justify-content: center;
  289. align-items: center;
  290. color: #b3b3b3;
  291. }
  292. .uni-searchbar__box-search-input {
  293. flex: 1;
  294. font-size: 32rpx;
  295. color: #333;
  296. }
  297. .uni-searchbar__box-icon-clear {
  298. align-items: center;
  299. line-height: 24px;
  300. padding-left: 8px;
  301. /* #ifdef H5 */
  302. cursor: pointer;
  303. /* #endif */
  304. }
  305. .uni-searchbar__text-placeholder {
  306. font-size: 32rpx;
  307. color: #b3b3b3;
  308. margin-left: 5px;
  309. }
  310. .uni-searchbar__cancel {
  311. padding-left: 10px;
  312. line-height: $uni-searchbar-height;
  313. font-size: 32rpx;
  314. color: #333333;
  315. /* #ifdef H5 */
  316. cursor: pointer;
  317. /* #endif */
  318. }
  319. </style>