Skip to content

静态文本组件

在构建页面中,通常需要一个文本组件来展示静态的文本信息,本例SVGWenBen组件便是一个静态的文本组件,从名称就可以看出它是一个以SVG来构建的文本展示组件。

代码如下

vue
<template>
  <div class="svg-container"
       :style="customStyle"
       @click="handleClick" @dblclick="handleDblClick" @contextmenu="openContextMenu">
    <svg xmlns="http://www.w3.org/2000/svg" :width="element.style.width" :height="element.style.height">
      <rect v-if="propValue.hasBackground" :x="1" :y="1" :width="element.style.width-2" :height="element.style.height-2"
            :rx="propValue.rx" :ry="propValue.ry"
            :fill="propValue.fillColor?propValue.fillColor:'none'" :stroke="propValue.strokeColor"
            :fill-opacity="propValue.fillOpacity" :stroke-opacity="propValue.strokeOpacity"
            :stroke-width="propValue.strokeWidth"></rect>
      <text :x="textX" :y="textY" :dx="propValue.dx"
            :fill="propValue.fontColor?propValue.fontColor:'none'"
            :dominant-baseline="textBaseLine"
            :text-anchor="textAnchor"
            :font-family="propValue.fontFamily"
            :font-size="propValue.fontSize"
            :font-weight="propValue.fontWeight"
      >{{ propValue.text }}
      </text>
    </svg>
  </div>
</template>

<script setup>
import {useEventHandler, useDataCacheStore, createSmartAccessor, CreateCompContext, CommonUtils} from "hflvloader";
import {
  watch,
  onMounted,
  computed,
  ref,
  onBeforeMount,
  onBeforeUnmount,
  onUnmounted,
  onActivated,
  onDeactivated
} from "vue";
import {useRoute, useRouter} from "vue-router";
import ContextMenu from '@imengyu/vue3-context-menu'
import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css'
import {useMenuHandler} from "@/common/useMenuHandler.js";
import {getCursorByEvents} from "@/common/useCursorManager.js";

defineOptions({
  name: 'SVGWenBen'
});


const props = defineProps({
  propValue: {
    type: Object,
    required: true,
    default: () => {
    }
  },
  element: {
    type: Object,
    default: () => {
    }
  },
  designStatus: {
    type: Boolean,
    default: false
  }
})

const eventHandler = ref(null);

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

const element = computed(() => {
  return props.element || {};
})

const events = computed(() => {
  return element.value.events || [];
})


const textX = ref(0);
const textY = ref(0);
const textBaseLine = ref('');
const textAnchor = ref('');


const handleClick = (event) => {
  eventHandler.value?.handleClick(event);
}

const handleDblClick = (event)=>{
  eventHandler.value?.handleDblClick(event);
}

watch(() => element.value.style.width, (value) => {
  draw();
})

watch(() => element.value.style.height, (value) => {
  draw();
})

watch(() => propValue.value.horizontalAlign, (value) => {
  draw();
})

watch(() => propValue.value.offsetX, (value) => {
  draw();
})

const draw = () => {
  const {width, height} = props.element.style
  drawChart(width, height)
}

const drawChart = (width, height) => {
  let horizontalAlign = props.propValue.horizontalAlign || 'left';
  let offsetX = props.propValue.offsetX || 0;

  if ('center' == horizontalAlign) {
    textAnchor.value = 'middle'
    textX.value = width * 0.5
  } else if ('right' == horizontalAlign) {
    textX.value = width - offsetX
    textAnchor.value = 'end'
  } else {
    textX.value = 0 + offsetX
    textAnchor.value = 'start'
  }

  textBaseLine.value = 'central';
  textY.value = height * 0.5
}

const router = useRouter();
const route = useRoute();
const compContext = CreateCompContext(propValue, element, router, route);

onBeforeMount(() => {
  eventHandler.value = useEventHandler(events.value, props.designStatus, compContext);
  eventHandler.value?.beforeMount();
})

onMounted(() => {
  draw();
  eventHandler.value?.mounted();
})

onBeforeUnmount(() => {
  eventHandler.value?.beforeUnmount();
})

onUnmounted(() => {
  eventHandler.value?.unmounted();
})

onActivated(() => {
  eventHandler.value?.activated();
})

onDeactivated(() => {
  eventHandler.value?.deactivated();
})


defineExpose({
  handleClick
})

const {processMenus} = useMenuHandler();

const openContextMenu = (_event) => {
  _event.preventDefault();
  let _menuItems = propValue.value.menuItems || [];
  if (CommonUtils.isArray(_menuItems) && _menuItems.length > 0) {
    let _menuList = [];
    _menuList = processMenus(_menuItems, function (item, event) {
      eventHandler.value?.handleContextMenu(_event, item.value);
    })
    ContextMenu.showContextMenu({
      x: _event.x,
      y: _event.y,
      items: _menuList
    })
  }
}

const customStyle = computed(() => {
  let style = {}
  style['cursor'] = getCursorByEvents(events.value);
  return style;
})

</script>

<style lang="scss" scoped>
.svg-container {
  width: 100%;
  height: 100%;

  svg {
    width: 100%;
    height: 100%;
  }
}
</style>

基于 VitePress 构建