分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊

这篇具有很好参考价值的文章主要介绍了分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

2022年11月23日首发于掘金,现在同步到公众号。

11. 前言

大家好,我是若川。推荐点右上方蓝字若川视野把我的公众号设为星标。我倾力持续组织了一年多源码共读,感兴趣的可以加我微信 lxchuan12 参与。另外,想学源码,极力推荐关注我写的专栏《学习源码整体架构系列》,目前是掘金关注人数(4.6k+人)第一的专栏,写有20余篇源码文章。


我们开发业务时经常会使用到组件库,一般来说,很多时候我们不需要关心内部实现。但是如果希望学习和深究里面的原理,这时我们可以分析自己使用的组件库实现。有哪些优雅实现、最佳实践、前沿技术等都可以值得我们借鉴。

相比于原生 JS 等源码。我们或许更应该学习,正在使用的组件库的源码,因为有助于帮助我们写业务和写自己的组件。

如果是 Vue 技术栈,开发移动端的项目,大多会选用 vant 组件库,目前(2022-11-20)star 多达 20.5k,最新版本是 v4.0.0-rc7。我们可以挑选 vant 组件库学习,我会写一个组件库源码系列专栏[1],欢迎大家关注。

  • vant 4 即将正式发布,支持暗黑主题,那么是如何实现的呢

  • 跟着 vant4 源码学习如何用 vue3+ts 开发一个 loading 组件,仅88行代码

  • 分析 vant4 源码,如何用 vue3 + ts 开发一个瀑布流滚动加载的列表组件?

这次我们来学习倒计时组件,`countdown`[2]

学完本文,你将学到:

1. 如何开发一个更优雅的毫秒级渲染的倒计时组件
2. 学会使用 requestAnimationFrame
3. 等等

22. 准备工作

看一个开源项目,我们可以先看 README.md[3] 再看 github/CONTRIBUTING.md[4]

2.1 克隆源码

You will need Node.js >= 14[5] and pnpm[6].

# 推荐克隆我的项目
git clone https://github.com/lxchuan12/vant-analysis
cd vant-analysis/vant

# 或者克隆官方仓库
git clone git@github.com:vant-ui/vant.git
cd vant

# 安装依赖,如果没安装 pnpm,可以用 npm i pnpm -g 安装,或者查看官网通过其他方式安装
pnpm i

# 启动服务
pnpm dev

执行 pnpm dev 后,这时我们打开倒计时组件 http://localhost:5173/#/zh-CN/count-down

33. 倒计时组件可谓是十分常用

在各种电商类或者其他的移动端页面中,倒计时真的是太常见了。我们自己也基本能够快速的写一个倒计时组件。代码实现参考这里,主要是 JavaScript。码上掘金倒计时初步代码@若川[7]

代码中,我直接使用的 setInterval 和每秒钟执行一次。把倒计时的时候减去1s,当倒计时毫秒数不足时用 clearInterval 清除停止定时器。

但如果要实现毫秒级的倒计时这种方法行不通。 另外 setInterval 这种做法,并不是最优的。 那么,vant 倒计时组件中,是如何处理毫秒级和实现倒计时呢。

带着问题我们直接找到 countdown demo 文件:vant/packages/vant/src/count-down/demo/index.vue。为什么是这个文件,我在之前文章跟着 vant4 源码学习如何用 vue3+ts 开发一个 loading 组件,仅88行代码分析了其原理,感兴趣的小伙伴点击查看。这里就不赘述了。

44. 利用 demo 调试源码

组件源码中的 TS 代码我不会过多解释。没学过 TS 的小伙伴,推荐学这个TypeScript 入门教程[8]。 另外,vant 使用了 @vue/babel-plugin-jsx[9] 插件来支持 JSX、TSX

