multiple-picker.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <view class="popup" v-show="show">
  3. <view class="bg" @tap="cancelMultiple"></view>
  4. <view class="selectMultiple" :animation="animationData">
  5. <view class="multipleBody">
  6. <view class="title">
  7. <view class="close" @tap="cancelMultiple">
  8. 取消
  9. </view>
  10. <view class="name">
  11. {{title}}
  12. </view>
  13. <view class="confirm" @tap="confirmMultiple">
  14. 确认
  15. </view>
  16. </view>
  17. <view class="list">
  18. <view class="mask mask-top"></view>
  19. <view class="mask mask-bottom"></view>
  20. <scroll-view class="diet-list" scroll-y="true">
  21. <view v-for="(item, index) in list" :class="['item', item.selected ? 'checked' : '']" @tap="onChange(index, item)">
  22. <span>{{item.label}}</span>
  23. <view class="icon" v-show="item.selected">
  24. <icon type="success_no_circle" size="16" color="#2D8DFF"/>
  25. </view>
  26. </view>
  27. </scroll-view>
  28. </view>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. export default {
  35. name:"multiple-picker",
  36. data() {
  37. return {
  38. // 选中值
  39. value: [],
  40. // 选中列表
  41. selected: [],
  42. // 列表数据
  43. list: [],
  44. // 出场动画
  45. animationData: {},
  46. };
  47. },
  48. props: {
  49. // 是否显示
  50. show: {
  51. type: Boolean,
  52. default: false
  53. },
  54. // 标题
  55. title: {
  56. type: String,
  57. default: ''
  58. },
  59. //数据列表
  60. columns: {
  61. type: Array,
  62. default: [
  63. {
  64. label: '测试1',
  65. value: '1',
  66. }
  67. ]
  68. },
  69. // 默认选中
  70. defaultIndex: {
  71. type: Array,
  72. default: [],
  73. }
  74. },
  75. watch: {
  76. // 监听是否显示
  77. show(val) {
  78. if(val) {
  79. this.openMultiple();
  80. }
  81. }
  82. },
  83. methods: {
  84. // 列点击事件
  85. onChange(index, item) {
  86. // 是否已选中
  87. if(this.value.indexOf(item.value.toString()) >= 0) {
  88. this.list[index].selected = false;
  89. }
  90. else {
  91. this.list[index].selected = true;
  92. }
  93. // 筛选已勾选数据
  94. this.value = [];
  95. this.selected = [];
  96. this.list.forEach((col_item, col_index) => {
  97. if(col_item.selected) {
  98. this.value.push(col_item.value.toString());
  99. this.selected.push({
  100. label: col_item.label,
  101. value: col_item.value,
  102. });
  103. }
  104. });
  105. this.$emit("change", {selected: this.selected, value: this.value});
  106. },
  107. // 弹出框开启触发事件
  108. openMultiple() {
  109. // 初始化列表数据,默认勾选数据
  110. this.value = this.defaultIndex;
  111. this.columns.forEach((item, index) => {
  112. this.$set(item, "selected", false);
  113. if(this.value.indexOf(item.value.toString()) >= 0) {
  114. item.selected = true;
  115. }
  116. });
  117. this.list = Object.assign([], this.columns);
  118. // 弹出动画
  119. this.openAnimation();
  120. },
  121. // 确认
  122. confirmMultiple() {
  123. this.$emit("confirm", {selected: this.selected, value: this.value});
  124. },
  125. // 关闭/取消
  126. cancelMultiple() {
  127. this.$emit("cancel");
  128. },
  129. // 展开动画
  130. openAnimation() {
  131. var animation = uni.createAnimation()
  132. animation.translate(0, 300).step({ duration: 0 });
  133. this.animationData = animation.export();
  134. this.$nextTick(() => {
  135. animation.translate(0, 0).step({ duration: 300, timingFunction: 'ease' });
  136. this.animationData = animation.export()
  137. })
  138. },
  139. }
  140. }
  141. </script>
  142. <style scoped lang="scss">
  143. .popup {
  144. width: 100%;
  145. height: 100vh;
  146. position: fixed;
  147. z-index: 99999;
  148. left: 0;
  149. bottom: 0;
  150. .bg {
  151. width: 100%;
  152. height: 100%;
  153. background-color: rgba(black, .5);
  154. }
  155. }
  156. .selectMultiple {
  157. width: 100%;
  158. position: absolute;
  159. left: 0;
  160. bottom: 0;
  161. background-color: white;
  162. .multipleBody {
  163. width: 100%;
  164. padding: 30rpx;
  165. box-sizing: border-box;
  166. padding-bottom: 80rpx;
  167. .title {
  168. font-size: 28rpx;
  169. display: flex;
  170. flex-direction: row;
  171. .close {
  172. width: 80rpx;
  173. opacity: .5;
  174. }
  175. .name {
  176. width: 530rpx;
  177. text-align: center;
  178. overflow: hidden;
  179. display: -webkit-box;
  180. -webkit-box-orient:vertical;
  181. -webkit-line-clamp:1;
  182. }
  183. .confirm {
  184. width: 80rpx;
  185. text-align: right;
  186. color: #2D8DFF;
  187. }
  188. }
  189. .list {
  190. width: 100%;
  191. padding-top: 30rpx;
  192. position: relative;
  193. .mask {
  194. width: 100%;
  195. height: 120rpx;
  196. position: absolute;
  197. left: 0;
  198. z-index: 2;
  199. pointer-events: none;
  200. &.mask-top {
  201. top: 30rpx;
  202. background-image: linear-gradient(to bottom, #fff, rgba(#fff, 0));
  203. }
  204. &.mask-bottom {
  205. bottom: 0;
  206. background-image: linear-gradient(to bottom, rgba(#fff, 0), #fff);
  207. }
  208. }
  209. .diet-list {
  210. max-height: 400rpx;
  211. }
  212. .item {
  213. position: relative;
  214. width: 100%;
  215. line-height: 40rpx;
  216. border-bottom: 1px solid rgba($color: #000000, $alpha: .05);
  217. padding: 20rpx 0;
  218. font-size: 30rpx;
  219. box-sizing: border-box;
  220. text-align: center;
  221. span {
  222. overflow: hidden;
  223. display: -webkit-box;
  224. -webkit-box-orient:vertical;
  225. -webkit-line-clamp:1;
  226. padding: 0 40rpx;
  227. }
  228. .icon {
  229. position: absolute;
  230. right: 10rpx;
  231. top: 50%;
  232. transform: translateY(-50%);
  233. height: 16px;
  234. }
  235. &.checked {
  236. color: #2D8DFF;
  237. }
  238. &:last-child {
  239. border-bottom: none;
  240. margin-bottom: 60rpx;
  241. }
  242. &:first-child {
  243. margin-top: 60rpx;
  244. }
  245. }
  246. }
  247. }
  248. }
  249. </style>