cc-dropDownMenu.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <template>
  2. <view style="width: 100%;">
  3. <view class="screen-bar" :style="{'height':height + 'rpx',backgroundColor:bgcolor}">
  4. <view class="screen-bar-item" @tap.stop="itemClick(index)" v-for="(item,index) in updateArr" :key="index"
  5. :style="{'width':(100/titleArr.length)+'%','fontSize':barFontSize+'rpx','color':(currentIndex==index&&show)?activeColor:barTextColor}">
  6. <view class="bar-item-text">
  7. {{item}}
  8. </view>
  9. <image :src="arrBase64"
  10. :style="{'transform': show?currentIndex==index? 'rotate(180deg)':'rotate(0)':'rotate(0)'}"></image>
  11. </view>
  12. <view class="dropdown-box"
  13. :style="{'bottom':'-' + (itemHeight*maxDropdownLength) + 'rpx','height':(itemHeight*maxDropdownLength) + 'rpx',backgroundColor:bgcolor,'opacity':show?'1':'0','display':show?'block':'none'}">
  14. <scroll-view scroll-y="true" style="height: 100%;">
  15. <view class="dropdown-item"
  16. :style="{'height':itemHeight+'rpx','paddingLeft':itemPadding+'rpx','fontSize':itemFontSize+'rpx','color':itemTextColor}"
  17. v-for="(item,index) in dropArr[currentIndex]" :key="index" @tap.stop="subItemClick(index)">
  18. {{item[showTag]}}
  19. </view>
  20. </scroll-view>
  21. </view>
  22. </view>
  23. <view class="bg-mask" :class="[show?'bg-mask-show':'']" @tap="maskClose" @touchmove="touchControl"></view>
  24. </view>
  25. </template>
  26. <script>
  27. /**
  28. * 下拉组件
  29. * @author xzj
  30. * @create date 2021-4-3
  31. * @update user xzj
  32. * @update date 2021-4-3
  33. * @note 遮罩层级98 筛选条&下拉层层级99
  34. **/
  35. export default {
  36. data() {
  37. return {
  38. // 主条目选择序列
  39. currentIndex: 0,
  40. // 下拉条目序列
  41. currentSubIndex: 0,
  42. show: false,
  43. // 更新数组
  44. updateArr: [],
  45. // 结果数组
  46. resultArr: [],
  47. arrBase64: 'data:image/png;base64,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'
  48. };
  49. },
  50. computed: {
  51. maxDropdownLength() {
  52. return this.dropArr[this.currentIndex].length > this.maxItemCount ? this.maxItemCount : this.dropArr[this
  53. .currentIndex].length
  54. }
  55. },
  56. props: {
  57. // 筛选条高度 (rpx)
  58. height: {
  59. type: Number,
  60. default: 92
  61. },
  62. // 下拉单项高度
  63. itemHeight: {
  64. type: Number,
  65. default: 88
  66. },
  67. // 当前文字活跃颜色
  68. activeColor: {
  69. type: String,
  70. default: '#0377fc'
  71. },
  72. //背景颜色
  73. bgcolor: {
  74. type: String,
  75. default: '#fff'
  76. },
  77. //下拉标题数组
  78. titleArr: {
  79. type: Array,
  80. default: () => {
  81. return []
  82. }
  83. },
  84. // item数量超过多少开始滚动
  85. maxItemCount: {
  86. type: Number,
  87. default: 6
  88. },
  89. //下拉选项数组(二维数组)
  90. dropArr: {
  91. type: Array,
  92. default: () => {
  93. return []
  94. }
  95. },
  96. // 选项左偏移
  97. itemPadding: {
  98. type: Number,
  99. default: 24
  100. },
  101. // 能否遮罩关闭
  102. maskTouch: {
  103. type: Boolean,
  104. default: true
  105. },
  106. // 是否需要选择后替换标题
  107. isNeedChangeTitle: {
  108. type: Boolean,
  109. default: true
  110. },
  111. // 标题字号
  112. barFontSize: {
  113. type: Number,
  114. default: 26
  115. },
  116. //标题颜色
  117. barTextColor: {
  118. type: String,
  119. default: '#666'
  120. },
  121. //下拉字号
  122. itemFontSize: {
  123. type: Number,
  124. default: 26
  125. },
  126. // 下拉文字颜色
  127. itemTextColor: {
  128. type: String,
  129. default: '#666'
  130. },
  131. // 需要展示的字段,比如你的数据是item.name 这里填的就是name
  132. showTag: {
  133. type: String,
  134. default: 'text'
  135. },
  136. // 是否要滑动关闭
  137. isTouchPrevent: {
  138. type: Boolean,
  139. default: true
  140. },
  141. // 自定义事件的索引数组
  142. customIndexArr: {
  143. type: Array,
  144. default: () => {
  145. return []
  146. }
  147. }
  148. },
  149. mounted() {
  150. // 设置更新数组与列表数组同长度
  151. this.updateArr = [...new Set(this.titleArr)]
  152. // 设置结果数组与列表数组同长度
  153. this.resultArr = new Array(this.titleArr.length).fill('');
  154. },
  155. methods: {
  156. itemClick(index) {
  157. if (this.customIndexArr.includes(index)) {
  158. this.show = false
  159. this.$emit('customClick', {
  160. '$index': index
  161. })
  162. return
  163. }
  164. if (this.currentIndex == index) {
  165. this.show = !this.show
  166. } else {
  167. this.currentIndex = index
  168. this.show = true
  169. }
  170. },
  171. subItemClick(index) {
  172. this.currentSubIndex = index
  173. if (this.isNeedChangeTitle) {
  174. this.updateArr.splice(this.currentIndex, 1, this.dropArr[this.currentIndex][this.currentSubIndex][this
  175. .showTag
  176. ])
  177. }
  178. this.resultArr.splice(this.currentIndex, 1, this.dropArr[this.currentIndex][this.currentSubIndex].value);
  179. this.$emit('finishDropClick', this.resultArr)
  180. console.log('更新数组 = ' + JSON.stringify(this.resultArr));
  181. this.show = false
  182. },
  183. maskClose() {
  184. if (!this.maskTouch) return
  185. this.show = false
  186. },
  187. //
  188. touchControl() {
  189. if (this.isTouchPrevent) {
  190. this.maskClose()
  191. }
  192. }
  193. }
  194. }
  195. </script>
  196. <style>
  197. .screen-bar {
  198. width: 100%;
  199. display: flex;
  200. position: relative;
  201. z-index: 99;
  202. }
  203. .screen-bar::after {
  204. position: absolute;
  205. content: '';
  206. width: 100%;
  207. height: 1rpx;
  208. background-color: #EEEEEE;
  209. bottom: -1rpx;
  210. left: 0;
  211. z-index: 99;
  212. }
  213. .screen-bar-item {
  214. height: 100%;
  215. display: flex;
  216. align-items: center;
  217. justify-content: center;
  218. }
  219. .screen-bar-item image {
  220. width: 24rpx;
  221. height: 24rpx;
  222. display: block;
  223. margin-left: 12rpx;
  224. transition: all .3s;
  225. flex-shrink: 0;
  226. }
  227. .dropdown-box {
  228. width: 100%;
  229. position: absolute;
  230. left: 0;
  231. z-index: 99;
  232. overflow: hidden;
  233. }
  234. .dropdown-item {
  235. width: 100%;
  236. display: flex;
  237. align-items: center;
  238. padding: 0 30rpx;
  239. box-sizing: border-box;
  240. font-size: 26rpx;
  241. color: #111111;
  242. border-bottom: 1rpx solid #EEEEEE;
  243. }
  244. .bg-mask {
  245. position: fixed;
  246. top: 0;
  247. left: 0;
  248. right: 0;
  249. bottom: 0;
  250. background: rgba(0, 0, 0, 0.3);
  251. z-index: 98;
  252. transition: all 0.3s ease-in-out;
  253. opacity: 0;
  254. visibility: hidden;
  255. }
  256. .bg-mask-show {
  257. visibility: visible;
  258. opacity: 1;
  259. }
  260. .bar-item-text {
  261. max-width: 120rpx;
  262. text-overflow: ellipsis;
  263. overflow: hidden;
  264. white-space: nowrap;
  265. }
  266. </style>