分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊
倒计时组件
// vant/packages/vant/src/count-down/demo/index.vue
<script setup lang="ts">
import VanGrid from '../../grid';
import VanGridItem from '../../grid-item';
import VanCountDown, { type CountDownInstance } from '..';
import { ref } from 'vue';
import { useTranslate } from '../../../docs/site';
import { showToast } from '../../toast';

const t = useTranslate({
  'zh-CN': {
    reset: '重置',
    pause: '暂停',
    start: '开始',
    finished: '倒计时结束',
    millisecond: '毫秒级渲染',
    customStyle: '自定义样式',
    customFormat: '自定义格式',
    manualControl: '手动控制',
    formatWithDay: 'DD 天 HH 时 mm 分 ss 秒',
  },
});

const time = ref(30 * 60 * 60 * 1000);
const countDown = ref<CountDownInstance>();

// 开始
const start = () => {
  countDown.value?.start();
};
// 暂停
const pause = () => {
  countDown.value?.pause();
};
// 重置
const reset = () => {
  countDown.value?.reset();
};
const onFinish = () => showToast(t('finished'));
</script>

<template>

  <!-- 基本使用 -->
  <demo-block :title="t('basicUsage')">
    <van-count-down :time="time" />
  </demo-block>

  <!-- 自定义渲染 -->
  <demo-block :title="t('customFormat')">
    <van-count-down :time="time" :format="t('formatWithDay')" />
  </demo-block>

  <!-- 毫秒级渲染 -->
  <demo-block :title="t('millisecond')">
    <van-count-down millisecond :time="time" format="HH:mm:ss:SS" />
  </demo-block>

  <!-- 自定义样式-->
  <demo-block :title="t('customStyle')">
    <van-count-down :time="time">
      <template #default="currentTime">
        <span class="block">{{ currentTime.hours }}</span>
        <span class="colon">:</span>
        <span class="block">{{ currentTime.minutes }}</span>
        <span class="colon">:</span>
        <span class="block">{{ currentTime.seconds }}</span>
      </template>
    </van-count-down>
  </demo-block>

  <!-- 手动控制 -->
  <demo-block :title="t('manualControl')">
    <van-count-down
      ref="countDown"
      millisecond
      :time="3000"
      :auto-start="false"
      format="ss:SSS"
      @finish="onFinish"
    />
    <van-grid clickable :column-num="3">
      <van-grid-item icon="play-circle-o" :text="t('start')" @click="start" />
      <van-grid-item icon="pause-circle-o" :text="t('pause')" @click="pause" />
      <van-grid-item icon="replay" :text="t('reset')" @click="reset" />
    </van-grid>
  </demo-block>
</template>

demo 文件中,我们可以看出 import VanCountDown, { type CountDownInstance } from '..';,引入自 vant/packages/vant/src/count-down/index.ts。我们继续来看入口 index.ts

55. 入口 index.ts

主要就是导出一下类型和变量等。

// vant/packages/vant/src/count-down/index.ts
import { withInstall } from '../utils';
import _CountDown from './CountDown';

export const CountDown = withInstall(_CountDown);
// 默认导出
// import xxx from 'vant'
export default CountDown;
export { countDownProps } from './CountDown';
export type { CountDownProps } from './CountDown';
export type {
  CountDownInstance,
  CountDownThemeVars,
  CountDownCurrentTime,
} from './types';

declare module 'vue' {
  export interface GlobalComponents {
    VanCountDown: typeof CountDown;
  }
}

withInstall 函数在之前文章5.1 withInstall 给组件对象添加 install 方法 也有分析,这里就不赘述了。

我们可以在这些文件,任意位置加上 debugger 调试源码。

截两张调试图。

调试 Countdown setup

分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊
调试 setup

调试 useCountDown

分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊
调试 useCountDown

我们跟着调试,继续分析 Countdown

66. 主文件 Countdown

// vant/packages/vant/src/count-down/CountDown.tsx
import { watch, computed, defineComponent, type ExtractPropTypes } from 'vue';

// Utils
import {
  truthProp,
  makeStringProp,
  makeNumericProp,
  createNamespace,
} from '../utils';
import { parseFormat } from './utils';

