Skip to content

属性编辑组件

组件在编辑器中使用时,需要提供一个该组件的属性编辑组件,命名规则为 【组件名】 + Attr。例如,组件名为 SVGWenBen,则其属性编辑组件名为 SVGWenBenAttr。该属性编辑组件仅在编辑状态下使用,运行状态不需要。如果组件不需要修改任何属性,可以提供一个空的属性编辑组件,或者不需要属性编辑组件也可以。该组件渲染在编辑器的右侧“属性”页签下的“组件属性”栏中,如图所示。

WARNING

组件的属性或数据配置通常都放在 propValue 对象中,并没有严格区分。组件定义者可根据需要自行划分在哪个编辑器中修改。

组件属性编辑器示意图

以SVGWenBenAttr为例

vue
<template>
  <div class="attr-list">
    <VECommonAttr :page-id="props.pageId">
      <template #default>
        <el-form :size="props.formSize" label-width="100px" label-position="left" style="padding:10px">
          <el-form-item label="内容">
            <el-input v-model="curComponent.propValue.text" type="text" class="common-item">
              <template #append>
                <el-icon
                    @click="copyText"><DocumentCopy /></el-icon>
              </template>
            </el-input>
          </el-form-item>
          <el-form-item label="横向位移字符">
            <el-input v-model="curComponent.propValue.dx" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item label="x方向偏移量">
            <el-input-number v-model="curComponent.propValue.offsetX" :precision="0" :step="1" :min="0" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item label="边框背景">
            <el-switch v-model="curComponent.propValue.hasBackground">
            </el-switch>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="边框宽度">
            <el-input-number v-model="curComponent.propValue.strokeWidth" :precision="0" :min="1" :max="10" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="边框圆角RX">
            <el-input-number v-model="curComponent.propValue.rx" :precision="0" :min="0" :step="1" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="边框圆角RY">
            <el-input-number v-model="curComponent.propValue.ry" :precision="0" :min="0" :step="1" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="边框颜色">
            <div style="display: flex; gap: 10px; width: 100%;">
              <el-color-picker v-model="curComponent.propValue.strokeColor" show-alpha
                               :predefine="predefine"></el-color-picker>
              <el-button icon="DocumentCopy" style="width:30px;height:30px;"
                         @click="copyAttr(curComponent.propValue.strokeColor)">
              </el-button>
            </div>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="笔触透明度">
            <el-input-number v-model="curComponent.propValue.strokeOpacity" :precision="1" :min="0" :step="0.1" :max="1" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="背景颜色">
            <div style="display: flex; gap: 10px; width: 100%;">
              <el-color-picker v-model="curComponent.propValue.fillColor" show-alpha
                               :predefine="predefine"></el-color-picker>
              <el-button icon="DocumentCopy" style="width:30px;height:30px;"
                         @click="copyAttr(curComponent.propValue.fillColor)">
              </el-button>
            </div>
          </el-form-item>
          <el-form-item v-if="curComponent.propValue.hasBackground" label="填充透明度">
            <el-input-number v-model="curComponent.propValue.fillOpacity" :precision="1" :min="0" :step="0.1" :max="1" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item label="字体颜色">
            <div style="display: flex; gap: 10px; width: 100%;">
              <el-color-picker v-model="curComponent.propValue.fontColor" show-alpha
                               :predefine="predefine"></el-color-picker>
              <el-button icon="DocumentCopy" style="width:30px;height:30px;"
                         @click="copyAttr(curComponent.propValue.fontColor)">
              </el-button>
            </div>
          </el-form-item>
          <el-form-item label="字体大小">
            <el-input-number v-model="curComponent.propValue.fontSize" :precision="0" :min="2" :step="1" type="text" class="common-item"/>
          </el-form-item>
          <el-form-item label="字体粗细">
            <el-select v-model="curComponent.propValue.fontWeight" placeholder="请选择" class="common-item">
              <el-option
                  v-for="item in fontWeightArr"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="字体">
            <el-select v-model="curComponent.propValue.fontFamily" placeholder="请选择" class="common-item">
              <el-option
                  v-for="item in fontFamilyArr"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="水平对齐">
            <el-select v-model="curComponent.propValue.horizontalAlign" placeholder="请选择" class="common-item">
              <el-option
                  v-for="item in horizontalAlignArr"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value">
              </el-option>
            </el-select>
          </el-form-item>
        </el-form>
      </template>
    </VECommonAttr>
  </div>
