| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- <template>
- <view class="l-liquid" :class="classes" :style="styles">
- <!-- #ifdef APP -->
- <view class="l-liquid__inner" :style="[innerStyle]">
- <view ref="drawRef" class="l-liquid__inner-drawable">
- <slot></slot>
- </view>
- </view>
- <!-- #endif -->
- <!-- #ifndef APP -->
- <view class="l-liquid__inner" :style="[innerStyle]">
- <view class="l-liquid__waves" :style="[wavesStyle]">
- <view class="wave" :style="[waveStyle]"></view>
- <view class="wave two" :style="[waveStyle]"></view>
- </view>
- </view>
- <view class="l-liquid__value">
- <slot></slot>
- </view>
- <!-- #endif -->
- </view>
- </template>
- <script lang="uts" setup>
- import { addUnit } from "@/uni_modules/lime-shared/addUnit";
- import { useTransition, UseTransitionOptions } from "@/uni_modules/lime-shared/animation/useTransition";
- import { toRgba } from './utils'
-
- defineOptions({
- name: 'l-liquid'
- })
- const emits = defineEmits(['update:current'])
- const props = defineProps({
- percent: {
- type: Number,
- default: 10
- },
- size: {
- type: String,
- default: '250rpx'
- },
- outline: {
- type: Boolean,
- default: false
- },
- radius: {
- type: String,
- // default: null
- },
- waveColor: {
- type: String,
- default: '#007aff'
- },
- innerColor: {
- type: String,
- // default: null
- }
- })
- const drawRef = ref<UniElement|null>(null)
- const current = useTransition(():number=> props.percent, {
- duration: 300,
- immediate: true
- } as UseTransitionOptions) //ref(props.percent)
- const a = ref(0)
- const classes = computed(():Map<string, any>=>{
- const cls = new Map<string, any>()
- if (props.outline) {
- cls.set('l-liquid--outline', true)
- }
- return cls
- })
- const styles = computed(():Map<string, any>=>{
- const style = new Map<string, any>()
- const size = addUnit(props.size)
- style.set('width', size)
- style.set('height', size)
- return style
- })
- const innerStyle= computed(():Map<string, any>=>{
- const style = new Map<string, any>()
- if(props.radius != null) {
- style.set('border-radius', props.radius!)
- }
- if(props.innerColor != null) {
- style.set('background', props.innerColor!)
- }
- return style
- })
- const wavesStyle= computed(():UTSJSONObject=>{
- return {
- '--l-liquid-percent': current.value * -1 + '%'
- }
- })
- const waveStyle = computed(():UTSJSONObject=>{
- return {
- background: props.waveColor
- }
- })
- let step: (() => void) | null = null
- const stopPercent = watch(current, (v: number) => {
- emits('update:current', Math.round(v))
- })
- let interval = -1
- onMounted(()=>{
-
- nextTick(()=>{
- // #ifdef APP
- const size = drawRef.value?.getBoundingClientRect()?.width!
- const ctx = drawRef.value?.getDrawableContext();
- if (ctx == null) return
- const render = (ctx : DrawableContext, size : number)=>{
- // let sinX = 0 // x轴
- // let offsetY = 0.3 // 高度 -- 越大高度越高
- let sinX:number,offsetY:number;
- let speed = 0.2 // x轴 移动距离
-
- /**
- * 波浪线
- * @param sinX -- 波浪线 sin坐标中 x轴的位置
- * @param offsetY -- 波浪线 在画布中的 高度比 画布垂直距离
- * @param waveW -- 波浪宽度
- * @param waveH -- 波浪深度
- * @param color -- 波浪颜色
- * */
- function drawWave(sinX : number, offsetY : number, waveW : number, waveH : number, color : string) {
- let canvasW = size
- let canvasH = size
- let offsetX = 0 // 波浪线 初始x轴坐标
- ctx.beginPath()
- ctx.lineWidth = 1
- for (let x = offsetX; x < canvasW; x += 20 / canvasW) {
- // 正弦曲线公式:y = Asin(ωx+φ) + k
- let y = waveH * Math.sin((offsetX + x) * waveW + sinX) + (1 - offsetY) * canvasH
- ctx.lineTo(x, y)
- }
- // 填充背景
- ctx.lineTo(canvasW, canvasH)
- ctx.lineTo(offsetX, canvasH)
- ctx.closePath()
- ctx.fillStyle = color
- ctx.fill()
- }
-
-
- // 绘制 波浪
- const lightColor = toRgba(props.waveColor, 0.4)
- function draw(count : number) {
- ctx.reset()
- offsetY = current.value / 100
- sinX = count * speed
- drawWave(sinX + 3, offsetY - 0.01, 0.08, 6, lightColor)
- drawWave(sinX, offsetY, 0.08, 4, props.waveColor)
- ctx.update()
- }
-
- let count : number = 0
- interval = setInterval(() => {
- draw(count)
- count += 0.3
- }, 1000 / 60)
- }
- render(ctx, size)
- // #endif
- })
- })
- onUnmounted(()=>{
- stopPercent()
- clearInterval(interval)
- })
- </script>
- <style lang="scss">
- @import './index-u';
- </style>
|