Pārlūkot izejas kodu

fix: 修改bar、slider问题

jiaxing.liao 1 mēnesi atpakaļ
vecāks
revīzija
7caabc5d44

+ 40 - 1
src/renderer/src/lvgl-widgets/bar/Bar.vue

@@ -3,7 +3,7 @@
     <ImageBg :src="styleMap?.mainStyle?.imageSrc" :image-style="styleMap?.mainStyle?.imageStyle" />
     <div
       class="absolute overflow-hidden"
-      :style="{ ...(styleMap?.indicatorStyle || {}), ...otherStyle }"
+      :style="indicatorStyle"
     >
       <ImageBg
         :src="styleMap?.indicatorStyle?.imageSrc"
@@ -17,6 +17,7 @@
 import { computed } from 'vue'
 import { useWidgetStyle } from '../hooks/useWidgetStyle'
 import ImageBg from '../ImageBg.vue'
+import type { CSSProperties } from 'vue'
 
 const props = defineProps<{
   width?: number
@@ -38,6 +39,44 @@ const styleMap = useWidgetStyle({
   props
 })
 
+const isGradientBackground = (background: unknown) => {
+  return typeof background === 'string' && /(?:linear|radial|conic)-gradient\(/.test(background)
+}
+
+const getOffset = (value: string | number | undefined, total = 0) => {
+  if (typeof value === 'number') return value
+  if (!value || value === 'auto') return 0
+  if (value.endsWith('%')) {
+    return (Number(value.replace('%', '')) / 100) * total
+  }
+  if (value.endsWith('px')) {
+    return Number(value.replace('px', ''))
+  }
+  return Number(value) || 0
+}
+
+const indicatorGradientStyle = computed<CSSProperties>(() => {
+  const indicatorBackground = styleMap.value?.indicatorStyle?.background
+  if (!isGradientBackground(indicatorBackground)) return {}
+
+  const width = Number(props.width || 0)
+  const height = Number(props.height || 0)
+  const left = getOffset(otherStyle.value.left, width)
+  const top = getOffset(otherStyle.value.top, height)
+
+  return {
+    backgroundSize: `${width}px ${height}px`,
+    backgroundPosition: `${-left}px ${-top}px`,
+    backgroundRepeat: 'no-repeat'
+  }
+})
+
+const indicatorStyle = computed(() => ({
+  ...(styleMap.value?.indicatorStyle || {}),
+  ...indicatorGradientStyle.value,
+  ...otherStyle.value
+}))
+
 const otherStyle = computed(() => {
   const { value = 0, max: e = 100, min: s = 0, width = 0, height = 0, mode, startValue } = props
   // 不管范围值如何,都取实际最小值和最大值

+ 70 - 17
src/renderer/src/lvgl-widgets/slider/Slider.vue

@@ -1,7 +1,7 @@
 <template>
   <div :style="styleMap?.mainStyle" class="w-full h-full box-border relative">
     <ImageBg :src="styleMap?.mainStyle?.imageSrc" :image-style="styleMap?.mainStyle?.imageStyle" />
-    <div class="absolute" :style="{ ...(styleMap?.indicatorStyle || {}), ...otherStyle.barStyle }">
+    <div class="absolute" :style="indicatorStyle">
       <ImageBg
         :src="styleMap?.indicatorStyle?.imageSrc"
         :image-style="styleMap?.indicatorStyle?.imageStyle"
@@ -41,6 +41,7 @@
 import { computed } from 'vue'
 import { useWidgetStyle } from '../hooks/useWidgetStyle'
 import ImageBg from '../ImageBg.vue'
+import type { CSSProperties } from 'vue'
 
 const props = defineProps<{
   width?: number
@@ -61,6 +62,44 @@ const styleMap = useWidgetStyle({
   props
 })
 
+const isGradientBackground = (background: unknown) => {
+  return typeof background === 'string' && /(?:linear|radial|conic)-gradient\(/.test(background)
+}
+
+const getOffset = (value: string | number | undefined, total = 0) => {
+  if (typeof value === 'number') return value
+  if (!value || value === 'auto') return 0
+  if (value.endsWith('%')) {
+    return (Number(value.replace('%', '')) / 100) * total
+  }
+  if (value.endsWith('px')) {
+    return Number(value.replace('px', ''))
+  }
+  return Number(value) || 0
+}
+
+const indicatorGradientStyle = computed<CSSProperties>(() => {
+  const indicatorBackground = styleMap.value?.indicatorStyle?.background
+  if (!isGradientBackground(indicatorBackground)) return {}
+
+  const width = Number(props.width || 0)
+  const height = Number(props.height || 0)
+  const left = getOffset(otherStyle.value.barStyle.left, width)
+  const top = getOffset(otherStyle.value.barStyle.top, height)
+
+  return {
+    backgroundSize: `${width}px ${height}px`,
+    backgroundPosition: `${-left}px ${-top}px`,
+    backgroundRepeat: 'no-repeat'
+  }
+})
+
+const indicatorStyle = computed(() => ({
+  ...(styleMap.value?.indicatorStyle || {}),
+  ...indicatorGradientStyle.value,
+  ...otherStyle.value.barStyle
+}))
+
 const otherStyle = computed(() => {
   const { value = 0, max: e = 100, min: s = 0, width = 0, height = 0, mode, startValue } = props
   // 不管范围值如何,都取实际最小值和最大值
@@ -147,6 +186,16 @@ const otherStyle = computed(() => {
     }
   }
 
+  const isHorizontal = ['ltr', 'rtl'].includes(direction)
+  const endHorizontalAnchor = (direction === 'ltr') !== reverse ? 'right' : 'left'
+  const startHorizontalAnchor = endHorizontalAnchor === 'right' ? 'left' : 'right'
+  const endVerticalAnchor = (direction === 'btt') !== reverse ? 'top' : 'bottom'
+  const startVerticalAnchor = endVerticalAnchor === 'top' ? 'bottom' : 'top'
+  const getHorizontalKnobTransform = (anchor: 'left' | 'right') =>
+    anchor === 'right' ? 'translateX(50%)' : 'translateX(-50%)'
+  const getVerticalKnobTransform = (anchor: 'top' | 'bottom') =>
+    anchor === 'bottom' ? 'translateY(50%)' : 'translateY(-50%)'
+
   return {
     barStyle: {
       width: width >= height ? 'auto' : '100%',
@@ -158,35 +207,39 @@ const otherStyle = computed(() => {
       bottom: e > s ? bottom : top
     },
     direction,
-    endKnobStyle: ['ltr', 'rtl'].includes(direction)
+    endKnobStyle: isHorizontal
       ? {
           top: '-4px',
           bottom: 'auto',
-          right: direction === 'ltr' && !reverse ? '0' : '',
-          left: direction === 'rtl' && !reverse ? '0' : '',
-          height: 'calc(100% + 8px)'
+          right: endHorizontalAnchor === 'right' ? '0' : 'auto',
+          left: endHorizontalAnchor === 'left' ? '0' : 'auto',
+          height: 'calc(100% + 8px)',
+          transform: getHorizontalKnobTransform(endHorizontalAnchor)
         }
       : {
-          left: '-4px',
+          left: '50%',
           right: 'auto',
-          top: direction === 'btt' && !reverse ? '0' : '',
-          bottom: direction === 'ttb' && !reverse ? '0' : '',
-          width: 'calc(100% + 8px)'
+          top: endVerticalAnchor === 'top' ? '0' : 'auto',
+          bottom: endVerticalAnchor === 'bottom' ? '0' : 'auto',
+          width: 'calc(100% + 8px)',
+          transform: `translateX(-50%) ${getVerticalKnobTransform(endVerticalAnchor)}`
         },
-    startKnobStyle: ['ltr', 'rtl'].includes(direction)
+    startKnobStyle: isHorizontal
       ? {
           top: '-4px',
           bottom: 'auto',
-          right: direction === 'ltr' && !reverse ? '' : '0',
-          left: direction === 'rtl' && !reverse ? '' : '0',
-          height: 'calc(100% + 8px)'
+          right: startHorizontalAnchor === 'right' ? '0' : 'auto',
+          left: startHorizontalAnchor === 'left' ? '0' : 'auto',
+          height: 'calc(100% + 8px)',
+          transform: getHorizontalKnobTransform(startHorizontalAnchor)
         }
       : {
-          left: '-4px',
+          left: '50%',
           right: 'auto',
-          top: direction === 'btt' && !reverse ? '' : '0',
-          bottom: direction === 'ttb' && !reverse ? '' : '0',
-          width: 'calc(100% + 8px)'
+          top: startVerticalAnchor === 'top' ? '0' : 'auto',
+          bottom: startVerticalAnchor === 'bottom' ? '0' : 'auto',
+          width: 'calc(100% + 8px)',
+          transform: `translateX(-50%) ${getVerticalKnobTransform(startVerticalAnchor)}`
         }
   }
 })

+ 5 - 1
src/renderer/src/views/designer/config/property/index.vue

@@ -112,7 +112,11 @@
         </el-form>
       </el-collapse-item>
     </el-collapse>
-    <div class="absolute left-0 top-0 w-full h-full" @click="handleClickMask"></div>
+    <div
+      :style="{ pointerEvents: isActiveWidgetLocked ? 'auto' : 'none' }"
+      class="absolute left-0 top-0 w-full h-full"
+      @click="handleClickMask"
+    ></div>
   </div>
 </template>