u-switch.vue 4.7 KB

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