推广小程序前端代码
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.

259 lines
6.7 KiB

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