u-switch.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <view :class="[value == true ? 'u-switch--on' : '', disabled ? 'u-switch--disabled' : '']" :style="[switchStyle]"
  3. class="u-switch"
  4. @tap="onClick">
  5. <view :style="{
  6. width: $u.addUnit(this.size),
  7. height: $u.addUnit(this.size)
  8. }" class="u-switch__node node-class">
  9. <u-loading :color="loadingColor" :show="loading" :size="size * 0.6" class="u-switch__loading"/>
  10. </view>
  11. </view>
  12. </template>
  13. <script>
  14. /**
  15. * switch 开关选择器
  16. * @description 选择开关一般用于只有两个选择,且只能选其一的场景。
  17. * @tutorial https://www.uviewui.com/components/switch.html
  18. * @property {Boolean} loading 是否处于加载中(默认false)
  19. * @property {Boolean} disabled 是否禁用(默认false)
  20. * @property {String Number} size 开关尺寸,单位rpx(默认50)
  21. * @property {String} active-color 打开时的背景色(默认#2979ff)
  22. * @property {Boolean} inactive-color 关闭时的背景色(默认#ffffff)
  23. * @property {Boolean | Number | String} active-value 打开选择器时通过change事件发出的值(默认true)
  24. * @property {Boolean | Number | String} inactive-value 关闭选择器时通过change事件发出的值(默认false)
  25. * @event {Function} change 在switch打开或关闭时触发
  26. * @example <u-switch v-model="checked" active-color="red" inactive-color="#eee"></u-switch>
  27. */
  28. export default {
  29. name: "u-switch",
  30. props: {
  31. // 是否为加载中状态
  32. loading: {
  33. type: Boolean,
  34. default: false
  35. },
  36. // 是否为禁用装填
  37. disabled: {
  38. type: Boolean,
  39. default: false
  40. },
  41. // 开关尺寸,单位rpx
  42. size: {
  43. type: [Number, String],
  44. default: 50
  45. },
  46. // 打开时的背景颜色
  47. activeColor: {
  48. type: String,
  49. default: '#2979ff'
  50. },
  51. // 关闭时的背景颜色
  52. inactiveColor: {
  53. type: String,
  54. default: '#ffffff'
  55. },
  56. // 通过v-model双向绑定的值
  57. value: {
  58. type: Boolean,
  59. default: false
  60. },
  61. // 是否使手机发生短促震动,目前只在iOS的微信小程序有效(2020-05-06)
  62. vibrateShort: {
  63. type: Boolean,
  64. default: false
  65. },
  66. // 打开选择器时的值
  67. activeValue: {
  68. type: [Number, String, Boolean],
  69. default: true
  70. },
  71. // 关闭选择器时的值
  72. inactiveValue: {
  73. type: [Number, String, Boolean],
  74. default: false
  75. },
  76. },
  77. data() {
  78. return {}
  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: 50 rpx;
  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>