// Composables
import { useCountDown } from '@vant/use';
import { useExpose } from '../composables/use-expose';

const [name, bem] = createNamespace('count-down');

export const countDownProps = {
  time: makeNumericProp(0),
  format: makeStringProp('HH:mm:ss'),
  autoStart: truthProp,
  millisecond: Boolean,
};

export type CountDownProps = ExtractPropTypes<typeof countDownProps>;

export default defineComponent({
  name,

  props: countDownProps,

  emits: ['change', 'finish'],

  setup(props, { emit, slots }) {
    // 代码省略,下文叙述
  },
});

6.1 setup 部分

这一部分主要使用了useCountDown

setup(props, { emit, slots }) {
  // useCountDown 组合式 API
  const { start, pause, reset, current } = useCountDown({
    // 传入的时间毫秒数,+ 是字符串转数字
    time: +props.time,
    // 毫秒级渲染
    millisecond: props.millisecond,
    // 回调事件,onChange, onFinish
    onChange: (current) => emit('change', current),
    onFinish: () => emit('finish'),
  });

  // 格式化时间
  const timeText = computed(() => parseFormat(props.format, current.value));

  // 重置,重新开始
  const resetTime = () => {
    reset(+props.time);

    if (props.autoStart) {
      start();
    }
  };

  watch(() => props.time, resetTime, { immediate: true });

  // 导出 start、pause、reset
  useExpose({
    start,
    pause,
    reset: resetTime,
  });

  return () => (
    // 有传入插槽,使用插槽,支持自定义样式,传入解析后的时间对象
    <div role="timer" class={bem()}>
      {slots.default ? slots.default(current.value) : timeText.value}
    </div>
  );
},

6.2 useExpose 暴露

import { getCurrentInstance } from 'vue';
import { extend } from '../utils';

// expose public api
export function useExpose<T = Record<string, any>>(apis: T) {
  const instance = getCurrentInstance();
  // 合并到 getCurrentInstance().proxy 上
  if (instance) {
    extend(instance.proxy as object, apis);
  }
}

通过 ref 可以获取到 Countdown 实例并调用实例方法,详见组件实例方法[10]

Vant 中的许多组件提供了实例方法,调用实例方法时,我们需要通过 ref 来注册组件引用信息,引用信息将会注册在父组件的 $refs 对象上。注册完成后,我们可以通过 this.$refs.xxx 或者

const xxxRef = ref();
xxxRef.value.xxx();

访问到对应的组件实例,并调用上面的实例方法。

77. useCountDown 组合式 API

7.1 parseTime 解析时间

// vant/packages/vant-use/src/useCountDown/index.ts
import {
  ref,
  computed,
  onActivated,
  onDeactivated,
  onBeforeUnmount,
} from 'vue';
import { raf, cancelRaf, inBrowser } from '../utils';

export type CurrentTime = {
  days: number;
  hours: number;
  total: number;
  minutes: number;
  seconds: number;
  milliseconds: number;
};

export type UseCountDownOptions = {
  time: number;
  // 毫秒
  millisecond?: boolean;
  onChange?: (current: CurrentTime) => void;
  onFinish?: () => void;
};

const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;

// 解析时间
function parseTime(time: number): CurrentTime {
  const days = Math.floor(time / DAY);
  const hours = Math.floor((time % DAY) / HOUR);
  const minutes = Math.floor((time % HOUR) / MINUTE);
  const seconds = Math.floor((time % MINUTE) / SECOND);
  const milliseconds = Math.floor(time % SECOND);

  return {
    total: time,
    days,
    hours,
    minutes,
    seconds,
    milliseconds,
  };
}

以上这大段代码,parseTime 是主要函数,解析时间,生成天数、小时、分钟、秒、毫秒的对象。

7.2 useCountDown 真实逻辑

真实逻辑这一段可以不用细看。可以调试时再细看。

