dropdown-item.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <div class="dropdown-item">
  3. <!-- selected -->
  4. <view class="dropdown-item__selected" @click="changePopup">
  5. <slot name="title" v-if="$slots.title"></slot>
  6. <block v-else>
  7. <view class="selected__name">
  8. {{title ? title : selectItem.text}}
  9. </view>
  10. <!-- <view class="selected__icon"
  11. :class="showClass === 'show'? 'up' : 'down'"
  12. >
  13. <span class="iconfont">&#xe851;</span>
  14. </view> -->
  15. </block>
  16. </view>
  17. <view class="dropdown-item__content" :style="{top: contentTop + 'px'}" v-if="showList">
  18. <!-- dropdown -->
  19. <view :class="['list', showClass]">
  20. <slot v-if="$slots.default"></slot>
  21. <block v-else>
  22. <view class="list__option" v-for="(item, index) in list" :key="index" @click="choose(item)">
  23. <view>{{item.text}}</view>
  24. <icon v-if="item.value === value" type="success_no_circle" size="26" />
  25. </view>
  26. </block>
  27. </view>
  28. <!-- dropdown-mask -->
  29. <!-- @touchmove 禁止滑动 -->
  30. <view @touchmove.stop.prevent="moveHandle" :class="['dropdown-mask', showClass]" v-if="showList" @click="closePopup"></view>
  31. </view>
  32. </div>
  33. </template>
  34. <script>
  35. export default {
  36. components: {},
  37. props: {
  38. value: [Number, String, Object],
  39. list: {
  40. type: Array,
  41. default: () => {
  42. return []
  43. }
  44. },
  45. title: [Number, String],
  46. contentTopReduse: {
  47. type: Number,
  48. default: 0
  49. }
  50. },
  51. data() {
  52. return {
  53. showList: "",
  54. showClass: '',
  55. selectItem: {},
  56. contentTop: 0
  57. }
  58. },
  59. watch: {},
  60. mounted() {
  61. this.showList = this.active;
  62. this.selectItem = this.list[this.value];
  63. // document.addEventListener('click', e => {
  64. // //this.$el 可以获取当前组件的容器节点
  65. // if (!this.$el.contains(e.target)) {
  66. // console.log('change');
  67. // this.close()
  68. // }
  69. // });
  70. },
  71. methods: {
  72. // 禁止滑动
  73. moveHandle() {},
  74. choose(item) {
  75. this.selectItem = item
  76. this.$emit('input', item.value)
  77. this.closePopup()
  78. },
  79. changePopup() {
  80. if (this.showList) {
  81. this.closePopup()
  82. } else {
  83. this.openPopup()
  84. }
  85. },
  86. openPopup() {
  87. // this.$parent -> dropdown-menu
  88. this.$parent.$emit('close')
  89. this.showList = true
  90. this.$nextTick(() => {
  91. this.getElementData('.dropdown-item__selected', (data) => {
  92. this.contentTop = data[0].bottom - this.contentTopReduse;
  93. this.showClass = 'show'
  94. })
  95. })
  96. },
  97. closePopup() {
  98. this.showClass = ''
  99. setTimeout(() => {
  100. this.showList = false
  101. }, 300)
  102. },
  103. close() {
  104. this.showClass = ''
  105. this.showList = false
  106. },
  107. getElementData(el, callback) {
  108. uni.createSelectorQuery().in(this).selectAll(el).boundingClientRect().exec((data) => {
  109. callback(data[0]);
  110. });
  111. }
  112. }
  113. }
  114. </script>
  115. <style lang="scss">
  116. @font-face {
  117. font-family: 'iconfont';
  118. /* project id 1564327 */
  119. src: url('https://at.alicdn.com/t/font_1564327_fcszez4n5i.eot');
  120. src: url('https://at.alicdn.com/t/font_1564327_fcszez4n5i.eot?#iefix') format('embedded-opentype'),
  121. url('https://at.alicdn.com/t/font_1564327_fcszez4n5i.woff2') format('woff2'),
  122. url('https://at.alicdn.com/t/font_1564327_fcszez4n5i.woff') format('woff'),
  123. url('https://at.alicdn.com/t/font_1564327_fcszez4n5i.ttf') format('truetype'),
  124. url('https://at.alicdn.com/t/font_1564327_fcszez4n5i.svg#iconfont') format('svg');
  125. }
  126. .iconfont {
  127. font-family: "iconfont" !important;
  128. font-size: 28rpx;
  129. font-style: normal;
  130. -webkit-font-smoothing: antialiased;
  131. -webkit-text-stroke-width: 0.2px;
  132. -moz-osx-font-smoothing: grayscale;
  133. }
  134. .line {
  135. position: absolute;
  136. height: 3px;
  137. width: 100px;
  138. background: #1abc9c;
  139. }
  140. .dropdown-item {
  141. position: relative;
  142. &__selected {
  143. position: relative;
  144. display: flex;
  145. align-items: center;
  146. background: transparent;
  147. // padding: 10rpx;
  148. box-sizing: border-box;
  149. justify-content: center;
  150. .selected__name {
  151. font-size: 32rpx;
  152. white-space: nowrap;
  153. position: relative;
  154. }
  155. .selected__icon {
  156. margin-left: 8rpx;
  157. &.down {
  158. transition: transform .3s;
  159. transform: rotateZ(0);
  160. }
  161. &.up {
  162. transition: transform .3s;
  163. transform: rotateZ(-180deg);
  164. }
  165. }
  166. }
  167. &__content {
  168. position: fixed;
  169. left: 0;
  170. right: 0;
  171. overflow: hidden;
  172. top: 0;
  173. bottom: 0;
  174. z-index: 10;
  175. .list {
  176. max-height: 400px;
  177. overflow-y: auto;
  178. position: absolute;
  179. left: 0;
  180. right: 0;
  181. z-index: 3;
  182. background: #fff;
  183. transform: translateY(-100%);
  184. transition: all .3s;
  185. &.show {
  186. transform: translateY(0);
  187. }
  188. &__option {
  189. font-size: 32rpx;
  190. padding: 26rpx 28rpx;
  191. display: flex;
  192. justify-content: space-between;
  193. &:not(:last-child) {
  194. border-bottom: 1rpx solid #DDDDDD;
  195. }
  196. }
  197. }
  198. .dropdown-mask {
  199. position: absolute;
  200. left: 0;
  201. right: 0;
  202. top: 0;
  203. bottom: 0;
  204. transition: all .3s;
  205. z-index: 2;
  206. &.show {
  207. background: rgba(0, 0, 0, 0.5);
  208. }
  209. }
  210. }
  211. &:not(:last-child):after {
  212. content: ' ';
  213. position: absolute;
  214. width: 2rpx;
  215. top: 36rpx;
  216. bottom: 36rpx;
  217. right: 0;
  218. background: $uni-border-color;
  219. }
  220. }
  221. </style>