fs-cell.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <template>
  2. <view
  3. class="fs-cell"
  4. :class="[cls,{shadow}]"
  5. :style="{backgroundColor:bgColor}"
  6. @click="handleClick"
  7. >
  8. <view class="fs-cell-flex" :class="['fs-cell-align-' + align, justify,{reverse}]">
  9. <view class="fs-cell-title" :class="{ 'fs-cell-required': required }" :style="titleStyle">
  10. <template v-if="title">{{title}}</template>
  11. <slot v-else name="title"></slot>
  12. </view>
  13. <view class="fs-cell-value">
  14. <template v-if="value">{{value}}</template>
  15. <slot v-else name="value"></slot>
  16. </view>
  17. <view class="fs-cell-extra">
  18. <template v-if="extra">{{extra}}</template>
  19. <slot v-else name="extra"></slot>
  20. </view>
  21. </view>
  22. <view class="fs-cell-label">
  23. <template v-if="label">{{label}}</template>
  24. <slot v-else name="label"></slot>
  25. </view>
  26. <view class="arrow-icon">
  27. <fs-icon type="icon-d-down" rotate="-90" size="28rpx" :color="arrowColor" :colorType="arrowColorType"></fs-icon>
  28. </view>
  29. </view>
  30. </template>
  31. <script setup>
  32. import { computed, toRefs, inject } from 'vue'
  33. const props = defineProps({
  34. title: String,
  35. titleWidth: String,
  36. value: String,
  37. extra: String,
  38. label: String,
  39. arrow: Boolean,
  40. arrowColor: {
  41. type: String,
  42. default: '#E8EAF2'
  43. },
  44. arrowColorType: {
  45. type: String,
  46. validator(value) {
  47. return ['primary', 'success', 'info', 'warning', 'danger'].includes(value)
  48. }
  49. },
  50. border: Boolean,
  51. tighten: Boolean,
  52. gutter: Boolean,
  53. radius: Boolean,
  54. reverse: Boolean,
  55. required: Boolean,
  56. align: {
  57. type: String,
  58. default: 'center',
  59. validator(value) {
  60. return ['top', 'center', 'bottom', 'stretch'].includes(value)
  61. }
  62. },
  63. justify: {
  64. type: String,
  65. validator(value) {
  66. return ['left', 'center', 'right'].includes(value)
  67. }
  68. },
  69. bgColor: {
  70. type: String,
  71. },
  72. shadow: Boolean,
  73. link: String,
  74. linkType: {
  75. type: String,
  76. default: 'navigateTo'
  77. },
  78. })
  79. const emits = defineEmits(['click'])
  80. const cellGroup = inject('cellGroup', {})
  81. const justify = props.justify || cellGroup.justify || 'left'
  82. const bgColor = props.bgColor || cellGroup.bgColor || '#fff'
  83. const arrowColor = props.arrowColor || cellGroup.arrowColor
  84. const arrowColorType = props.arrowColorType || cellGroup.arrowColorType
  85. const cls = computed(() => {
  86. const classNames = [];
  87. (props.arrow || cellGroup.arrow) && classNames.push('arrow');
  88. (props.border || cellGroup.border) && classNames.push('border');
  89. (props.tighten || cellGroup.tighten) && classNames.push('tighten')
  90. props.gutter && classNames.push('gutter')
  91. props.radius && classNames.push('radius')
  92. return classNames.join(' ')
  93. })
  94. const titleStyle = computed(() => {
  95. const width = props.titleWidth || cellGroup.titleWidth
  96. return width ? `width: ${width}` : ''
  97. })
  98. const handleClick = () => {
  99. if (props.link) {
  100. uni[props.linkType]({
  101. url: props.link
  102. })
  103. }
  104. emits('click')
  105. }
  106. </script>
  107. <style lang="scss" scoped>
  108. .fs-cell {
  109. padding: 30rpx var(--gutter);
  110. position: relative;
  111. font-size: var(--content-size);
  112. background-color: #fff;
  113. line-height: 1.4;
  114. width: 100%;
  115. box-sizing: border-box;
  116. &-flex {
  117. display: flex;
  118. justify-content: space-between;
  119. }
  120. &-value {
  121. flex: 1;
  122. padding-left: 20rpx;
  123. text-align: right;
  124. }
  125. &-label {
  126. font-size: var(--sub-size);
  127. color: var(--sub);
  128. }
  129. &-align-top {
  130. align-items: flex-start;
  131. }
  132. &-align-center {
  133. align-items: center;
  134. }
  135. &-align-bottom {
  136. align-items: flex-end;
  137. }
  138. &.arrow {
  139. padding-right: 50rpx;
  140. .arrow-icon{
  141. display: block;
  142. }
  143. }
  144. &-required{
  145. position: relative;
  146. padding-left: 7px;
  147. &::before{
  148. position: absolute;
  149. content: '*';
  150. color: red;
  151. left: 0;
  152. }
  153. }
  154. &.gutter {
  155. margin-bottom: var(--gutter-v);
  156. }
  157. &.radius {
  158. border-radius: var(--radius);
  159. }
  160. &.reverse{
  161. flex-direction: row-reverse;
  162. }
  163. &.tighten {
  164. padding: var(--tighten-gutter);
  165. }
  166. &.border {
  167. border-bottom: 2rpx solid var(--border-color);
  168. }
  169. }
  170. .arrow-icon{
  171. display: none;
  172. position: absolute;
  173. right: 10rpx;
  174. top: 50%;
  175. transform: translateY(-50%);
  176. }
  177. .left .fs-cell-value {
  178. text-align: left;
  179. }
  180. .center .fs-cell-value {
  181. text-align: center;
  182. }
  183. .right .fs-cell-value {
  184. text-align: right;
  185. }
  186. </style>