主要就是利用 Date.now() 会自己走的原理。

初始化开始:结束时间 = 当前时间戳 + 剩余时间
获取:剩余时间 = 结束时间 - 当前时间戳
加上自己定时器逻辑循环
剩余时间就是真实流逝的时间
如果是毫秒级渲染,就直接赋值剩余时间
如果不是,那就判断是同一秒才赋值

设计的十分巧妙,看到这里,我们可能感慨:不得不佩服。

// 简化版 一
const useCountDown = (options) => {
  let endTime;
  let remain = options.time;
  const getCurrentRemain = () => Math.max(endTime - Date.now(), 0);
  const start = () => {
    endTime = Date.now() + remain;
  }
  const setRemain = (value) => {
    remain = value;
  };
  return {
    start,
  }
}
const { start } = useCountDown({time: 3 * 1000});
start();

码上掘金倒计时简化版二

码上掘金倒计时简化版二@若川[11]

// vant/packages/vant-use/src/useCountDown/index.ts
function isSameSecond(time1: number, time2: number): boolean {
  return Math.floor(time1 / 1000) === Math.floor(time2 / 1000);
}

export function useCountDown(options: UseCountDownOptions) {
  let rafId: number;
  let endTime: number;
  let counting: boolean;
  let deactivated: boolean;

  const remain = ref(options.time);
  const current = computed(() => parseTime(remain.value));

  const pause = () => {
    counting = false;
    cancelRaf(rafId);
  };

  const getCurrentRemain = () => Math.max(endTime - Date.now(), 0);

  const setRemain = (value: number) => {
    remain.value = value;
    options.onChange?.(current.value);

    if (value === 0) {
      pause();
      options.onFinish?.();
    }
  };

  const microTick = () => {
    rafId = raf(() => {
      // in case of call reset immediately after finish
      if (counting) {
        setRemain(getCurrentRemain());

        if (remain.value > 0) {
          microTick();
        }
      }
    });
  };

  const macroTick = () => {
    rafId = raf(() => {
      // in case of call reset immediately after finish
      if (counting) {
        const remainRemain = getCurrentRemain();

        if (!isSameSecond(remainRemain, remain.value) || remainRemain === 0) {
          setRemain(remainRemain);
        }

        if (remain.value > 0) {
          macroTick();
        }
      }
    });
  };

  const tick = () => {
    // should not start counting in server
    // see: https://github.com/vant-ui/vant/issues/7807
    if (!inBrowser) {
      return;
    }

    if (options.millisecond) {
      microTick();
    } else {
      macroTick();
    }
  };

  const start = () => {
    if (!counting) {
      endTime = Date.now() + remain.value;
      counting = true;
      tick();
    }
  };

  const reset = (totalTime: number = options.time) => {
    pause();
    remain.value = totalTime;
  };

  // 组件被卸载之前被调用
  onBeforeUnmount(pause);

  // 激活
  onActivated(() => {
    if (deactivated) {
      counting = true;
      deactivated = false;
      tick();
    }
  });

  onDeactivated(() => {
    if (counting) {
      pause();
      deactivated = true;
    }
  });

  // 返回方法和当前时间对象
  return {
    start,
    pause,
    reset,
    current,
  };
}

我们继续来看 rafcancelRaf,是如何实现的。

88. raf、cancelRaf、inBrowser 实现

// 判断是不是浏览器环境,你可能会问,为啥要判断?因为 SSR (服务端渲染)不是浏览器环境。
export const inBrowser = typeof window !== 'undefined';

// Keep forward compatible
// should be removed in next major version
export const supportsPassive = true;

export function raf(fn: FrameRequestCallback): number {
  return inBrowser ? requestAnimationFrame(fn) : -1;
}

export function cancelRaf(id: number) {
  if (inBrowser) {
    cancelAnimationFrame(id);
  }
}

// double raf for animation
export function doubleRaf(fn: FrameRequestCallback): void {
  raf(() => raf(fn));
}

