formSelect.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <template>
  2. <view class="form-select">
  3. <view class="uni_select">
  4. <view class="uni_select_input_box" @click="toggleSelector">
  5. <view v-if="!current" class="uni_select_input_text_tips" :class="disabled?'_disabled':''">{{placeholder}}</view>
  6. <view v-if="current" class="uni_select_input_text" :class="disabled?'_disabled':''">{{current}}</view>
  7. <view v-if="icon" class="iconfont" :class="showSelector ? 'icon-to-up'+(disabled?' _disabled':'') : 'icon-to-down'+(disabled?' _disabled':'')"></view>
  8. </view>
  9. <view class="uni_select_mask" v-if="showSelector" @click="toggleSelector" />
  10. <view class="uni_select_selector" v-if="showSelector" :style="selectStyle">
  11. <scroll-view scroll-y="true" class="uni_select_selector_scroll">
  12. <view style="height: 4px;"></view>
  13. <view class="uni_select_selector_empty" v-if="localdata.length === 0">
  14. <view class="select-text" style="word-break: break-all;font-size:12px;">{{emptyTips}}</view>
  15. </view>
  16. <view v-else class="uni_select_selector_item" :class="item.userId == selectedId ? '_selected' : (item.disabled?'_disabled':'')" v-for="(item,index) in localdata"
  17. :key="index" @click="change(item)">
  18. <view class="select-text" style="word-break: break-all;">{{item.nickName}}</view>
  19. <view v-if="item.icon" :class="item.icon" :style="item.color?'color:'+item.color:''"></view>
  20. </view>
  21. <view style="height: 4px;"></view>
  22. </scroll-view>
  23. </view>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. /**
  29. * DataChecklist 数据选择器
  30. * @description 通过数据渲染的下拉框组件
  31. * @property {Array} localdata 本地数据 ,格式 [{id:'',title:''}]
  32. * @property {String, Number} selectedId 默认选项id
  33. * @property {String} placeholder 表单placeholder
  34. * @property {String} emptyText 没有数据时显示的文字 ,本地数据无效
  35. * @property {Boolean} icon 是否显示下拉图标
  36. * @property {Boolean} disabled 是否禁止选择
  37. * @property {String, Number} tag 标签,对于一个页面同时使用多次该组件时,并且选择后的回调为相同的函数时,可使用该标签进行区分
  38. * @event {Function} change 选中发生变化触发
  39. */
  40. export default {
  41. name:"formSelect",
  42. props: {
  43. localdata: {
  44. type: Array,
  45. default () {
  46. return []
  47. }
  48. },
  49. selectedId: {
  50. type: [String, Number],
  51. default: ''
  52. },
  53. placeholder: {
  54. type: String,
  55. default: '请选择'
  56. },
  57. emptyTips: {
  58. type: String,
  59. default: '没有更多选项了'
  60. },
  61. icon: {
  62. type: Boolean,
  63. default: false
  64. },
  65. disabled:{
  66. type: Boolean,
  67. default: false
  68. },
  69. tag: {
  70. type: [String, Number],
  71. default: ''
  72. },
  73. },
  74. data() {
  75. return {
  76. current:'',
  77. showSelector:false,
  78. selectStyle:'',
  79. maxHeight:288,
  80. };
  81. },
  82. mounted(){
  83. this.update();
  84. this.$nextTick(() => {
  85. this.setPosition();
  86. });
  87. },
  88. methods:{
  89. setPosition() {
  90. let that = this;
  91. if(this.$props.localdata.length < 8){
  92. if(this.$props.localdata.length > 0){
  93. this.maxHeight = (this.$props.localdata.length*36)+10;
  94. }
  95. }
  96. const query = uni.createSelectorQuery().in(this);
  97. query.select('.uni_select_input_box').boundingClientRect(data => {
  98. if (data) {
  99. // 获取当前窗口的高度
  100. const windowHeight = uni.getSystemInfoSync().windowHeight;
  101. // 元素顶部到窗口顶部的距离
  102. const elementTop = data.top;
  103. // 元素的高度
  104. const elementHeight = data.height;
  105. // 元素距离底部的位置 = 窗口高度 - 元素顶部距离窗口顶部距离 - 元素高度
  106. const bottomPosition = windowHeight - elementTop - elementHeight;
  107. if(bottomPosition < that.maxHeight){
  108. that.selectStyle = "bottom:"+(elementHeight + 4)+"px;top:auto;max-height:"+that.maxHeight+"px;";
  109. }else{
  110. that.selectStyle = "bottom:auto;top:calc(100% + 4px);max-height:"+that.maxHeight+"px;";
  111. }
  112. }
  113. }).exec();
  114. },
  115. update(){
  116. this.$data.current = '';
  117. if(this.$props.selectedId !== ''){
  118. for(var i in this.$props.localdata){
  119. if(this.$props.localdata[i].userId == this.$props.selectedId){
  120. this.$data.current = this.$props.localdata[i].nickName;
  121. }
  122. }
  123. }
  124. },
  125. toggleSelector() {
  126. if(!this.disabled){
  127. let that = this;
  128. this.setPosition();
  129. setTimeout(function(){
  130. that.showSelector = !that.showSelector
  131. },20);
  132. }
  133. },
  134. change(item){
  135. if(!item.disabled){
  136. this.$data.current = item.nickName;
  137. item.tag = this.$props.tag;
  138. this.$emit('change',item);
  139. this.showSelector = false;
  140. }
  141. }
  142. }
  143. }
  144. </script>
  145. <style>
  146. @import "./iconfont/iconfont.css";
  147. .form-select{
  148. display: flex;
  149. justify-content: flex-end;
  150. align-items: center;
  151. width:100%;
  152. cursor: pointer;
  153. }
  154. .uni_select {
  155. font-size: 14px;
  156. box-sizing: border-box;
  157. position: relative;
  158. /* #ifndef APP-NVUE */
  159. display: flex;
  160. user-select: none;
  161. /* #endif */
  162. flex-direction: row;
  163. align-items: center;
  164. justify-content: space-between;
  165. width:100%;
  166. padding:0 12px;
  167. }
  168. .uni_select_input_box{
  169. width: 100%;
  170. display: flex;
  171. justify-content: space-between;
  172. align-items: center;
  173. }
  174. .uni_select_mask {
  175. position: fixed;
  176. top: 0;
  177. bottom: 0;
  178. right: 0;
  179. left: 0;
  180. }
  181. .uni_select_selector {
  182. /* #ifndef APP-NVUE */
  183. box-sizing: border-box;
  184. /* #endif */
  185. position: absolute;
  186. left: 0;
  187. width: 100%;
  188. background-color: #FFFFFF;
  189. border: 0.5px solid #DFE7E1;
  190. border-radius: 4px;
  191. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  192. z-index: 2;
  193. overflow: hidden;
  194. }
  195. .uni_select_input_text_tips{
  196. overflow: hidden;
  197. height:40px;
  198. line-height: 40px;
  199. color:#7d7a7a;
  200. }
  201. .uni_select_input_text{
  202. height:40px;
  203. line-height: 40px;
  204. overflow: hidden;
  205. color:black;
  206. }
  207. .uni_select_selector_scroll {
  208. /* #ifndef APP-NVUE */
  209. max-height: 288px;
  210. box-sizing: border-box;
  211. /* #endif */
  212. }
  213. .uni_select_selector_empty,
  214. .uni_select_selector_item {
  215. /* #ifndef APP-NVUE */
  216. display: flex;
  217. cursor: pointer;
  218. /* #endif */
  219. line-height: 36px;
  220. font-size: 14px;
  221. text-align: center;
  222. /* border-bottom: solid 1px #DDDDDD; */
  223. padding: 0px 10px;
  224. display: flex;
  225. justify-content: space-between;
  226. align-items: center;
  227. }
  228. .select-text{
  229. line-height: 36px;
  230. height: 36px;
  231. word-break: break-all;
  232. overflow: hidden;
  233. }
  234. .uni_select_selector_item_this {
  235. background-color: rgb(21, 197, 206);
  236. }
  237. .uni_select_selector_empty:last-child,
  238. .uni_select_selector_item:last-child {
  239. /* #ifndef APP-NVUE */
  240. border-bottom: none;
  241. /* #endif */
  242. }
  243. ._selected{
  244. background-color: #e6e6e6;
  245. }
  246. ._disabled{
  247. color:#c7c4c4;
  248. }
  249. </style>