index.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <template>
  2. <view :class="['lb-picker', inline ? 'lb-picker-inline' : '']">
  3. <view class="lb-picker-mask"
  4. v-show="visible && !inline"
  5. :style="{ 'background-color': maskColor }"
  6. @tap.stop="handleMaskTap"
  7. @touchmove.stop.prevent="moveHandle">
  8. </view>
  9. <view :class="['lb-picker-container', visible ? 'lb-picker-toggle' : '']"
  10. :style="{ borderRadius: `${radius} ${radius} 0 0` }">
  11. <view v-if="showHeader"
  12. class="lb-picker-header"
  13. :style="{
  14. height: pickerHeaderHeight,
  15. 'line-height': pickerHeaderHeight
  16. }">
  17. <view class="lb-picker-action lb-picker-left">
  18. <view class="lb-picker-action-cancel"
  19. @tap.stop="handleCancel">
  20. <slot v-if="$slots['cancel-text']"
  21. name="cancel-text"> </slot>
  22. <view v-else
  23. class="action-cancel-text"
  24. :style="{ color: cancelColor }" style="font-size: 28rpx;">
  25. {{ cancelText }}
  26. </view>
  27. </view>
  28. </view>
  29. <view class="lb-picker-action lb-picker-center"
  30. v-if="$slots['action-center']">
  31. <slot name="action-center"></slot>
  32. </view>
  33. <view class="lb-picker-action lb-picker-right">
  34. <view class="lb-picker-action-confirm"
  35. @tap.stop="handleConfirm">
  36. <slot v-if="$slots['confirm-text']"
  37. name="confirm-text"> </slot>
  38. <view v-else
  39. class="action-confirm-text"
  40. style="font-size: 28rpx;color: #FA6400;">
  41. {{ confirmText }}
  42. </view>
  43. </view>
  44. </view>
  45. </view>
  46. <view class="lb-picker-content"
  47. :style="{ height: pickerContentHeight }">
  48. <!-- loading -->
  49. <view v-if="loading"
  50. class="lb-picker-loading">
  51. <slot name="loading">
  52. <view class="lb-picker-loading-img"></view>
  53. </slot>
  54. </view>
  55. <!-- 暂无数据 -->
  56. <view v-if="isEmpty && !loading"
  57. class="lb-picker-empty">
  58. <slot name="empty">
  59. <text class="lb-picker-empty-text"
  60. :style="{ color: emptyColor }">
  61. {{ emptyText }}
  62. </text>
  63. </slot>
  64. </view>
  65. <!-- 单选 -->
  66. <selector-picker v-if="mode === 'selector' && !loading && !isEmpty"
  67. :value="value"
  68. :list="list"
  69. :props="pickerProps"
  70. :height="pickerContentHeight"
  71. :inline="inline"
  72. @change="handleChange">
  73. </selector-picker>
  74. <!-- 多列联动 -->
  75. <multi-selector-picker v-if="mode === 'multiSelector' && !loading && !isEmpty"
  76. :value="value"
  77. :list="list"
  78. :level="level"
  79. :visible="visible"
  80. :props="pickerProps"
  81. :height="pickerContentHeight"
  82. :inline="inline"
  83. @change="handleChange">
  84. </multi-selector-picker>
  85. <!-- 非联动选择 -->
  86. <unlinked-selector-picker v-if="mode === 'unlinkedSelector' && !loading && !isEmpty"
  87. :value="value"
  88. :list="list"
  89. :visible="visible"
  90. :props="pickerProps"
  91. :height="pickerContentHeight"
  92. :inline="inline"
  93. @change="handleChange">
  94. </unlinked-selector-picker>
  95. </view>
  96. </view>
  97. </view>
  98. </template>
  99. <script>
  100. const defaultProps = {
  101. label: 'label',
  102. value: 'value',
  103. children: 'children'
  104. }
  105. import { getIndicatorHeight } from './utils'
  106. import SelectorPicker from './pickers/selector-picker'
  107. import MultiSelectorPicker from './pickers/multi-selector-picker'
  108. import UnlinkedSelectorPicker from './pickers/unlinked-selector-picker'
  109. const indicatorHeight = getIndicatorHeight()
  110. export default {
  111. components: {
  112. SelectorPicker,
  113. MultiSelectorPicker,
  114. UnlinkedSelectorPicker
  115. },
  116. props: {
  117. value: [String, Number, Array],
  118. list: Array,
  119. mode: {
  120. type: String,
  121. default: 'selector'
  122. },
  123. level: {
  124. type: Number,
  125. default: 1
  126. },
  127. props: {
  128. type: Object
  129. },
  130. cancelText: {
  131. type: String,
  132. default: '取消'
  133. },
  134. cancelColor: String,
  135. confirmText: {
  136. type: String,
  137. default: '确定'
  138. },
  139. confirmColor: '#FA6400',
  140. canHide: {
  141. type: Boolean,
  142. default: true
  143. },
  144. emptyColor: String,
  145. emptyText: {
  146. type: String,
  147. default: '暂无数据'
  148. },
  149. radius: String,
  150. columnNum: {
  151. type: Number,
  152. default: 5
  153. },
  154. loading: Boolean,
  155. closeOnClickMask: {
  156. type: Boolean,
  157. default: true
  158. },
  159. maskColor: {
  160. type: String,
  161. default: 'rgba(0, 0, 0, 0.4)'
  162. },
  163. dataset: Object,
  164. inline: Boolean,
  165. showHeader: {
  166. type: Boolean,
  167. default: true
  168. }
  169. },
  170. data () {
  171. return {
  172. visible: false,
  173. myValue: this.value,
  174. picker: {},
  175. pickerProps: Object.assign({}, defaultProps, this.props),
  176. pickerHeaderHeight: indicatorHeight + 'px',
  177. pickerContentHeight: indicatorHeight * this.columnNum + 'px'
  178. }
  179. },
  180. computed: {
  181. isEmpty () {
  182. if (!this.list) return true
  183. if (this.list && !this.list.length) return true
  184. return false
  185. }
  186. },
  187. methods: {
  188. show () {
  189. if (this.inline) return
  190. this.visible = true
  191. },
  192. hide () {
  193. if (this.inline) return
  194. this.visible = false
  195. },
  196. handleCancel () {
  197. this.$emit('cancel', this.picker)
  198. if (this.canHide && !this.inline) {
  199. this.hide()
  200. }
  201. },
  202. handleConfirm () {
  203. if (this.isEmpty) {
  204. this.$emit('confirm', null)
  205. this.hide()
  206. } else {
  207. const picker = JSON.parse(JSON.stringify(this.picker))
  208. this.myValue = picker.value
  209. this.$emit('confirm', this.picker)
  210. if (this.canHide) this.hide()
  211. }
  212. },
  213. handleChange ({ value, item, index, change }) {
  214. this.picker.value = value
  215. this.picker.item = item
  216. this.picker.index = index
  217. this.picker.change = change
  218. this.picker.dataset = this.dataset || {}
  219. this.$emit('change', this.picker)
  220. },
  221. handleMaskTap () {
  222. if (this.closeOnClickMask) {
  223. this.visible = false
  224. this.$emit('visibleCityPicker', false)
  225. }
  226. },
  227. moveHandle () {}
  228. },
  229. watch: {
  230. value (newVal) {
  231. this.myValue = newVal
  232. },
  233. myValue (newVal) {
  234. this.$emit('input', newVal)
  235. },
  236. visible (newVisible) {
  237. if (newVisible) {
  238. this.$emit('show')
  239. } else {
  240. this.$emit('hide')
  241. }
  242. }
  243. }
  244. }
  245. </script>
  246. <style lang="scss" scoped>
  247. @import "./style/picker.scss";
  248. </style>