Skip to content

自定义样式

自定义颜色

为了更容易观察填充颜色变化,调大了字体。

CodeSandbox Logo

0110110440,,055011044

你还可以将下列属性作为文本颜色:

点击查看代码
vue
<script setup>
import { ref } from "vue";

const number = ref(114514);

function switchNumber() {
  number.value = Math.floor(Math.random() * 1000000);
}

const color = ref(
  "#" +
    Math.floor(Math.random() * 16777215)
      .toString(16)
      .padStart(6, "0")
);
</script>

<template>
  <div class="text-center">
    <vue-to-counter-number
      class="!text-8xl font-bold"
      :value="number"
      :color="color"
      locale-number
    />
  </div>
  <hr />
  <div class="flex gap-4">
    <input class="border border-solid p-1" v-model="number" type="number" />
    <button class="border border-solid p-1" @click="switchNumber">切换</button>
    <span class="flex-auto" />
    <input class="border border-solid p-1" v-model="color" type="color" />
  </div>
  <div class="flex flex-col mt-4">
    <div>你还可以将下列属性作为文本颜色:</div>
    <ol>
      <li>
        <label>
          <input
            type="radio"
            name="color"
            value="linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet)"
            v-model="color"
          />
          CSS 渐变属性
        </label>
      </li>
      <li>
        <label>
          <input
            type="radio"
            name="color"
            value="url('https://picsum.photos/400/300')"
            v-model="color"
          />
          CSS 图片属性(加载图片时会有一段空白时间)
        </label>
      </li>
      <li>
        <label>
          <input
            type="radio"
            name="color"
            value="linear-gradient(rgba(255, 0, 0, 0.4), rgba(0, 0, 255, 0.4)), url('https://picsum.photos/400/300')"
            v-model="color"
          />
          CSS 渐变属性 + 图片属性
        </label>
      </li>
    </ol>
  </div>
  <div class="flex gap-4"></div>
</template>

<style scoped></style>
vue
<script setup>
import StackblitzLogo from "../assets/stackblitz-logo.svg";
import { ref, toRefs } from "vue";
import { getCodeStackblitzParams } from "./generate-stackblitz-params";
import sdk from "@stackblitz/sdk";
import packageInfo from "../../vue-to-counter/package.json";

const props = defineProps({
  title: {
    type: String,
    required: true,
  },
});
const { title } = toRefs(props);

const containerRef = ref();

function handleStackblitz() {
  if (!containerRef.value) return;

  const tabs = containerRef.value.querySelectorAll(".tabs > label");
  const blocks = containerRef.value.querySelectorAll(".blocks > div code");
  if (tabs.length !== blocks.length) {
    window.alert("The number of tabs and code blocks should be the same.");
    return;
  }

  const files = Array.from(tabs).map((tab, index) => ({
    filename: tab.textContent.trim(),
    content: blocks[index].textContent,
  }));

  const params = getCodeStackblitzParams(files, {
    title: `${title.value} - vue-to-counter@${packageInfo.version}`,
  });
  sdk.openProject(params, {
    openFile: "src/demo.vue",
  });
}
</script>

<template>
  <div ref="containerRef" class="demo-container">
    <div class="flex relative">
      <span class="flex-auto" />
      <span
        title="Open In Stackblitz"
        class="inline-block p-1 cursor-pointer hover:outline hover:outline-[#1389FD] outline-1"
        @click="handleStackblitz"
      >
        <img
          class="h-4 w-4 pointer-events-none"
          :src="StackblitzLogo"
          alt="CodeSandbox Logo"
        />
      </span>
    </div>
    <hr />
    <slot />
  </div>
</template>

<style lang="scss">
.demo-container {
  @apply flex flex-col justify-center border p-4 rounded-lg mt-4 text-sm;

  .vue-to-counter {
    @apply font-mono text-4xl;
  }

  .custom-block {
    @apply m-0;
  }
}
</style>

自定义字体

可以直接通过设置 CSS 属性来自定义字体的各种属性。

CodeSandbox Logo

0110110440,,055011044


点击查看代码
vue
<script setup>
import { ref } from "vue";
import GoogleFontPicker from "./GoogleFontPicker.vue";

const number = ref(114514);

function switchNumber() {
  number.value = Math.floor(Math.random() * 1000000);
}

const italic = ref(false);
const fontSize = ref(64);

const color = ref(
  "#" +
    Math.floor(Math.random() * 16777215)
      .toString(16)
      .padStart(6, "0")
);

const fontFamily = ref("");
</script>

<template>
  <div class="text-center">
    <vue-to-counter-number
      :value="number"
      :color="color"
      locale-number
      :style="{
        fontSize: fontSize + 'px',
        lineHeight: 1.2,
        fontStyle: italic ? 'italic' : 'normal',
        fontFamily: fontFamily,
      }"
    />
  </div>
  <hr />
  <div class="flex gap-4">
    <input class="border border-solid p-1" v-model="number" type="number" />
    <button class="border border-solid p-1" @click="switchNumber">切换</button>
    <span class="flex-auto" />
    <input class="border border-solid p-1" v-model="color" type="color" />
  </div>
  <div class="flex gap-4 mt-4">
    <label class="inline-flex gap-1 border border-solid p-1">
      斜体
      <input v-model="italic" type="checkbox" />
    </label>
    <label class="inline-flex gap-1 border border-solid p-1">
      字号
      <input v-model="fontSize" type="range" min="1" max="128" />
      {{ fontSize }}px
    </label>
  </div>
  <div class="flex gap-4 mt-4">
    <google-font-picker v-model="fontFamily" />
  </div>