</template>

<script setup>

import {useEditorStore} from "hflveditor3";
import {fontWeightArr, predefine,fontFamilyArr,horizontalAlignArr} from "@/custom-components/common/constant.js";
import {computed} from "vue";
import {copyAttr, copyToClipboard} from "@/custom-components/common/common.js";
import {showMessage} from "@/custom-components/common/message.js";
import { DocumentCopy } from '@element-plus/icons-vue';

const props = defineProps(['pageId','formSize'])
const editorStore = useEditorStore(props.pageId);

const curComponent = computed(() => {
  return editorStore.curComponent
})

const propValue = computed(()=>{
  return curComponent.value.propValue || {};
})

const copyText = ()=>{
  let flag = copyToClipboard(propValue.value.text);
  if (flag) {
    showMessage("success","复制成功");
  } else {
    showMessage("error","复制失败");
  }
}

</script>

<style lang="scss" scoped>

.attr-list {

  .el-form {
    padding:10px;
  }

  .el-form-item {
    margin-bottom: 4px;
    margin-right: 4px;
  }

  .common-item {
    width: 180px;
  }

  .common-item :deep(.el-input-group__append) {
    width: 24px;
    height: 32px;
    padding: 0 2px; /* 调整内边距 */
  }

  .picture-uploader {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    width: 50px;
  }

  .avatar-uploader .el-upload:hover {
    border-color: #409EFF;
  }

  .avatar-uploader-icon {
    font-size: 14px;
    color: #8c939d;
    width: 30px;
    height: 30px;
    line-height: 30px;
    text-align: center;
  }

  .avatar {
    width: 30px;
    height: 30px;
    display: block;
  }
}


</style>

TIP

VECommonAttr 是编辑器中提供的组件,即属性页签中的通用属性和通用样式等共性内容。

编辑器状态

通过编辑器的 Store 获取当前选中的组件对象。由于是多 Tab 编辑器模式,需要使用 useEditorStore 获取当前激活的 Tab 页签对应的编辑器。

javascript
import {useEditorStore} from "hflveditor3";

const props = defineProps(['pageId','formSize'])
const editorStore = useEditorStore(props.pageId);

const curComponent = computed(() => {
  return editorStore.curComponent
})

空属性编辑组件示例

如果组件不需要任何属性编辑,可以提供一个空的属性编辑组件,示例如下:

vue
<template>
  <div class="attr-list">
    <VECommonAttr :page-id="props.pageId" :form-size="props.formSize">
      <template #default>
        <el-form  :size="props.formSize" label-width="100px" label-position="left" style="padding:10px">
          
        </el-form>
      </template>
    </VECommonAttr>
  </div>
</template>

<script setup>
import {computed} from "vue";
import {useEditorStore} from "hflveditor3";
const props = defineProps(['pageId','formSize'])
const editorStore = useEditorStore(props.pageId);

const curComponent = computed(() => {
  return editorStore.curComponent
})

const propValue = computed(()=>{
  return curComponent.value.propValue || {};
})
</script>

<style lang="scss" scoped>
.attr-list {
  .el-form {
    padding:10px;
  }

  .el-form-item {
    margin-bottom: 4px;
    margin-right: 4px;
  }

  .common-item {
    width: 180px;
  }
}
</style>

组件注册

WARNING

示例中的属性编辑组件内部并没有包含注册命令的代码,这是因为通过统一安装时进行命名。开发者可根据自己的习惯选择在组件内部注册还是统一处理。

javascript
const svgComponents = ['SVGWenBen', 'SVGDataText']

svgComponents.forEach((key) => {
	app.component(`${key}Attr`, defineAsyncComponent(() => import(`@/custom-components/svg/${key}/Attr.vue`)))
	app.component(`${key}Data`, defineAsyncComponent(() => import(`@/custom-components/svg/${key}/Data.vue`)))
})

基于 VitePress 构建