u-select.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <view class="u-select">
  3. <view class="u-select__content">
  4. <view class="u-select__label" @click="openSelect">
  5. <slot name="text">
  6. <text class="u-select__text" v-if="showOptionsLabel">
  7. {{ currentLabel }}
  8. </text>
  9. <text class="u-select__text" v-else>
  10. {{ label }}
  11. </text>
  12. </slot>
  13. <slot name="icon">
  14. <u-icon name="arrow-down" :size="iconSize" :color="iconColor"></u-icon>
  15. </slot>
  16. </view>
  17. <u-overlay
  18. :show="isOpen"
  19. @click="overlayClick"
  20. v-if="overlay"
  21. :zIndex="zIndex"
  22. :duration="duration + 50"
  23. :customStyle="overlayStyle"
  24. :opacity="overlayOpacity"
  25. ></u-overlay>
  26. <view class="u-select__options__wrap"
  27. :style="{ zIndex: zIndex + 1, left: optionsWrapLeft, right: optionsWrapRight }">
  28. <view class="u-select__options" v-if="isOpen">
  29. <slot name="options">
  30. <view class="u-select__options_item"
  31. :class="current == item[keyName] ? 'active': ''"
  32. :key="index" v-for="(item, index) in options"
  33. @click="selectItem(item)">
  34. <slot name="optionItem" :item="item">
  35. <text class="u-select__item_text" :style="{color: itemColor}">
  36. {{item[labelName]}}
  37. </text>
  38. </slot>
  39. </view>
  40. </slot>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. </template>
  46. <script>
  47. import { getWindowInfo } from '../../libs/function/index';
  48. export default {
  49. name:"up-select",
  50. emits: ['update:current', 'select'],
  51. props: {
  52. overlay: {
  53. type: Boolean,
  54. default: true
  55. },
  56. overlayOpacity: {
  57. type: Number,
  58. default: 0.01
  59. },
  60. overlayStyle: {
  61. type: Object,
  62. default: () => {
  63. return {}
  64. }
  65. },
  66. duration: {
  67. type: Number,
  68. default: 300
  69. },
  70. label: {
  71. type: String,
  72. default: '选项'
  73. },
  74. options: {
  75. type: Array,
  76. default: () => {
  77. return []
  78. }
  79. },
  80. keyName: {
  81. type: String,
  82. default: 'id'
  83. },
  84. labelName: {
  85. type: String,
  86. default: 'name'
  87. },
  88. showOptionsLabel: {
  89. type: Boolean,
  90. default: false
  91. },
  92. current: {
  93. type: [String, Number],
  94. default: ''
  95. },
  96. zIndex: {
  97. type: Number,
  98. default: 11000
  99. },
  100. itemColor: {
  101. type: String,
  102. default: '#333333'
  103. },
  104. iconColor: {
  105. type: String,
  106. default: ''
  107. },
  108. iconSize: {
  109. type: [String],
  110. default: '13px'
  111. }
  112. },
  113. data() {
  114. return {
  115. isOpen: false,
  116. optionsWrapLeft: 'auto',
  117. optionsWrapRight: 'auto'
  118. }
  119. },
  120. computed: {
  121. currentLabel() {
  122. let name = '';
  123. this.options.forEach((ele) => {
  124. if (ele[this.keyName] === this.current) {
  125. name = ele[this.labelName];
  126. }
  127. });
  128. return name;
  129. }
  130. },
  131. methods: {
  132. openSelect() {
  133. this.isOpen = true;
  134. this.$nextTick(() => {
  135. if (this.isOpen) {
  136. this.adjustOptionsWrapPosition();
  137. }
  138. });
  139. },
  140. overlayClick() {
  141. this.isOpen = false;
  142. },
  143. selectItem(item) {
  144. this.isOpen = false;
  145. this.$emit('update:current', item[this.keyName]);
  146. this.$emit('select', item);
  147. },
  148. adjustOptionsWrapPosition() {
  149. let wi = getWindowInfo();
  150. let windowWidth = wi.windowWidth;
  151. this.$uGetRect('.u-select__options__wrap').then(rect => {
  152. console.log(rect)
  153. if (rect.left + rect.width > windowWidth) {
  154. // 如果右侧被遮挡,则调整到左侧
  155. this.optionsWrapLeft = 'auto';
  156. this.optionsWrapRight = `0px`;
  157. }
  158. });
  159. }
  160. }
  161. }
  162. </script>
  163. <style lang="scss" scoped>
  164. .u-select__content {
  165. position: relative;
  166. .u-select__label {
  167. display: flex;
  168. justify-content: space-between;
  169. /* #ifdef H5 */
  170. &:hover {
  171. cursor: pointer;
  172. }
  173. /* #endif */
  174. }
  175. .u-select__text {
  176. margin-right: 2px;
  177. }
  178. .u-select__options__wrap {
  179. margin-bottom: 46px;
  180. position: absolute;
  181. top: 20px;
  182. left: 0;
  183. }
  184. .u-select__options {
  185. min-width: 100px;
  186. box-sizing: border-box;
  187. border-radius: 4px;
  188. border: 1px solid #f1f1f1;
  189. background-color: #fff;
  190. .u-select__options_item {
  191. padding: 10px 12px;
  192. box-sizing: border-box;
  193. width: 100%;
  194. height: 100%;
  195. &:hover {
  196. background-color: #f7f7f7;
  197. }
  198. /* #ifdef H5 */
  199. &:hover {
  200. cursor: pointer;
  201. }
  202. .u-select__item_text {
  203. &:hover {
  204. cursor: pointer;
  205. }
  206. }
  207. /* #endif */
  208. }
  209. }
  210. }
  211. </style>