uni-search-bar.vue 7.3 KB

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