上文代码,主要一个 APIrequestAnimationFrame、cancelAnimationFrame

我们这里简单理解为 window.requestAnimationFrame() 中的回调函数,每 16.67ms 执行一次回调函数即可。

也就是类似 setTimeout、clearTimeout

const timeId = setTimeout( () => {
  // 16.67ms 执行一次
  console.log('16.67ms 执行一次');
}, 16.67);

clearTimeout(timeId);

也可以自行搜索这个 API 查阅更多资料。比如 MDN 上的解释。

mdn window.requestAnimationFrame[12]

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行

回调函数执行次数通常是每秒 60 次,但在大多数遵循 W3C 建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。

备注: 若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用 window.requestAnimationFrame()

99. 支持格式化时间,默认 HH:mm:ss

9.1 parseFormat 处理格式化

再来看看,组件中,是如何格式化时间的。这个值得我们参考。我们很多时候可能都是写死天数、小时等文案。不支持自定义格式化。

// vant/packages/vant/src/count-down/utils.ts
import { padZero } from '../utils';
import { CurrentTime } from '@vant/use';

export function parseFormat(format: string, currentTime: CurrentTime): string {
  const { days } = currentTime;
  let { hours, minutes, seconds, milliseconds } = currentTime;

  // 有 DD 参数,补零替换,没有则小时数加上天数
  if (format.includes('DD')) {
    format = format.replace('DD', padZero(days));
  } else {
    hours += days * 24;
  }

  // 有 HH 参数,补零替换,没有则分钟数加上小时数
  if (format.includes('HH')) {
    format = format.replace('HH', padZero(hours));
  } else {
    minutes += hours * 60;
  }

  // 有 mm 参数,补零替换,没有则秒数加上分钟数
  if (format.includes('mm')) {
    format = format.replace('mm', padZero(minutes));
  } else {
    seconds += minutes * 60;
  }

  // 有 mm 参数,补零替换,没有则毫秒数加上秒数
  if (format.includes('ss')) {
    format = format.replace('ss', padZero(seconds));
  } else {
    milliseconds += seconds * 1000;
  }

  // 毫秒数 默认补三位数,按照格式最终给出对应的位数
  if (format.includes('S')) {
    const ms = padZero(milliseconds, 3);

    if (format.includes('SSS')) {
      format = format.replace('SSS', ms);
    } else if (format.includes('SS')) {
      format = format.replace('SS', ms.slice(0, 2));
    } else {
      format = format.replace('S', ms.charAt(0));
    }
  }

  // 最终返回格式化的数据
  return format;
}

9.2 padZero 补零

// vant/packages/vant-compat/node_modules/vant/src/utils/format.ts
// 补零操作
export function padZero(num: Numeric, targetLength = 2): string {
  let str = num + '';

  while (str.length < targetLength) {
    str = '0' + str;
  }

  return str;
}

行文自此,我们就分析完了毫秒级渲染的倒计时组件的实现。

1010. 总结

我们来简单总结下。通过 demo 文件调试,入口文件,主文件,useCountDown 组合式 API,插槽等。 分析了自定义格式、毫秒级渲染、自定义样式(利用插槽)等功能的实现。

其中毫秒级渲染,主要就是利用 Date.now() 和 (window.requestAnimationFrame)每 16.67ms 执行一次回调函数。

大致流程如下:

初始化开始:结束时间 = 当前时间戳 + 剩余时间
获取:剩余时间 = 结束时间 - 当前时间戳
加上自己定时器逻辑循环(`window.requestAnimationFrame`)每 16.67ms 执行一次回调函数
剩余时间就是真实流逝的时间
如果是毫秒级渲染,就直接赋值剩余时间
如果不是,那就判断是同一秒才赋值

看完这篇源码文章,再去看 CountDown 组件文档[13],可能就会有豁然开朗的感觉。再看其他组件,可能就可以猜测出大概实现的代码了。

