Alpha.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <template>
  2. <div class="alpha">
  3. <div class="alpha-checkboard-wrap">
  4. <Checkboard />
  5. </div>
  6. <div class="alpha-gradient" :style="{ background: gradientColor }"></div>
  7. <div
  8. class="alpha-container"
  9. ref="alphaRef"
  10. @mousedown="$event => handleMouseDown($event)"
  11. >
  12. <div class="alpha-pointer" :style="{ left: color.a * 100 + '%' }">
  13. <div class="alpha-picker"></div>
  14. </div>
  15. </div>
  16. </div>
  17. </template>
  18. <script lang="ts">
  19. import { computed, defineComponent, onUnmounted, PropType, ref } from 'vue'
  20. import Checkboard from './Checkboard.vue'
  21. import { ColorFormats } from 'tinycolor2'
  22. export default defineComponent({
  23. name: 'alpha',
  24. components: {
  25. Checkboard,
  26. },
  27. props: {
  28. value: {
  29. type: Object as PropType<ColorFormats.RGBA>,
  30. required: true,
  31. },
  32. },
  33. setup(props, { emit }) {
  34. const color = computed(() => props.value)
  35. const gradientColor = computed(() => {
  36. const rgbaStr = [color.value.r, color.value.g, color.value.b].join(',')
  37. return `linear-gradient(to right, rgba(${rgbaStr}, 0) 0%, rgba(${rgbaStr}, 1) 100%)`
  38. })
  39. const alphaRef = ref<HTMLElement>()
  40. const handleChange = (e: MouseEvent) => {
  41. e.preventDefault()
  42. if (!alphaRef.value) return
  43. const containerWidth = alphaRef.value.clientWidth
  44. const xOffset = alphaRef.value.getBoundingClientRect().left + window.pageXOffset
  45. const left = e.pageX - xOffset
  46. let a
  47. if (left < 0) a = 0
  48. else if (left > containerWidth) a = 1
  49. else a = Math.round(left * 100 / containerWidth) / 100
  50. if (color.value.a !== a) {
  51. emit('colorChange', {
  52. r: color.value.r,
  53. g: color.value.g,
  54. b: color.value.b,
  55. a: a,
  56. })
  57. }
  58. }
  59. const unbindEventListeners = () => {
  60. window.removeEventListener('mousemove', handleChange)
  61. window.removeEventListener('mouseup', unbindEventListeners)
  62. }
  63. const handleMouseDown = (e: MouseEvent) => {
  64. handleChange(e)
  65. window.addEventListener('mousemove', handleChange)
  66. window.addEventListener('mouseup', unbindEventListeners)
  67. }
  68. onUnmounted(unbindEventListeners)
  69. return {
  70. alphaRef,
  71. gradientColor,
  72. handleMouseDown,
  73. color,
  74. }
  75. },
  76. })
  77. </script>
  78. <style lang="scss" scoped>
  79. .alpha {
  80. position: absolute;
  81. top: 0;
  82. right: 0;
  83. bottom: 0;
  84. left: 0;
  85. }
  86. .alpha-checkboard-wrap {
  87. position: absolute;
  88. top: 0;
  89. right: 0;
  90. bottom: 0;
  91. left: 0;
  92. overflow: hidden;
  93. }
  94. .alpha-gradient {
  95. position: absolute;
  96. top: 0;
  97. right: 0;
  98. bottom: 0;
  99. left: 0;
  100. }
  101. .alpha-container {
  102. cursor: pointer;
  103. position: relative;
  104. z-index: 2;
  105. height: 100%;
  106. margin: 0 3px;
  107. }
  108. .alpha-pointer {
  109. z-index: 2;
  110. position: absolute;
  111. }
  112. .alpha-picker {
  113. cursor: pointer;
  114. width: 4px;
  115. height: 8px;
  116. box-shadow: 0 0 2px rgba(0, 0, 0, .6);
  117. background: #fff;
  118. margin-top: 1px;
  119. transform: translateX(-2px);
  120. }
  121. </style>