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.

163 lines
4.5 KiB

3 years ago
  1. <template>
  2. <view class="u-switch" :class="[value == true ? 'u-switch--on' : '', disabled ? 'u-switch--disabled' : '']" @tap="onClick"
  3. :style="[switchStyle]">
  4. <view class="u-switch__node node-class" :style="{
  5. width: $u.addUnit(this.size),
  6. height: $u.addUnit(this.size)
  7. }">
  8. <u-loading :show="loading" class="u-switch__loading" :size="size * 0.6" :color="loadingColor" />
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. /**
  14. * switch 开关选择器
  15. * @description 选择开关一般用于只有两个选择且只能选其一的场景
  16. * @tutorial https://www.uviewui.com/components/switch.html
  17. * @property {Boolean} loading 是否处于加载中默认false
  18. * @property {Boolean} disabled 是否禁用默认false
  19. * @property {String Number} size 开关尺寸单位rpx默认50
  20. * @property {String} active-color 打开时的背景色默认#2979ff
  21. * @property {Boolean} inactive-color 关闭时的背景色默认#ffffff
  22. * @property {Boolean | Number | String} active-value 打开选择器时通过change事件发出的值默认true
  23. * @property {Boolean | Number | String} inactive-value 关闭选择器时通过change事件发出的值默认false
  24. * @event {Function} change 在switch打开或关闭时触发
  25. * @example <u-switch v-model="checked" active-color="red" inactive-color="#eee"></u-switch>
  26. */
  27. export default {
  28. name: "u-switch",
  29. props: {
  30. // 是否为加载中状态
  31. loading: {
  32. type: Boolean,
  33. default: false
  34. },
  35. // 是否为禁用装填
  36. disabled: {
  37. type: Boolean,
  38. default: false
  39. },
  40. // 开关尺寸,单位rpx
  41. size: {
  42. type: [Number, String],
  43. default: 50
  44. },
  45. // 打开时的背景颜色
  46. activeColor: {
  47. type: String,
  48. default: '#2979ff'
  49. },
  50. // 关闭时的背景颜色
  51. inactiveColor: {
  52. type: String,
  53. default: '#ffffff'
  54. },
  55. // 通过v-model双向绑定的值
  56. value: {
  57. type: Boolean,
  58. default: false
  59. },
  60. // 是否使手机发生短促震动,目前只在iOS的微信小程序有效(2020-05-06)
  61. vibrateShort: {
  62. type: Boolean,
  63. default: false
  64. },
  65. // 打开选择器时的值
  66. activeValue: {
  67. type: [Number, String, Boolean],
  68. default: true
  69. },
  70. // 关闭选择器时的值
  71. inactiveValue: {
  72. type: [Number, String, Boolean],
  73. default: false
  74. },
  75. },
  76. data() {
  77. return {
  78. }
  79. },
  80. computed: {
  81. switchStyle() {
  82. let style = {};
  83. style.fontSize = this.size + 'rpx';
  84. style.backgroundColor = this.value ? this.activeColor : this.inactiveColor;
  85. return style;
  86. },
  87. loadingColor() {
  88. return this.value ? this.activeColor : null;
  89. }
  90. },
  91. methods: {
  92. onClick() {
  93. if (!this.disabled && !this.loading) {
  94. // 使手机产生短促震动,微信小程序有效,APP(HX 2.6.8)和H5无效
  95. if(this.vibrateShort) uni.vibrateShort();
  96. this.$emit('input', !this.value);
  97. // 放到下一个生命周期,因为双向绑定的value修改父组件状态需要时间,且是异步的
  98. this.$nextTick(() => {
  99. this.$emit('change', this.value ? this.activeValue : this.inactiveValue);
  100. })
  101. }
  102. }
  103. }
  104. };
  105. </script>
  106. <style lang="scss" scoped>
  107. @import "../../libs/css/style.components.scss";
  108. .u-switch {
  109. position: relative;
  110. /* #ifndef APP-NVUE */
  111. display: inline-block;
  112. /* #endif */
  113. box-sizing: initial;
  114. width: 2em;
  115. height: 1em;
  116. background-color: #fff;
  117. border: 1px solid rgba(0, 0, 0, 0.1);
  118. border-radius: 1em;
  119. transition: background-color 0.3s;
  120. font-size: 50rpx;
  121. }
  122. .u-switch__node {
  123. @include vue-flex;
  124. align-items: center;
  125. justify-content: center;
  126. position: absolute;
  127. top: 0;
  128. left: 0;
  129. border-radius: 100%;
  130. z-index: 1;
  131. background-color: #fff;
  132. background-color: #fff;
  133. box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);
  134. box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);
  135. transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);
  136. transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05), -webkit-transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);
  137. transition: transform cubic-bezier(0.3, 1.05, 0.4, 1.05);
  138. transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05)
  139. }
  140. .u-switch__loading {
  141. @include vue-flex;
  142. align-items: center;
  143. justify-content: center;
  144. }
  145. .u-switch--on {
  146. background-color: #1989fa;
  147. }
  148. .u-switch--on .u-switch__node {
  149. transform: translateX(100%);
  150. }
  151. .u-switch--disabled {
  152. opacity: 0.4;
  153. }
  154. </style>