Skip to content

简单的滚动效果

VueToCounter 提供了下列组件,他们用于滚动不同类型的数据:

仅使用默认的配置,即可获得一个看起来不错的滚动效果。

TIP

点击 按钮,观察数值的改变。

使数字滚动

想像一下,现实生活中的水表,它会不断地滚动,显示当前的用水量。VueToCounter 可以帮助你实现这样的效果。

水表
CC BY-SA 3.0, Link
CodeSandbox Logo

011011044055011044


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

const number = ref(114514);

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

<template>
  <div class="text-center">
    <vue-to-counter-number :value="number" />
  </div>
  <hr />
  <div class="flex gap-4">
    <input class="border border-solid p-1" v-model="number" />
    <button class="border border-solid p-1" @click="switchNumber">切换</button>
  </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>

倒计时效果

我相信你已经见过很多的倒计时,但大部分的变化是生硬的,没有过渡。VueToCounter 可以让你的倒计时效果更加平滑。

CodeSandbox Logo


~

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

const from = ref("2024-12-01T00:00:00");
const to = ref("2024-12-31T00:05:30");

function switchDatetime() {
  [from.value, to.value] = [to.value, from.value];
}

const precision = ref(DurationPartType.Second);
</script>

<template>
  <div class="text-center">
    <vue-to-counter-datetime-duration
      :value="[from, to]"
      :precision="precision"
    />
  </div>
  <hr />
  <div class="flex gap-4">
    <div>
      <input
        class="border border-solid p-1"
        v-model="from"
        type="datetime-local"
      />
      ~
      <input
        class="border border-solid p-1"
        v-model="to"
        type="datetime-local"
      />
    </div>
    <button class="border border-solid p-1" @click="switchDatetime">
      切换
    </button>
  </div>
  <div class="flex gap-4 mt-4">
    <label>
      时间范围精度
      <select
        class="border border-solid p-1 appearance-auto"
        v-model="precision"
      >
        <option
          v-for="precision in [
            DurationPartType.Year,
            DurationPartType.Month,
            DurationPartType.Day,
            DurationPartType.Hour,
            DurationPartType.Minute,
            DurationPartType.Second,
          ]"
          :key="precision"
          :value="precision"
        >
          {{ precision }}
        </option>
      </select>
    </label>
  </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>

字符串也可以滚动

看到首页上那个会动的标题了吗?在静态网页上,这样的效果会让你的页面更加生动。

TIP

请注意,默认配置下最长支持 17 个字符。如果你需要更多的字符长度,请参阅如何解除字符长度限制

CodeSandbox Logo

0HH0ee0ll0ll0oo0,,0  0WW0oo0rr0ll0dd0!!


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

const string = ref("Hello, World!");

const strings = [
  "Hello, World!",
  "你好,世界!",
  "こんにちは、世界!",
  "안녕하세요, 세계!",
  // 太长了
  // "Bonjour, le monde!",
  "Hallo, Welt!",
  "Ciao, mondo!",
  "Olá, mundo!",
  "Привет, мир!",
  "¡Hola, mundo!",
  "Hej, världen!",
  "Merhaba, Dünya!",
  "مرحبا بالعالم!",
  "שלום, עולם!",
  "नमस्ते, दुनिया!",
  "سلام دنیا!",
];
let stringIndex = 0;
function switchString() {
  stringIndex = (stringIndex + 1) % strings.length;
  string.value = strings[stringIndex];
}
</script>

<template>
  <div class="text-center">
    <vue-to-counter-string :value="string" />
  </div>
  <hr />
  <div class="flex gap-4">
    <input class="border border-solid p-1" v-model="string" />
    <button class="border border-solid p-1" @click="switchString">切换</button>
  </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>

下一步