uni-search-bar.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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: 14px;
  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: 14px;
  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: 14px;
  314. color: #333333;
  315. /* #ifdef H5 */
  316. cursor: pointer;
  317. /* #endif */
  318. }
  319. </style>