如果是使用 reactTaro 技术栈,感兴趣也可以看看 taroify CountDown 组件的实现 文档[14],源码[15]

如果看完有收获,欢迎点赞、评论、分享支持。你的支持和肯定,是我写作的动力

参考资料

[1]

组件库源码系列专栏: https://juejin.cn/column/7140264842954276871

[2]

countdown: https://vant-contrib.gitee.io/vant/v4/#/zh-CN/count-down

[3]

README.md: https://github.com/youzan/vant

[4]

github/CONTRIBUTING.md: https://github.com/youzan/vant/blob/main/.github/CONTRIBUTING.md

[5]

Node.js >= 14: https://nodejs.org

[6]

pnpm: https://pnpm.io

[7]

码上掘金倒计时初步代码@若川: https://code.juejin.cn/pen/7167966535649230883

[8]

TypeScript 入门教程: http://ts.xcatliu.com/

[9]

@vue/babel-plugin-jsx: https://www.npmjs.com/package/@vue/babel-plugin-jsx

[10]

组件实例方法: https://vant-contrib.gitee.io/vant/v4/#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa

[11]

码上掘金倒计时简化版二@若川: https://code.juejin.cn/pen/7168892330752081928

[12]

mdn window.requestAnimationFrame: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame

[13]

CountDown 组件文档: https://vant-contrib.gitee.io/vant/#/zh-CN/count-down

[14]

文档: https://taroify.gitee.io/taroify.com/components/countdown

[15]

源码: https://github.com/mallfoundry/taroify/tree/main/packages/core/src/countdown

分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经坚持写了8年,点击查看年度总结。
同时,持续组织了一年多源码共读活动,帮助5000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

扫码加我微信 lxchuan12、拉你进源码共读

今日话题

目前建有江西|湖南|湖北 籍 前端群,想进群的可以加我微信 lxchuan12 进群。分享、收藏、点赞、在看我的文章就是对我最大的支持~文章来源地址https://www.toymoban.com/news/detail-446190.html

