Bladeren bron

feat: 添加文本框控件

jiaxing.liao 2 maanden geleden
bovenliggende
commit
2978694ac5

+ 2 - 0
src/renderer/src/lvgl-widgets/index.ts

@@ -3,6 +3,7 @@ import ImageButton from './image-button'
 import MatrixButton from './button-matrix/index'
 import Image from './image'
 import SpanGroup from './span-group/index'
+import Textarea from './textarea'
 
 import Container from './container'
 import Label from './label'
@@ -15,6 +16,7 @@ export const ComponentArray = [
   MatrixButton,
   Image,
   SpanGroup,
+  Textarea,
   Container,
   Page,
   Label

+ 1 - 1
src/renderer/src/lvgl-widgets/span-group/SpanGroup.vue

@@ -29,7 +29,7 @@ const getProps = computed(() => {
   const styles = props.styles
   const stateStyles = styles.find((item) => item.state === props.state)
   const otherStyles: CSSProperties = {}
-  console.log(props.mode)
+
   if (props.mode === 'expand') {
     otherStyles.display = 'flex'
     otherStyles.flexWrap = 'nowrap'

+ 56 - 25
src/renderer/src/lvgl-widgets/textarea/Textarea.vue

@@ -1,9 +1,13 @@
 <template>
-  <div v-bind="getProps">{{ props.text }}</div>
+  <div :style="getProps.mainStyle">
+    <span :style="{ color: !text ? '#ccc' : '' }">{{ getContent }}</span>
+  </div>
 </template>
 
 <script setup lang="ts">
-import { computed } from 'vue'
+import { computed, type CSSProperties } from 'vue'
+import defaultStyle from './style.json'
+
 const props = defineProps<{
   width: number
   height: number
@@ -17,48 +21,75 @@ const props = defineProps<{
   nowrap: boolean
 }>()
 
-const getProps = computed(() => {
+// 文本内容
+const getContent = computed(() => {
+  const { text, placeholder, passwordMode } = props
+
+  return passwordMode ? '*'.repeat(text.length) : text || placeholder
+})
+
+const getProps = computed((): Record<string, CSSProperties> => {
   const styles = props.styles
-  const stateStyles = styles.find((item) => item.state === props.state)
+  let mainStyle = styles.find((item) => item.state === props.state && item.part.name === 'main')
+  let scrollbarStyle = styles.find(
+    (item) => item.state === props.state && item.part.name === 'scrollbar'
+  )
 
+  // 从默认样式获取样式
+  if (!mainStyle && props.state) {
+    mainStyle = defaultStyle.part
+      ?.find((item) => item.partName === 'main')
+      ?.state.find((item) => item.state === props.state)?.style
+  }
+
+  if (!scrollbarStyle && props.state) {
+    scrollbarStyle = defaultStyle.part
+      ?.find((item) => item.partName === 'scrollbar')
+      ?.state.find((item) => item.state === props.state)?.style
+  }
+  console.log(mainStyle, scrollbarStyle)
   return {
-    class: 'button',
-    style: {
+    mainStyle: {
       width: `${props.width}px`,
       height: `${props.height}px`,
+      boxSizing: 'border-box',
+      display: 'flex',
 
-      backgroundColor: stateStyles?.background.color,
+      backgroundColor: mainStyle?.background.color,
 
-      fontSize: `${stateStyles?.text.size}px`,
-      color: stateStyles?.text?.color,
-      display: 'flex',
-      justifyContent: stateStyles?.text?.align || 'center',
-      alignItems: 'center',
+      fontSize: `${mainStyle?.text.size}px`,
+      color: mainStyle?.text?.color,
+      justifyContent: mainStyle?.text?.align || 'center',
+      fontWeight: mainStyle?.text.bold ? 'bold' : 'normal',
 
-      borderRadius: `${stateStyles?.border.radius}px`,
+      borderRadius: `${mainStyle?.border.radius}px`,
       borderStyle: 'solid',
       borderColor: 'transparent',
-      borderWidth: `${stateStyles?.border.width}px`,
+      borderWidth: `${mainStyle?.border.width}px`,
       borderTopColor:
-        stateStyles?.border?.side?.includes('all') || stateStyles?.border?.side?.includes('top')
-          ? stateStyles?.border?.color
+        mainStyle?.border?.side?.includes('all') || mainStyle?.border?.side?.includes('top')
+          ? mainStyle?.border?.color
           : 'transparent',
       borderRightColor:
-        stateStyles?.border?.side?.includes('all') || stateStyles?.border?.side?.includes('right')
-          ? stateStyles?.border?.color
+        mainStyle?.border?.side?.includes('all') || mainStyle?.border?.side?.includes('right')
+          ? mainStyle?.border?.color
           : 'transparent',
       borderBottomColor:
-        stateStyles?.border?.side?.includes('all') || stateStyles?.border?.side?.includes('bottom')
-          ? stateStyles?.border?.color
+        mainStyle?.border?.side?.includes('all') || mainStyle?.border?.side?.includes('bottom')
+          ? mainStyle?.border?.color
           : 'transparent',
       borderLeftColor:
-        stateStyles?.border?.side?.includes('all') || stateStyles?.border?.side?.includes('left')
-          ? stateStyles?.border?.color
+        mainStyle?.border?.side?.includes('all') || mainStyle?.border?.side?.includes('left')
+          ? mainStyle?.border?.color
           : 'transparent',
+      // 内边距
+      padding: `${mainStyle?.padding.top}px ${mainStyle?.padding.right}px ${mainStyle?.padding.bottom}px ${mainStyle?.padding.left}px`,
       /* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */
-      boxShadow: stateStyles?.shadow
-        ? `${stateStyles?.shadow?.x}px ${stateStyles?.shadow?.y}px ${stateStyles?.shadow?.width}px ${stateStyles?.shadow?.spread}px ${stateStyles?.shadow?.color}`
-        : 'none'
+      boxShadow: mainStyle?.shadow
+        ? `${mainStyle?.shadow?.x}px ${mainStyle?.shadow?.y}px ${mainStyle?.shadow?.width}px ${mainStyle?.shadow?.spread}px ${mainStyle?.shadow?.color}`
+        : 'none',
+      // 字间距
+      letterSpacing: `${mainStyle?.gap?.column}px`
     }
   }
 })

+ 81 - 39
src/renderer/src/lvgl-widgets/textarea/index.ts

@@ -33,7 +33,7 @@ export default {
       addFlags: [],
       removeFlags: [],
       text: 'hello world',
-      placeholder: 'placeholder',
+      placeholder: '',
       maxLength: 32,
       allowString: '',
       passwordMode: false,
@@ -169,18 +169,33 @@ export default {
         }
       },
       {
-        label: '模式',
-        field: 'props.mode',
-        valueType: 'select',
+        label: '提示文本',
+        field: 'props.placeholder',
+        valueType: 'text'
+      },
+      {
+        label: '最大长度',
+        field: 'props.maxLength',
+        valueType: 'number',
         componentProps: {
-          options: [
-            { label: 'Circular', value: 'circular' },
-            { label: 'Clip', value: 'clip' },
-            { label: 'Dot', value: 'dot' },
-            { label: 'Scroll', value: 'Scroll' },
-            { label: 'Wrap', value: 'wrap' }
-          ]
+          min: 0,
+          step: 1
         }
+      },
+      {
+        label: '允许字符',
+        field: 'props.allowString',
+        valueType: 'text'
+      },
+      {
+        label: '密码模式',
+        field: 'props.passwordMode',
+        valueType: 'switch'
+      },
+      {
+        label: '不换行模式',
+        field: 'props.nowrap',
+        valueType: 'switch'
       }
     ],
     // 组件样式
@@ -191,34 +206,61 @@ export default {
         valueType: 'part'
       },
       {
-        label: '背景',
-        field: 'background',
-        valueType: 'background'
-      },
-      {
-        label: '字体',
-        field: 'text',
-        valueType: 'font'
-      },
-      {
-        label: '间距',
-        field: 'gap',
-        valueType: 'gap'
-      },
-      {
-        label: '内边距',
-        field: 'padding',
-        valueType: 'padding'
-      },
-      {
-        label: '边框',
-        field: 'border',
-        valueType: 'border'
-      },
-      {
-        label: '阴影',
-        field: 'shadow',
-        valueType: 'shadow'
+        name: ['part'],
+        valueType: 'dependency',
+        dependency: ({ part }) => {
+          return part?.name === 'scrollbar'
+            ? [
+                {
+                  label: '背景',
+                  field: 'background',
+                  valueType: 'background',
+                  componentProps: {
+                    onlyColor: true
+                  }
+                },
+                {
+                  label: '圆角',
+                  field: 'border.radius',
+                  valueType: 'number'
+                }
+              ]
+            : [
+                {
+                  label: '背景',
+                  field: 'background',
+                  valueType: 'background'
+                },
+                {
+                  label: '字体',
+                  field: 'text',
+                  valueType: 'font'
+                },
+                {
+                  label: '间距',
+                  field: 'gap',
+                  valueType: 'gap',
+                  componentProps: {
+                    hideRow: true
+                  }
+                },
+                {
+                  label: '内边距',
+                  field: 'padding',
+                  valueType: 'padding'
+                },
+                {
+                  label: '边框',
+                  field: 'border',
+                  valueType: 'border'
+                },
+                {
+                  label: '阴影',
+                  field: 'shadow',
+                  valueType: 'shadow'
+                }
+              ]
+        }
       }
     ]
   }

+ 51 - 13
src/renderer/src/views/designer/config/property/CusFormItem.vue

@@ -2,26 +2,40 @@
   <el-col :span="schema?.componentProps?.span ?? 24">
     <el-form-item v-if="isFormItem" :prop="schema.field" :label="schema.label">
       <!-- 文本 -->
-      <el-input v-if="schema.valueType === 'text'" v-model="value" />
+      <el-input
+        v-if="schema.valueType === 'text'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 数字 -->
       <el-input-number
-        class="w-full"
-        controls-position="right"
         v-if="schema.valueType === 'number'"
         v-model="value"
+        controls-position="right"
+        style="width: 100%"
+        v-bind="schema?.componentProps"
       />
       <!-- 选择框 -->
       <el-select-v2
         v-if="schema.valueType === 'select'"
         :options="schema?.componentProps?.options || []"
         v-model="value"
+        v-bind="schema?.componentProps"
       />
       <!-- 开关 -->
       <el-switch v-if="schema.valueType === 'switch'" v-model="value" />
       <!-- 文本框 -->
-      <CusTextarea v-if="schema.valueType === 'textarea'" v-model="value" />
+      <CusTextarea
+        v-if="schema.valueType === 'textarea'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 图片选择 -->
-      <ImageSelect v-if="schema.valueType === 'image'" v-model="value" />
+      <ImageSelect
+        v-if="schema.valueType === 'image'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
     </el-form-item>
 
     <!-- 分组 -->
@@ -57,22 +71,46 @@
       <StyleBackground
         v-if="schema.valueType === 'background'"
         v-model="value"
-        v-bind="schema.componentProps"
+        v-bind="schema?.componentProps"
       />
       <!-- 边框 -->
-      <StyleBorder v-if="schema.valueType === 'border'" v-model="value" />
+      <StyleBorder
+        v-if="schema.valueType === 'border'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 字体 -->
-      <StyleFont v-if="schema.valueType === 'font'" v-model="value" />
+      <StyleFont
+        v-if="schema.valueType === 'font'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 外边距 -->
-      <StyleMargin v-if="schema.valueType === 'margin'" v-model="value" />
+      <StyleMargin
+        v-if="schema.valueType === 'margin'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 内边距 -->
-      <StylePadding v-if="schema.valueType === 'padding'" v-model="value" />
+      <StylePadding
+        v-if="schema.valueType === 'padding'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 阴影 -->
-      <StyleShadow v-if="schema.valueType === 'shadow'" v-model="value" />
+      <StyleShadow
+        v-if="schema.valueType === 'shadow'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
       <!-- 间距 -->
-      <StyleGap v-if="schema.valueType === 'gap'" v-model="value" />
+      <StyleGap v-if="schema.valueType === 'gap'" v-model="value" v-bind="schema?.componentProps" />
       <!-- 线段  -->
-      <StyleLine v-if="schema.valueType === 'line'" v-model="value" />
+      <StyleLine
+        v-if="schema.valueType === 'line'"
+        v-model="value"
+        v-bind="schema?.componentProps"
+      />
     </el-card>
 
     <!-- 自定义渲染 -->

+ 14 - 14
src/renderer/src/views/designer/config/property/components/StyleBackground.vue

@@ -10,7 +10,7 @@
       />
       <span class="text-text-active">{{ modelValue?.color }}</span>
     </el-form-item>
-    <el-form-item label="背景图片" label-position="left" label-width="60px">
+    <el-form-item v-if="!onlyColor" label="背景图片" label-position="left" label-width="60px">
       <el-select-v2
         placeholder="选择图片"
         :model-value="modelValue?.image?.imgId"
@@ -19,7 +19,7 @@
         @change="handleImageChange"
       />
     </el-form-item>
-    <el-form-item label="图片颜色" label-position="left" label-width="60px">
+    <el-form-item v-if="!onlyColor" label="图片颜色" label-position="left" label-width="60px">
       <ColorPicker
         use-type="pure"
         picker-type="chrome"
@@ -33,14 +33,14 @@
 </template>
 
 <script setup lang="ts">
-import { computed, ref, watch } from 'vue'
+import { computed } from 'vue'
 import { ColorPicker } from '@/components'
 import { parseCssGradient, generateCssGradient } from '@/utils'
 import { useProjectStore } from '@/store/modules/project'
 
 import type { GradientColor } from '@/lvgl-widgets/type'
 
-withDefaults(defineProps<{ useType?: 'pure' | 'gradient' | 'both' }>(), {
+withDefaults(defineProps<{ useType?: 'pure' | 'gradient' | 'both'; onlyColor?: boolean }>(), {
   useType: 'pure'
 })
 
@@ -54,7 +54,16 @@ const modelValue = defineModel<{
   }
 }>('modelValue')
 // 纯色
-const pureColor = ref(modelValue?.value?.color || '')
+const pureColor = computed({
+  get() {
+    return modelValue.value?.color
+  },
+  set(val: string) {
+    if (modelValue.value) {
+      modelValue.value.color = val
+    }
+  }
+})
 // 渐变
 const gradientColor = computed({
   get() {
@@ -87,15 +96,6 @@ const imageOptions = computed(() => {
   return list.map((item) => ({ label: item.fileName, value: item.id }))
 })
 
-watch(
-  () => pureColor.value,
-  () => {
-    if (modelValue.value) {
-      modelValue.value.color = pureColor.value
-    }
-  }
-)
-
 const handleImageChange = (imageId: string) => {
   if (modelValue.value) {
     if (!modelValue.value?.image) {

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

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <el-form-item label="行间距" label-position="left" label-width="60px">
+    <el-form-item v-if="!hideRow" label="行间距" label-position="left" label-width="60px">
       <el-input-number
         placeholder="请输入"
         v-model="row"
@@ -27,6 +27,10 @@ const modelValue = defineModel<{
   row: number
 }>('modelValue')
 
+const props = defineProps<{
+  hideRow?: boolean
+}>()
+
 // column
 const column = computed({
   get: () => modelValue.value?.column,