特易招,招聘小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
6.3 KiB

4 months ago
2 months ago
4 months ago
2 months ago
4 months ago
2 months ago
4 months ago
  1. <template>
  2. <view class="uv-drop-down-popup"
  3. >
  4. <uv-transition :show="show" mode="fade" :duration="300" :custom-style="overlayStyle" @click="clickOverlay">
  5. <view class="uv-dp__container" ref="uvDPContainer" :style="{height: `${height}px`}" @click.stop="blockClick">
  6. <scroll-view
  7. style="height: 100%;"
  8. scroll-y="true">
  9. <view class="uv-dp__container__list" ref="uvDPList">
  10. <slot>
  11. <view class="uv-dp__container__list--item" v-for="(item,index) in list" :key="index" @click="clickHandler(item,index)" :style="[itemCustomStyle(index)]">
  12. <uv-text :text="item[keyName]" :size="getTextSize(index)" :color="getTextColor(index)"></uv-text>
  13. </view>
  14. </slot>
  15. </view>
  16. </scroll-view>
  17. </view>
  18. </uv-transition>
  19. </view>
  20. </template>
  21. <script>
  22. import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
  23. import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
  24. // #ifdef APP-NVUE
  25. const animation = uni.requireNativePlugin('animation');
  26. const dom = uni.requireNativePlugin('dom');
  27. // #endif
  28. /**
  29. * DropDownPopup 下拉框
  30. * @description 下拉筛选框
  31. * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
  32. * @property {String | Number} name 字段标识
  33. * @property {String | Number} zIndex 弹出层的层级
  34. * @property {String | Number} opacity 遮罩层的透明度
  35. * @property {Boolean} clickOverlayOnClose 是否允许点击遮罩层关闭弹窗
  36. * @property {Object} currentDropItem 当前下拉筛选菜单对象
  37. * @property {String} keyName 指定从当前下拉筛选菜单对象元素中读取哪个属性作为文本展示
  38. */
  39. export default {
  40. name: 'uv-drop-down-popup',
  41. mixins: [mpMixin, mixin],
  42. props: {
  43. sign: {
  44. type: [String, Number],
  45. default: 'UVDROPDOWN'
  46. },
  47. zIndex: {
  48. type: [Number, String],
  49. default: 999
  50. },
  51. opacity: {
  52. type: [Number, String],
  53. default: 0.5
  54. },
  55. clickOverlayOnClose: {
  56. type: Boolean,
  57. default: true
  58. },
  59. // 当前下拉选项对象
  60. currentDropItem: {
  61. type: Object,
  62. default () {
  63. return {
  64. activeIndex: 0,
  65. child: []
  66. }
  67. }
  68. },
  69. keyName: {
  70. type: String,
  71. default: 'label'
  72. }
  73. },
  74. data() {
  75. return {
  76. show: false,
  77. rect: {},
  78. height: 0
  79. }
  80. },
  81. computed: {
  82. overlayStyle() {
  83. let { height = 0, top = 0 } = this.rect;
  84. // #ifdef H5
  85. top += this.$uv.sys().windowTop;
  86. // #endif
  87. const style = {
  88. position: 'fixed',
  89. top: `${top+height}px`,
  90. left: 0,
  91. right: 0,
  92. zIndex: this.zIndex,
  93. bottom: 0,
  94. 'background-color': `rgba(0, 0, 0, ${this.opacity})`
  95. }
  96. return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
  97. },
  98. list() {
  99. try {
  100. return Array.isArray(this.currentDropItem.child) ? this.currentDropItem.child : [];
  101. } catch (e) {
  102. return [];
  103. }
  104. },
  105. getTextColor(index) {
  106. return index => {
  107. const active = this.currentDropItem.activeIndex == index;
  108. const color = this.currentDropItem.color;
  109. const activeColor = this.currentDropItem.activeColor;
  110. if (active) {
  111. return activeColor ? activeColor : '#3c9cff';
  112. }
  113. return color ? color : '#333';
  114. }
  115. },
  116. getTextSize(index) {
  117. return index => {
  118. const active = this.currentDropItem.activeIndex == index;
  119. const size = this.currentDropItem.size;
  120. const activeSize = this.currentDropItem.activeSize;
  121. if (active) {
  122. return activeSize ? activeSize : '30rpx';
  123. }
  124. return size ? size : '30rpx';
  125. }
  126. },
  127. itemCustomStyle() {
  128. return index => {
  129. const active = this.currentDropItem.activeIndex == index;
  130. const style = {};
  131. if (active && this.currentDropItem.itemActiveCustomStyle) {
  132. return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemActiveCustomStyle));
  133. }
  134. if (this.currentDropItem.itemCustomStyle) {
  135. return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemCustomStyle))
  136. }
  137. return style;
  138. }
  139. }
  140. },
  141. created() {
  142. this.init();
  143. },
  144. methods: {
  145. blockClick() {},
  146. clickHandler(item, index) {
  147. this.currentDropItem.activeIndex = index;
  148. this.$emit('clickItem', item);
  149. this.close();
  150. },
  151. init() {
  152. uni.$off(`${this.sign}_GETRECT`);
  153. uni.$on(`${this.sign}_GETRECT`, rect => {
  154. this.rect = rect;
  155. })
  156. uni.$off(`${this.sign}_CLICKMENU`);
  157. uni.$on(`${this.sign}_CLICKMENU`, async res => {
  158. if (res.show) {
  159. this.open();
  160. } else {
  161. this.close();
  162. }
  163. })
  164. },
  165. open() {
  166. this.show = true;
  167. this.$nextTick(async () => {
  168. // #ifndef H5 || MP-WEIXIN
  169. await this.$uv.sleep(60);
  170. // #endif
  171. const res = await this.queryRect();
  172. // #ifndef APP-NVUE
  173. this.height = res.height;
  174. // #endif
  175. // #ifdef APP-NVUE
  176. this.animation(res.height);
  177. // #endif
  178. this.$emit('popupChange', { show: true });
  179. })
  180. },
  181. close() {
  182. if(!this.show) return;
  183. this.height = 0;
  184. // #ifndef APP-NVUE
  185. this.height = 0;
  186. // #endif
  187. // #ifdef APP-NVUE
  188. this.animation(0);
  189. // #endif
  190. this.show = false;
  191. uni.$emit(`${this.sign}_CLOSEPOPUP`);
  192. this.$emit('popupChange', { show: false });
  193. },
  194. clickOverlay() {
  195. if (this.clickOverlayOnClose) {
  196. this.close();
  197. }
  198. },
  199. // 查询内容高度
  200. queryRect() {
  201. // #ifndef APP-NVUE
  202. // 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
  203. return new Promise(resolve => {
  204. this.$uvGetRect(`.uv-dp__container__list`).then(size => {
  205. resolve(size)
  206. })
  207. })
  208. // #endif
  209. // #ifdef APP-NVUE
  210. // nvue下,使用dom模块查询元素高度
  211. // 返回一个promise,让调用此方法的主体能使用then回调
  212. return new Promise(resolve => {
  213. dom.getComponentRect(this.$refs.uvDPList, res => {
  214. resolve(res.size)
  215. })
  216. })
  217. // #endif
  218. },
  219. // nvue下设置高度
  220. animation(height, duration = 200) {
  221. // #ifdef APP-NVUE
  222. const ref = this.$refs['uvDPContainer'];
  223. animation.transition(ref, {
  224. styles: {
  225. height: `${height}px`
  226. },
  227. duration
  228. })
  229. // #endif
  230. }
  231. }
  232. }
  233. </script>
  234. <style scoped lang="scss">
  235. .uv-dp__container {
  236. /* #ifndef APP-NVUE */
  237. overflow: hidden;
  238. transition: all .15s;
  239. /* #endif */
  240. background-color: #fff;
  241. max-height: 40vh;
  242. }
  243. .uv-dp__container__list {
  244. &--item {
  245. padding: 20rpx 60rpx;
  246. }
  247. }
  248. </style>