云链智安app
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

l-liquid.uvue 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <view class="l-liquid" :class="classes" :style="styles">
  3. <!-- #ifdef APP -->
  4. <view class="l-liquid__inner" :style="[innerStyle]">
  5. <view ref="drawRef" class="l-liquid__inner-drawable">
  6. <slot></slot>
  7. </view>
  8. </view>
  9. <!-- #endif -->
  10. <!-- #ifndef APP -->
  11. <view class="l-liquid__inner" :style="[innerStyle]">
  12. <view class="l-liquid__waves" :style="[wavesStyle]">
  13. <view class="wave" :style="[waveStyle]"></view>
  14. <view class="wave two" :style="[waveStyle]"></view>
  15. </view>
  16. </view>
  17. <view class="l-liquid__value">
  18. <slot></slot>
  19. </view>
  20. <!-- #endif -->
  21. </view>
  22. </template>
  23. <script lang="uts" setup>
  24. import { addUnit } from "@/uni_modules/lime-shared/addUnit";
  25. import { useTransition, UseTransitionOptions } from "@/uni_modules/lime-shared/animation/useTransition";
  26. import { toRgba } from './utils'
  27. defineOptions({
  28. name: 'l-liquid'
  29. })
  30. const emits = defineEmits(['update:current'])
  31. const props = defineProps({
  32. percent: {
  33. type: Number,
  34. default: 10
  35. },
  36. size: {
  37. type: String,
  38. default: '250rpx'
  39. },
  40. outline: {
  41. type: Boolean,
  42. default: false
  43. },
  44. radius: {
  45. type: String,
  46. // default: null
  47. },
  48. waveColor: {
  49. type: String,
  50. default: '#007aff'
  51. },
  52. innerColor: {
  53. type: String,
  54. // default: null
  55. }
  56. })
  57. const drawRef = ref<UniElement|null>(null)
  58. const current = useTransition(():number=> props.percent, {
  59. duration: 300,
  60. immediate: true
  61. } as UseTransitionOptions) //ref(props.percent)
  62. const a = ref(0)
  63. const classes = computed(():Map<string, any>=>{
  64. const cls = new Map<string, any>()
  65. if (props.outline) {
  66. cls.set('l-liquid--outline', true)
  67. }
  68. return cls
  69. })
  70. const styles = computed(():Map<string, any>=>{
  71. const style = new Map<string, any>()
  72. const size = addUnit(props.size)
  73. style.set('width', size)
  74. style.set('height', size)
  75. return style
  76. })
  77. const innerStyle= computed(():Map<string, any>=>{
  78. const style = new Map<string, any>()
  79. if(props.radius != null) {
  80. style.set('border-radius', props.radius!)
  81. }
  82. if(props.innerColor != null) {
  83. style.set('background', props.innerColor!)
  84. }
  85. return style
  86. })
  87. const wavesStyle= computed(():UTSJSONObject=>{
  88. return {
  89. '--l-liquid-percent': current.value * -1 + '%'
  90. }
  91. })
  92. const waveStyle = computed(():UTSJSONObject=>{
  93. return {
  94. background: props.waveColor
  95. }
  96. })
  97. let step: (() => void) | null = null
  98. const stopPercent = watch(current, (v: number) => {
  99. emits('update:current', Math.round(v))
  100. })
  101. let interval = -1
  102. onMounted(()=>{
  103. nextTick(()=>{
  104. // #ifdef APP
  105. const size = drawRef.value?.getBoundingClientRect()?.width!
  106. const ctx = drawRef.value?.getDrawableContext();
  107. if (ctx == null) return
  108. const render = (ctx : DrawableContext, size : number)=>{
  109. // let sinX = 0 // x轴
  110. // let offsetY = 0.3 // 高度 -- 越大高度越高
  111. let sinX:number,offsetY:number;
  112. let speed = 0.2 // x轴 移动距离
  113. /**
  114. * 波浪线
  115. * @param sinX -- 波浪线 sin坐标中 x轴的位置
  116. * @param offsetY -- 波浪线 在画布中的 高度比 画布垂直距离
  117. * @param waveW -- 波浪宽度
  118. * @param waveH -- 波浪深度
  119. * @param color -- 波浪颜色
  120. * */
  121. function drawWave(sinX : number, offsetY : number, waveW : number, waveH : number, color : string) {
  122. let canvasW = size
  123. let canvasH = size
  124. let offsetX = 0 // 波浪线 初始x轴坐标
  125. ctx.beginPath()
  126. ctx.lineWidth = 1
  127. for (let x = offsetX; x < canvasW; x += 20 / canvasW) {
  128. // 正弦曲线公式:y = Asin(ωx+φ) + k
  129. let y = waveH * Math.sin((offsetX + x) * waveW + sinX) + (1 - offsetY) * canvasH
  130. ctx.lineTo(x, y)
  131. }
  132. // 填充背景
  133. ctx.lineTo(canvasW, canvasH)
  134. ctx.lineTo(offsetX, canvasH)
  135. ctx.closePath()
  136. ctx.fillStyle = color
  137. ctx.fill()
  138. }
  139. // 绘制 波浪
  140. const lightColor = toRgba(props.waveColor, 0.4)
  141. function draw(count : number) {
  142. ctx.reset()
  143. offsetY = current.value / 100
  144. sinX = count * speed
  145. drawWave(sinX + 3, offsetY - 0.01, 0.08, 6, lightColor)
  146. drawWave(sinX, offsetY, 0.08, 4, props.waveColor)
  147. ctx.update()
  148. }
  149. let count : number = 0
  150. interval = setInterval(() => {
  151. draw(count)
  152. count += 0.3
  153. }, 1000 / 60)
  154. }
  155. render(ctx, size)
  156. // #endif
  157. })
  158. })
  159. onUnmounted(()=>{
  160. stopPercent()
  161. clearInterval(interval)
  162. })
  163. </script>
  164. <style lang="scss">
  165. @import './index-u';
  166. </style>