index.vue 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <template>
  2. <view class="start-bar" :style="`--rate-size: ${size}rpx`">
  3. <block v-for="(item, index) in starts" :key="index">
  4. <view
  5. class="start"
  6. :class="item.active ? 'active' : ''"
  7. :data-score="item.score"
  8. @click="select"
  9. >
  10. </view>
  11. </block>
  12. </view>
  13. </template>
  14. <script lang="ts" setup>
  15. import { ref, watch } from 'vue';
  16. const props = defineProps({
  17. // 最大分值
  18. max: {
  19. type: Number,
  20. default: 5,
  21. },
  22. // 分数值
  23. score: {
  24. type: Number,
  25. default: 0,
  26. },
  27. // 是否只读
  28. disabled: {
  29. type: Boolean,
  30. default: false,
  31. },
  32. // 是否显示分数
  33. showScore: {
  34. type: Boolean,
  35. default: false,
  36. },
  37. size: {
  38. type: Number,
  39. default: 30,
  40. },
  41. });
  42. const starts = ref([]);
  43. const emits = defineEmits(['update:score', 'change']);
  44. const select = ({ target: { dataset } }) => {
  45. if (props.disabled) return;
  46. // 这里暂时不支持分数清零
  47. starts.value = starts.value.map((item) => {
  48. item.active = item.score <= dataset.score;
  49. return item;
  50. });
  51. emits('update:score', dataset.score);
  52. emits('change', dataset.score);
  53. };
  54. watch(
  55. () => [props.max, props.score],
  56. ([max, score]) => {
  57. starts.value = [];
  58. for (let i = 1; i <= max; i++) {
  59. starts.value.push({
  60. score: i,
  61. active: i <= score,
  62. });
  63. }
  64. },
  65. {
  66. immediate: true,
  67. }
  68. );
  69. </script>
  70. <style lang="scss" scoped>
  71. .start-bar {
  72. display: flex;
  73. justify-content: space-around;
  74. --rate-fill-color: #bebebe;
  75. --rate-size: 30rpx;
  76. }
  77. .start.active {
  78. --rate-fill-color: #f7ba2a;
  79. }
  80. .start,
  81. .start::before,
  82. .start::after {
  83. width: 0;
  84. height: 0;
  85. border-top: calc(var(--rate-size) / 1.2) solid var(--rate-fill-color);
  86. border-right: var(--rate-size) solid transparent;
  87. border-left: var(--rate-size) solid transparent;
  88. overflow: visible;
  89. }
  90. .start {
  91. margin: calc(var(--rate-size) / 2);
  92. position: relative;
  93. display: block;
  94. color: var(--rate-fill-color);
  95. }
  96. .start::before,
  97. .start::after {
  98. content: '';
  99. display: block;
  100. position: absolute;
  101. left: calc(var(--rate-size) * -1);
  102. top: calc(var(--rate-size) / -1.3);
  103. }
  104. .start::before {
  105. transform: rotate(68deg);
  106. }
  107. .start::after {
  108. transform: rotate(-68deg);
  109. }
  110. </style>