index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import baseComponent from '../helpers/baseComponent'
  2. import classNames from '../helpers/classNames'
  3. baseComponent({
  4. properties: {
  5. prefixCls: {
  6. type: String,
  7. value: 'wux-rater',
  8. },
  9. max: {
  10. type: Number,
  11. value: 5,
  12. observer() {
  13. this.updateValue()
  14. },
  15. },
  16. icon: {
  17. type: String,
  18. value: '',
  19. },
  20. star: {
  21. type: String,
  22. value: '★',
  23. },
  24. defaultValue: {
  25. type: Number,
  26. value: 0,
  27. },
  28. value: {
  29. type: Number,
  30. value: 0,
  31. observer(newVal) {
  32. if (this.data.controlled) {
  33. this.updateValue(newVal)
  34. }
  35. },
  36. },
  37. activeColor: {
  38. type: String,
  39. value: '#ffc900',
  40. },
  41. margin: {
  42. type: Number,
  43. value: 2,
  44. },
  45. fontSize: {
  46. type: Number,
  47. value: 25,
  48. },
  49. disabled: {
  50. type: Boolean,
  51. value: false,
  52. },
  53. allowHalf: {
  54. type: Boolean,
  55. value: false,
  56. },
  57. allowClear: {
  58. type: Boolean,
  59. value: false,
  60. },
  61. allowTouchMove: {
  62. type: Boolean,
  63. value: false,
  64. },
  65. controlled: {
  66. type: Boolean,
  67. value: false,
  68. },
  69. },
  70. data: {
  71. raterValue: 0,
  72. },
  73. computed: {
  74. classes() {
  75. const { prefixCls, disabled } = this.data
  76. const wrap = classNames(prefixCls, {
  77. [`${prefixCls}--disabled`]: disabled,
  78. })
  79. const star = `${prefixCls}__star`
  80. const box = `${prefixCls}__box`
  81. const inner = `${prefixCls}__inner`
  82. const outer = `${prefixCls}__outer`
  83. const icon = `${prefixCls}__icon`
  84. return {
  85. wrap,
  86. star,
  87. box,
  88. inner,
  89. outer,
  90. icon,
  91. }
  92. },
  93. },
  94. methods: {
  95. updateValue(value = this.data.raterValue) {
  96. const { max, activeColor } = this.data
  97. const stars = [...new Array(max)].map((_, i) => i)
  98. const raterValue = value <= 0 ? 0 : value > max ? max : value
  99. const colors = stars.reduce((a, _, i) => ([...a, i <= value - 1 ? activeColor : '#ccc']), [])
  100. const _val = raterValue.toString().split('.')
  101. const sliceValue = _val.length === 1 ? [_val[0], 0] : _val
  102. this.setData({
  103. stars,
  104. colors,
  105. raterValue,
  106. cutIndex: sliceValue[0] * 1,
  107. cutPercent: sliceValue[1] * 10,
  108. })
  109. },
  110. updateHalfStarValue(index, x, cb) {
  111. const { prefixCls } = this.data
  112. const query = wx.createSelectorQuery().in(this)
  113. query.selectAll(`.${prefixCls}__star`).boundingClientRect((rects) => {
  114. if (rects.filter((n) => !n).length) return
  115. const { left, width } = rects[index]
  116. const has = (x - left) < width / 2
  117. const value = has ? index + .5 : index + 1
  118. cb.call(this, value, index)
  119. }).exec()
  120. },
  121. onTap(e) {
  122. const { index } = e.currentTarget.dataset
  123. const { raterValue, disabled, allowHalf, allowClear } = this.data
  124. // 判断是否禁用
  125. if (!disabled) {
  126. // 判断是否支持选中半星
  127. if (!allowHalf) {
  128. const value = index + 1
  129. const isReset = allowClear && value === raterValue
  130. this.fireEvents(isReset ? 0 : value, index)
  131. } else {
  132. this.updateHalfStarValue(index, e.detail.x, (value, index) => {
  133. const isReset = allowClear && value === raterValue
  134. this.fireEvents(isReset ? 0 : value, index)
  135. })
  136. }
  137. }
  138. },
  139. fireEvents(value, index) {
  140. if (!this.data.controlled) {
  141. this.updateValue(value)
  142. }
  143. this.triggerEvent('change', { value, index })
  144. },
  145. onTouchMove(e) {
  146. const { disabled, allowHalf, allowTouchMove } = this.data
  147. if (!disabled && allowTouchMove) {
  148. const x = e.changedTouches[0].pageX
  149. const { prefixCls } = this.data
  150. const query = wx.createSelectorQuery().in(this)
  151. query.selectAll(`.${prefixCls}__star`).boundingClientRect((rects) => {
  152. if (rects.filter((n) => !n).length) return
  153. const { left, width } = rects[0]
  154. const maxWidth = rects.map((n) => n.width).reduce((a, b) => a + b)
  155. const diff = x - left
  156. let value = Math.ceil(diff / width)
  157. // 判断是否在组件宽度范围内
  158. if (diff > 0 && diff < maxWidth) {
  159. const index = value - 1
  160. if (allowHalf) {
  161. const star = rects[index]
  162. const has = (x - star.left) < star.width / 2
  163. value = has ? value - .5 : value
  164. }
  165. this.fireEvents(value, index)
  166. }
  167. }).exec()
  168. }
  169. },
  170. },
  171. attached() {
  172. const { defaultValue, value, controlled } = this.data
  173. const raterValue = controlled ? value : defaultValue
  174. this.updateValue(raterValue)
  175. },
  176. })