到了这里,关于分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Vant4在Vue3.3中如何按需导入组件和样式

    Vant4在Vue3.3中如何按需导入组件和样式

    最近我在Vue 3.3的项目中对Vant4做按需导入时,尽管按照Vant4的官方指南进行操作,但样式仍然无法正确加载。经过深入研究和多篇文章的比较,我终于找到了在Vue3中如何正确的按需导入Vant 4组件和样式的方法。由于Vue3.3和Vant4相对较新,相关资料可能还不够完善,因此我认为

    2024年01月21日
    浏览(37)
  • 项目实战:《智慧线上购物商城》:基于vue3+vite+vant4组件(一)

    项目实战:《智慧线上购物商城》:基于vue3+vite+vant4组件(一)

    本项目主要是基于vue3和vite以及vant4组件所开发的移动端购物商城。项目没有接口,所运用的存储数据为json数据通过axios请求,以及Localstorage等技术实现数据。 开发的模型参考以下的网站,感兴趣的小伙伴可以去看看。 AxureShop原型演示 AxureShop原型演示 https://demo.axureshop.com/?

    2024年02月02日
    浏览(36)
  • # vue3 vant4 Tabbar 标签栏组件的封装 和Popup弹出层的封装

    # vue3 vant4 Tabbar 标签栏组件的封装 和Popup弹出层的封装

    需求如上,标签栏里第三个是图片,整个项目有两种场景, 标签栏正常跳转页面, 标签拦渲染别的图片时候,点击就是打开弹出层, 封装了标签栏,弹出层两部分,作为公共组件 标签栏的封装 徽标样式需要调整,list现在是自己暂时再state里写的假数据 下面是再使用标签组

    2024年01月20日
    浏览(69)
  • Vite + Vue3 +Vant4构建项目时,按需引入使用Toast组件,引用 showToast 时出现编译报错的解决方案

    Vite + Vue3 +Vant4构建项目时,按需引入使用Toast组件,引用 showToast 时出现编译报错的解决方案

    一.问题定位 在Vite + Vue3 +Vant4构建项目时,需要使用Toast组件显示提示信息,按照官方文档使用函数调用 使用后直接报错,说是找不到对应的样式文件(如下图): 在项目中查找node-moudles文件,确实没有找到,只有一个toast文件(如下图): 在百度搜索解决方法,说是需要单

    2024年01月17日
    浏览(41)
  • uniapp vue3版本+ts使用 vant小程序 组件库

    1.首先从uniapp官网下载vue3版本+ts的模板 2.安装vant微信小程序版本 3.在项目src目录创建wxcomponents文件夹,在wxcomponents文件夹下创建vant文件夹 4.从node_modules文件夹下的@vant文件夹里面的weapp,weapp下的dist文件夹,将dist文件夹里面的文件复制到/wxcomponents/vant 5.全局引用   在 pages

    2024年02月13日
    浏览(39)
  • 基于Vant组件库二次封装组件(TS+Vue3.x环境)

    基于Vant组件库二次封装组件(TS+Vue3.x环境)

    1. 今天的需求是封装一个 Navigation Bar 导航栏组件,目的是给到App几乎所有的页面复用:      2. 因为之前的项目里使用过Vant组件库,笔者第一时间想到了Vant组件库中的 NavBar 组件,和当前App的需求匹配度很高。Vant组件库的 NavBar 组件: 3. 相信你也发现了,Vant组件库默认主题

    2023年04月18日
    浏览(41)
  • 实用的开源应用全新开源源码Vue3+TS的前后台分离的开发平台源码开源技术社区平台

    实用的开源应用全新开源源码Vue3+TS的前后台分离的开发平台源码开源技术社区平台

    开源全新开源源码Vue3+TS的前后台分离的开发平台源码。创意、新奇、有趣、实用的开源应用、系统、软件、硬件及技术,一个探索、发现、分享、使用与互动交流的开源技术社区平台。致力于打造活力开源社区,共建开源新生态! 功能简介 个人办公:待办事项、抄送传阅、

    2024年02月13日
    浏览(74)
  • 【Vue H5项目实战】从0到1的自助点餐系统—— 搭建脚手架(Vue3.2 + Vite + TS + Vant + Pinia + Node.js)

    【Vue H5项目实战】从0到1的自助点餐系统—— 搭建脚手架(Vue3.2 + Vite + TS + Vant + Pinia + Node.js)

    H5 项目基于 Web 技术,可以在智能手机、平板电脑等移动设备上的浏览器中运行,无需下载和安装任何应用程序,且H5 项目的代码和资源可以集中在服务器端进行管理,只需更新服务器上的代码,即可让所有顾客访问到最新的系统版本。 本系列将以肯德基自助点餐页面为模板

    2024年02月13日
    浏览(53)
  • 【Vant4】Vant4 样式不显示问题 && Toast 轻提示不显示 && Notify 消息提示不显示

    【Vant4】Vant4 样式不显示问题 && Toast 轻提示不显示 && Notify 消息提示不显示

    使用 Toast 轻提示 和 Notify 消息提示 时没有样式,如下图 引入所需的样式,例如: 我要使用 消息提示 (Notify),就引入 import \\\'vant/es/notify/style\\\' 我要使用 轻提示 (Toast),就引入 import \\\'vant/es/toast/style\\\' HomeView.vue End 2023/3/7 一改 【Vue3】vue3的keepAlive保存滚动位置 CKEditor5 添加代码高亮

    2023年04月18日
    浏览(11)
  • 3d环形图开发(vue3+vite+ts)

    3d环形图开发(vue3+vite+ts)

    开发效果(待完善):   技术支持: Echarts  echarts-gl 安装: 注:echarts与echarts-gl版本需对应,可参考官网 pnpm add echarts@4.9.0 echarts-gl@1.1.2  组件封装:

    2024年02月07日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包