select-lay.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <template>
  2. <view class="uni-select-lay" :style="{'z-index':zindex}">
  3. <input type="text" :name="name" v-model="value" class="uni-select-input">
  4. <view class="uni-select-lay-select" :class="{'active':active}">
  5. <!-- 禁用mask -->
  6. <view class="uni-disabled" v-if="disabled"></view>
  7. <!-- 禁用mask -->
  8. <!-- 清空 -->
  9. <view class="uni-select-lay-input-close" v-if="changevalue!=''&&this.active">
  10. <text @click="removevalue"></text>
  11. </view>
  12. <!-- 清空 -->
  13. <input type="text" class="uni-select-lay-input" :class="{active:changevalue!=''&&changevalue!=placeholder}"
  14. v-model="changevalue" :disabled="disabled" :placeholder="placeholder" @focus="unifocus"
  15. @input="intchange" @blur="uniblur">
  16. <view class="uni-select-lay-icon" @click="select"><text></text></view>
  17. </view>
  18. <view class="uni-select-lay-options" v-show="active">
  19. <template v-if="!changes">
  20. <view class="uni-select-lay-item" v-if="showplaceholder" :class="{active:value==''}"
  21. @click="selectitem(-1,null)">
  22. {{placeholder}}
  23. </view>
  24. <view class="uni-select-lay-item" :class="{active:value==item[svalue]}" v-for="(item,index) in options"
  25. :key="index" @click="selectitem(index,item)">{{item[slabel]}}</view>
  26. </template>
  27. <!-- 搜索 -->
  28. <template v-else>
  29. <template v-if="vlist.length>0">
  30. <view class="uni-select-lay-item" :class="{active:value==item[svalue]}"
  31. v-for="(item,index) in vlist" :key="index" @click="selectitem(index,item)">{{item[slabel]}}
  32. </view>
  33. </template>
  34. <template v-else>
  35. <view class="nosearch">无匹配内容!</view>
  36. </template>
  37. </template>
  38. </view>
  39. </view>
  40. </template>
  41. <script>
  42. export default {
  43. name: 'select-lay',
  44. props: {
  45. disabled: {
  46. type: Boolean,
  47. default: false
  48. },
  49. zindex: {
  50. type: Number,
  51. default: 999
  52. },
  53. options: {
  54. type: Array,
  55. default () {
  56. return []
  57. }
  58. },
  59. name: {
  60. type: String,
  61. default: ''
  62. },
  63. value: {
  64. type: String | Number,
  65. default: ''
  66. },
  67. placeholder: {
  68. type: String,
  69. default: '请选择'
  70. },
  71. showplaceholder: {
  72. type: Boolean,
  73. default: true
  74. },
  75. slabel: {
  76. type: String,
  77. default: 'label'
  78. },
  79. svalue: {
  80. type: String,
  81. default: 'value'
  82. }
  83. },
  84. data() {
  85. return {
  86. active: false, //组件是否激活,
  87. isremove: false, //是否是因为点击清空才导致的失去焦点
  88. changevalue: '', //搜索框同步
  89. oldvalue: '', //数据回滚
  90. changes: false, //正在搜索
  91. vlist: [], //搜索框查询的列表
  92. settimer: null //value改变定时器
  93. };
  94. },
  95. mounted() {
  96. this.itemcheck();
  97. },
  98. watch: {
  99. //value改变
  100. value() {
  101. this.itemcheck();
  102. },
  103. //初始化数组
  104. options() {
  105. // 此处判断是否有初始value,存在则判断显示文字
  106. this.itemcheck();
  107. }
  108. },
  109. methods: {
  110. //判断数组跟当前active值
  111. itemcheck() {
  112. // 此处判断是否有初始value,存在则判断显示文字
  113. if (this.value != '') {
  114. // 展示plachhoder
  115. //判断数组
  116. if (this.options.length > 0) {
  117. this.options.forEach(item => {
  118. if (this.value == item[this.svalue]) {
  119. this.oldvalue = this.changevalue = item[this.slabel];
  120. return;
  121. }
  122. })
  123. }
  124. } else {
  125. this.oldvalue = this.changevalue = '';
  126. }
  127. },
  128. //点击组件
  129. select() {
  130. if (this.disabled) return;
  131. this.active = !this.active;
  132. if (this.active) {
  133. this.changes = false;
  134. } else {
  135. this.changevalue = this.oldvalue;
  136. }
  137. },
  138. // 获得焦点
  139. unifocus() {
  140. if (this.disabled) return;
  141. this.active = true;
  142. this.changes = false;
  143. },
  144. // 失去焦点
  145. uniblur() {
  146. // bug 点击组件列会先触发失去焦点,此时组件列事件不执行
  147. setTimeout(() => {
  148. if (this.isremove) {
  149. this.isremove = false;
  150. } else {
  151. this.changevalue = this.oldvalue;
  152. this.isremove = false;
  153. this.active = false;
  154. }
  155. }, 153)
  156. },
  157. //移除数据
  158. removevalue() {
  159. this.isremove = true;
  160. this.changes = false;
  161. this.changevalue = '';
  162. },
  163. //value 改变
  164. intchange() {
  165. if (this.changevalue == '') {
  166. this.changes = false;
  167. return;
  168. };
  169. if (this.settimer) {
  170. clearTimeout(this.settimer)
  171. }
  172. this.changes = true;
  173. this.settimer = setTimeout(() => {
  174. this.vlist = this.options.filter(item => {
  175. return item[this.slabel].includes(this.changevalue)
  176. })
  177. }, 600)
  178. },
  179. //点击组件列
  180. selectitem(index, item) {
  181. this.changevalue = this.oldvalue;
  182. this.active = false;
  183. this.$emit('selectitem', index, item)
  184. }
  185. }
  186. }
  187. </script>
  188. <style lang="scss" scoped>
  189. .uni-select-lay {
  190. position: relative;
  191. z-index: 999;
  192. .uni-select-input {
  193. opacity: 0;
  194. position: absolute;
  195. z-index: -111;
  196. }
  197. // select部分
  198. .uni-select-lay-select {
  199. user-select: none;
  200. position: relative;
  201. z-index: 3;
  202. height: 72rpx;
  203. padding: 0 30px 0 10px;
  204. box-sizing: border-box;
  205. border-radius: 4px;
  206. border: 1px solid rgb(229, 229, 229);
  207. display: flex;
  208. align-items: center;
  209. font-size: 14px;
  210. color: #999;
  211. .uni-disabled {
  212. position: absolute;
  213. left: 0;
  214. width: 100%;
  215. height: 100%;
  216. z-index: 19;
  217. cursor: no-drop;
  218. }
  219. // input 框的清除按钮
  220. .uni-select-lay-input-close {
  221. position: absolute;
  222. right: 35px;
  223. top: 0;
  224. height: 100%;
  225. width: 15px;
  226. display: flex;
  227. align-items: center;
  228. justify-content: center;
  229. z-index: 3;
  230. cursor: pointer;
  231. text {
  232. position: relative;
  233. background: #fff;
  234. width: 13px;
  235. height: 13px;
  236. border-radius: 50%;
  237. border: 1px solid #bbb;
  238. &::before,
  239. &::after {
  240. content: "";
  241. position: absolute;
  242. left: 20%;
  243. top: 50%;
  244. height: 1px;
  245. width: 60%;
  246. transform: rotate(45deg);
  247. background-color: #bbb;
  248. }
  249. &::after {
  250. transform: rotate(-45deg);
  251. }
  252. }
  253. }
  254. .uni-select-lay-input {
  255. font-size: 14px;
  256. color: #999;
  257. display: block;
  258. width: 98%;
  259. overflow: hidden;
  260. text-overflow: ellipsis;
  261. white-space: nowrap;
  262. line-height: 30px;
  263. box-sizing: border-box;
  264. &.active {
  265. color: #333
  266. }
  267. }
  268. .uni-select-lay-icon {
  269. cursor: pointer;
  270. position: absolute;
  271. right: 0;
  272. top: 0;
  273. height: 100%;
  274. width: 30px;
  275. display: flex;
  276. align-items: center;
  277. justify-content: center;
  278. &::before {
  279. content: "";
  280. width: 1px;
  281. height: 100%;
  282. position: absolute;
  283. left: 0;
  284. top: 0;
  285. background-color: #e5e5e5;
  286. }
  287. text {
  288. display: block;
  289. width: 0;
  290. height: 0;
  291. border-width: 12rpx 12rpx 0;
  292. border-style: solid;
  293. border-color: #bbb transparent transparent;
  294. transition: .3s;
  295. }
  296. }
  297. &.active .uni-select-lay-icon {
  298. text {
  299. transform: rotate(180deg);
  300. }
  301. }
  302. }
  303. // options部分
  304. .uni-select-lay-options {
  305. user-select: none;
  306. position: absolute;
  307. top: calc(100% + 5px);
  308. left: 0;
  309. width: 100%;
  310. height: 500rpx;
  311. overflow-y: auto;
  312. border-radius: 4px;
  313. border: 1px solid rgb(229, 229, 229);
  314. background: #fff;
  315. padding: 5px 0;
  316. box-sizing: border-box;
  317. z-index: 9;
  318. .uni-select-lay-item {
  319. padding: 0 10px;
  320. box-sizing: border-box;
  321. cursor: pointer;
  322. line-height: 2.5;
  323. transition: .3s;
  324. font-size: 14px;
  325. &.active {
  326. background: #007AFF;
  327. color: #fff;
  328. &:hover {
  329. background: #007AFF;
  330. color: #fff;
  331. }
  332. }
  333. &:hover {
  334. background-color: #f5f5f5;
  335. }
  336. }
  337. .nosearch {
  338. font-size: 16px;
  339. line-height: 3;
  340. text-align: center;
  341. color: #666;
  342. }
  343. }
  344. }
  345. </style>