Skip to content

带有 title 的分割线

带有 title 的分割线

这就是title
这就是title
这就是title
这就是title
这就是title
这就是title3
这就是title2
这就是title
这就是title
调用代码展示
vue
<script setup lang="ts">
import Line from "./Line.vue";
import LineTsx from "./index.tsx";
</script>

<template>
  <Line style="margin-top: 20px" title="这就是title" lineStyle="dashed" :lineWidth="5"></Line>
  <Line style="margin-top: 20px" title="这就是title" :position="'center'" lineStyle="dotted" color="rgb(206, 46, 17)"></Line>
  <Line style="margin-top: 20px" title="这就是title" :position="'right'"></Line>
  <Line style="margin-top: 20px" :title="['这就是title']" :position="['left', 'center']"></Line>
  <Line style="margin-top: 20px" :title="['这就是title', '这就是title2', '这就是title3']" :position="['right', 'center', 'left']">
  </Line>
  <LineTsx style="margin-top: 20px" title="这就是title" lineStyle="dashed" :lineWidth="2" :color="`rgb(206, 46, 17)`"
    position="center">
  </LineTsx>
</template>
组件源码
vue
<!--
 /** author:Jinke Yan
     time:2023-04-17 18:32:17
 */
-->

<template>
  <div class="line">
    <div v-if="isShow('left')" class="line-text line-left">
      {{ viewTitle("left") }}
    </div>
    <div class="line-online" :style="computedLineStyle"></div>
    <div v-if="isShow('center')" class="line-text line-center">
      {{ viewTitle("center") }}
    </div>
    <div class="line-online" :style="computedLineStyle"></div>
    <div v-if="isShow('right')" class="line-text line-right">
      {{ viewTitle("right") }}
    </div>
  </div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import type { StyleValue } from "vue";
import type { position, numberRange10, color, lineStyle } from "docs/types";

interface Props {
  lineTitle: string | string[];
  linePosition: position | position[];
}
const props = withDefaults(
  defineProps<{
    title?: Props["lineTitle"];
    position?: Props["linePosition"];
    lineWidth?: numberRange10;
    color?: color;
    lineStyle?: lineStyle;
  }>(),
  {
    title: "",
    position: "left",
    lineWidth: 1,
    color: "rgb(220, 220, 220)",
    lineStyle: "solid",
  }
);

const computedLineStyle = computed<StyleValue>(() => {
  return {
    flex: 1,
    borderTop: `${props.lineWidth}px ${props.lineStyle} ${props.color}`,
  };
});

const isShow = (position: position): boolean => {
  const positionArray = Array.isArray(props.position)
    ? props.position
    : [props.position];
  return positionArray.includes(position);
};
const viewTitle = (position: position): string => {
  const titleArray = Array.isArray(props.title) ? props.title : [props.title];
  const positionArray = Array.isArray(props.position)
    ? props.position
    : [props.position];
  return titleArray[
    Math.min(titleArray.length - 1, positionArray.indexOf(position))
  ];
};
</script>

<style lang="scss" scoped>
@import "./style.module.scss";
</style>
TSX 写法组件源码
tsx
import { defineComponent, computed } from "vue";
import type { PropType } from "vue";
import type { position, numberRange10, color, lineStyle } from "docs/types";
import style from "./style.module.scss";

interface Props {
  lineTitle: string | string[];
  linePosition: position | position[] | "line";
}
type domType = position | "line";
export default defineComponent({
  name: "Line",
  props: {
    title: {
      type: String as PropType<Props["lineTitle"]>,
      default: "",
    },
    position: {
      type: String as PropType<Props["linePosition"]>,
      default: "left",
    },
    lineWidth: {
      type: Number as PropType<numberRange10>,
      default: 1,
    },
    color: {
      type: String as PropType<color>,
      default: "rgb(220, 220, 220)",
    },
    lineStyle: {
      type: String as PropType<lineStyle>,
      default: "solid",
    },
  },
  setup(props) {
    // 获取插槽数据
    const computedLineStyle = computed(() => {
      return {
        flex: 1,
        borderTop: `${props.lineWidth}px ${props.lineStyle} ${props.color}`,
      };
    });
    const isShow = (position: position): boolean => {
      const positionArray = Array.isArray(props.position)
        ? props.position
        : [props.position];
      return positionArray.includes(position);
    };
    const viewTitle = (position: position): string => {
      const titleArray = Array.isArray(props.title)
        ? props.title
        : [props.title];
      const positionArray = Array.isArray(props.position)
        ? props.position
        : [props.position];
      return titleArray[
        Math.min(titleArray.length - 1, positionArray.indexOf(position))
      ];
    };

    const itemTypeArr: domType[] = ["left", "line", "center", "line", "right"];
    // 渲染组件
    return () => (
      <div class={style.line}>
        {itemTypeArr.map((item) => {
          return item === "line" ? (
            <div class={style.line} style={computedLineStyle.value}></div>
          ) : (
            isShow(item) && (
              <div class={(style.lineText, style[`line-${item}`])}>
                {viewTitle(item)}
              </div>
            )
          );
        })}
      </div>
    );
  },
});
样式外联
scss
.line {
  width: 100%;
  display: flex;
  align-items: center;
  .line-text {
    font-weight: bold;
  }
  &-online {
    transform: scaleY(0.5);
  }
  &-left {
    margin-right: 12px;
  }
  &-center {
    margin-right: 12px;
    margin-left: 12px;
  }
  &-right {
    margin-left: 12px;
  }
}