</template>

<style scoped></style>
vue
<script setup>
import { ref, onMounted, watch, computed } from "vue";

const fonts = ref([]);
const searchQuery = ref("");
const selectedFont = defineModel("modelValue");

const fetchFonts = async () => {
  try {
    const response = await fetch(
      "https://www.googleapis.com/webfonts/v1/webfonts?" +
        new URLSearchParams({
          key: "AIzaSyBJPgjEPn1iDes5wLzDF-JMEst6QdR4skU",
          capability: "WOFF2",
          sort: "popularity",
        }).toString()
    ); // Replace with your Google Fonts API key
    const data = await response.json();
    fonts.value = data.items;
  } catch (error) {
    console.error("Error fetching fonts:", error);
  }
};

const filteredFonts = computed(() => {
  if (!searchQuery.value) {
    return fonts.value;
  }
  return fonts.value.filter((font) =>
    font.family.toLowerCase().includes(searchQuery.value.toLowerCase())
  );
});

const loadFont = (fontName) => {
  const link = document.createElement("link");
  link.href = `https://fonts.googleapis.com/css2?family=${fontName.replace(/ /g, "+")}&display=swap`;
  link.rel = "stylesheet";
  document.head.appendChild(link);
};

watch(selectedFont, (newFont) => {
  if (newFont) {
    loadFont(newFont);
  }
});

onMounted(async () => {
  await fetchFonts();
  selectedFont.value = "Ingrid Darling";

  // await nextTick();

  // document
  //   .querySelector(`#${selectedFont.value.replaceAll(" ", "-")}`)
  //   ?.scrollIntoView();
});

// 自动加载选择框中可见字体的预览menu字体
watch(
  filteredFonts,
  (newFonts) => {
    newFonts.forEach((font) => {
      const previewFamily = joinPreviewFamily(font.family);

      const fontFace = new FontFace(previewFamily, `url(${font.menu})`, {
        display: "swap",
      });
      document.fonts.add(fontFace);
    });
  },
  { immediate: true }
);
function joinPreviewFamily(family) {
  return [...family.split(" "), "PREVIEW"].join("-");
}
</script>

<template>
  <div class="flex-none flex flex-col">
    <input
      type="text"
      v-model="searchQuery"
      placeholder="Search for fonts"
      class="w-full border border-solid p-1 self-start"
    />
    <a
      href="https://developers.google.com/fonts"
      target="_blank"
      class="mt-1 text-xs"
    >
      Data provided by Google Fonts API
    </a>
  </div>
  <div
    class="flex-auto font-list-container border border-solid p-1 overflow-y-scroll h-64"
  >
    <div
      v-for="font in filteredFonts"
      :key="font.family"
      :id="font.family.replace(' ', '-')"
      :style="{ fontFamily: joinPreviewFamily(font.family) }"
      class="font-item p-2 cursor-pointer"
      :class="{
        'bg-gray-200': selectedFont === font.family,
      }"
      @click="selectedFont = font.family"
    >
      {{ font.family }}
    </div>
  </div>
</template>

<style scoped>
.font-list-container {
  max-height: 16rem;
}
.font-item:hover {
  background-color: #f0f0f0;
}
</style>
vue
<script setup>
import StackblitzLogo from "../assets/stackblitz-logo.svg";
import { ref, toRefs } from "vue";
import { getCodeStackblitzParams } from "./generate-stackblitz-params";
import sdk from "@stackblitz/sdk";
import packageInfo from "../../vue-to-counter/package.json";

const props = defineProps({
  title: {
    type: String,
    required: true,
  },
});
const { title } = toRefs(props);

const containerRef = ref();

function handleStackblitz() {
  if (!containerRef.value) return;

  const tabs = containerRef.value.querySelectorAll(".tabs > label");
  const blocks = containerRef.value.querySelectorAll(".blocks > div code");
  if (tabs.length !== blocks.length) {
    window.alert("The number of tabs and code blocks should be the same.");
    return;
  }

  const files = Array.from(tabs).map((tab, index) => ({
    filename: tab.textContent.trim(),
    content: blocks[index].textContent,
  }));

  const params = getCodeStackblitzParams(files, {
    title: `${title.value} - vue-to-counter@${packageInfo.version}`,
  });
  sdk.openProject(params, {
    openFile: "src/demo.vue",
  });
}
</script>

<template>
  <div ref="containerRef" class="demo-container">
    <div class="flex relative">
      <span class="flex-auto" />
      <span
        title="Open In Stackblitz"
        class="inline-block p-1 cursor-pointer hover:outline hover:outline-[#1389FD] outline-1"
        @click="handleStackblitz"
      >
        <img
          class="h-4 w-4 pointer-events-none"
          :src="StackblitzLogo"
          alt="CodeSandbox Logo"
        />
      </span>
    </div>
    <hr />
    <slot />
  </div>
</template>

<style lang="scss">
.demo-container {
  @apply flex flex-col justify-center border p-4 rounded-lg mt-4 text-sm;

  .vue-to-counter {
    @apply font-mono text-4xl;
  }

  .custom-block {
    @apply m-0;
  }
}
</style>