Skip to main content

如何比较版本号大小

· One min read
陈碧滔
Front End Engineer
tip

比较两个版本号大小的 JavaScript 函数,支持如“1.1.1”、“1.12.10”、“0.0.1”、“0.0.0”、“2.0.0”这样的版本号格式

function App() {
  /**
   * 比较两个版本号的大小
   * @param {string} v1 - 版本号1,例如 '1.1.1'
   * @param {string} v2 - 版本号2,例如 '1.12.10'
   * @returns {number} - 如果v1 > v2返回1,v1 < v2返回-1,相等返回0
   */
  function compareVersion(v1, v2) {
      const arr1 = v1.split('.').map(Number);
      const arr2 = v2.split('.').map(Number);
      const len = Math.max(arr1.length, arr2.length);

      for (let i = 0; i < len; i++) {
          const num1 = arr1[i] || 0;
          const num2 = arr2[i] || 0;
          if (num1 > num2) return 1;
          if (num1 < num2) return -1;
      }
      return 0;
  }
  return (<div>
    <p>{compareVersion("1.1.1", "1.12.10")}</p>
    <p>{compareVersion("1.12.10", "1.1.1")}</p>
    <p>{compareVersion("1.1.1", "1.1.1")}</p>
  </div>)
}
输出结果:
function App() {
  /**
   * 比较两个版本号的大小
   * @param {string} v1 - 版本号1,例如 '1.1.1'
   * @param {string} v2 - 版本号2,例如 '1.12.10'
   * @returns {number} - 如果v1 > v2返回1,v1 < v2返回-1,相等返回0
   */
  function compareVersion(v1, v2) {
      const arr1 = v1.split('.').map(Number);
      const arr2 = v2.split('.').map(Number);
      const len = Math.max(arr1.length, arr2.length);

      for (let i = 0; i < len; i++) {
          const num1 = arr1[i] || 0;
          const num2 = arr2[i] || 0;
          if (num1 > num2) return 1;
          if (num1 < num2) return -1;
      }
      return 0;
  }
  const versions = ["1.1.1.1", "1.1.1", "1.9.10", "0.0.1", "0.0.0", "2.0.0"];
  versions.sort(compareVersion);
  return (<div>
    <p>排序:{versions.join(", ")}</p>
  </div>)
}
输出结果:

在 Docusaurus MDX 中使用 ReactLive 的案例

· 3 min read
陈碧滔
Front End Engineer

你可以在 Docusaurus 的 MDX 文件中这样使用 ReactLive 组件,实现代码片段和运行结果的互动演示。

官方文档 https://nearform.com/open-source/react-live/docs/

先实现代码

import React from 'react';
import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live';

type ReactLiveDemoProps = {
code: string;
liveProps?: React.ComponentProps<typeof LiveProvider>;
};

export default function ReactLiveDemo({ code, liveProps = {} }: ReactLiveDemoProps) {
return (
<LiveProvider code={code} {...liveProps}>
<LiveEditor />
<LiveError />
<div>
<strong>输出结果:</strong>
<LivePreview />
</div>
</LiveProvider>
);
}

下面分别演示了几个不同场景:

场景一:基础累加

import ReactLiveDemo from "./ReactLiveDemo";

export default function Demo() {
let code = `function App() {
function add(...args: number[]) {
return args.reduce((a, b) => a + b, 0);
}
return (<div>{add(1, 2, 3)}</div>)
}`

return (
<ReactLiveDemo
code={code}
liveProps={{
language: "ts",
noInline: false,
typescript: true,
}}
/>
);
}

预览

function App() {
  function add(...args: number[]) {
    return args.reduce((a, b) => a + b, 0);
  }
  return (<div>{add(1, 2, 3)}</div>)
}
输出结果:

场景二:链式调用

import { ReactLiveDemo } from "./ReactLive";

export default function Demo() {
let code = `
function App() {
function add(...args: number[]) {
let sum = Array.isArray(args) ? args.reduce((a, b) => a + b, 0) : 0;
function inner(...next: number[]) {
sum += Array.isArray(next) ? next.reduce((a, b) => a + b, 0) : 0;
return inner;
}
inner.valueOf = () => sum;
inner.toString = () => sum.toString();
return inner;
}
return (<div>{+add(1)(2)(3)}</div>);
}
`

return (
<ReactLiveDemo
code={code}
liveProps={{
language: "ts",
noInline: false,
typescript: true,
}}
/>
);
}

预览


    function App() {
      function add(...args: number[]) {
        let sum = Array.isArray(args) ? args.reduce((a, b) => a + b, 0) : 0;
        function inner(...next: number[]) {
          sum += Array.isArray(next) ? next.reduce((a, b) => a + b, 0) : 0;
          return inner;
        }
        inner.valueOf = () => sum;
        inner.toString = () => sum.toString();
        return inner;
      }
      return (<div>{+add(1)(2)(3)}</div>);
    }
  
输出结果:

场景三:多参数混合调用

import { ReactLiveDemo } from "./ReactLive";

export default function Demo() {
let code = `
function App() {
function add(...args: number[]) {
let sum = Array.isArray(args) ? args.reduce((a, b) => a + b, 0) : 0;
function inner(...next: number[]) {
sum += Array.isArray(next) ? next.reduce((a, b) => a + b, 0) : 0;
return inner;
}
inner.valueOf = () => sum;
inner.toString = () => sum.toString();
return inner;
}
return <div>{+add(1, 2)(3)}</div>;
}
`

return (
<ReactLiveDemo
code={code}
liveProps={{
language: "ts",
noInline: false,
typescript: true,
}}
/>
);
}

预览


    function App() {
      function add(...args: number[]) {
        let sum = Array.isArray(args) ? args.reduce((a, b) => a + b, 0) : 0;
        function inner(...next: number[]) {
          sum += Array.isArray(next) ? next.reduce((a, b) => a + b, 0) : 0;
          return inner;
        }
        inner.valueOf = () => sum;
        inner.toString = () => sum.toString();
        return inner;
      }
      return <div>{+add(1, 2)(3)}</div>;
    }
  
输出结果:

场景四:编辑器主题和配置自定义

你可以通过 liveProps 传递更多参数,定制编辑器行为,例如设置只读、不同的主题、是否内联运行等:

<ReactLiveDemo
code={`const hello: string = "Hello, Docusaurus!";
<div>{hello}</div>`}
liveProps={{
language: "ts",
theme: { plain: { backgroundColor: "#222", color: "#fff" } },
disabled: true
}}
/>

场景五:只展示代码(不运行)

如果只想展示代码,不显示运行结果,可以通过在外层自定义隐藏 LivePreview

<ReactLiveDemo
code={`function foo() { return "bar"; }`}
liveProps={{
language: "ts",
noInline: false,
theme: { plain: { backgroundColor: "#fafafa" } }
}}
/>

使用vue组件

· One min read
陈碧滔
Front End Engineer

Blog posts support Docusaurus Markdown features, such as MDX.

tip

使用vue组件


// 引入转换包

import { uvc } from 'use-vue-component';

// 引入vue组件

import test from '@site/src/components/vue/test.vue';

// 转换

export const HelloWorld = uvc(test);

<HelloWorld />


// 引入vue组件

import hello from '@site/src/components/vue/hello.vue';

// 转换

export const Hello = uvc(hello);

// 传参
<Hello name="john" />

注意,import和export的前后都必须空一行

为什么还要学习js创建html这些基础

· 4 min read
陈碧滔
Front End Engineer

学习 JavaScript(JS)、HTML 等基础技术依然很重要,尽管如今有许多高级框架和工具可以大大简化开发流程。这是因为:

1. 理解核心原理

  • 框架和工具都是基于基础构建的:现代前端框架如 React、Vue、Angular 都是基于 JavaScript 和 HTML 的。如果没有对这些基础的深入理解,遇到复杂问题时会很难理解框架背后的原理,也就更难进行调试和优化。
  • 灵活应对需求变化:很多情况下,现成的框架或库不能满足特定的需求,开发者可能需要手动编写 JavaScript 或 HTML 来处理一些定制化的功能。

2. 提升调试和问题解决能力

  • 排查问题:在实际开发中,浏览器调试工具(如 Chrome DevTools)依赖于 HTML、CSS、JavaScript 的基础知识。当你遇到问题(例如样式错乱或功能异常)时,必须清楚地理解这些基础才能快速找到问题根源。
  • 调试框架:即使使用框架,前端应用中也可能会出现与浏览器渲染或事件处理相关的低级问题,掌握基础技术有助于你追踪问题到源头。

3. 更高效的学习框架和库

  • 减少学习曲线:框架和库的很多概念都是对基础技术的扩展或优化。如果基础不牢固,学习新框架时会遇到很多障碍。理解 JavaScript 的原生 DOM 操作和事件模型后,学习框架中的虚拟 DOM 或事件机制时会更加顺畅。
  • 掌握更多选择:不同项目可能会使用不同的框架,有些项目甚至可能没有使用框架。掌握基础可以让你在不同环境下更好地适应和选择工具。

4. 开发性能优化

  • 页面优化:通过了解 HTML 和 JavaScript,你可以更好地理解页面性能的瓶颈,如加载速度、渲染阻塞等。掌握基础后,你可以通过优化 DOM 操作、减少重绘、优化图片资源等方式提升页面性能。
  • 内存和计算效率:JavaScript 是浏览器的运行语言,理解如何高效处理数据和管理事件循环能帮助你编写更高效的代码,避免内存泄漏和页面卡顿等问题。

5. 跨平台开发和全栈能力

  • 前端与后端的沟通:如今的 Web 开发经常涉及到前后端协作,比如通过 API 获取数据、管理状态等。理解 JavaScript、HTML 等前端技术有助于你更好地与后端开发人员协作,并设计出更流畅的交互体验。
  • 全栈开发:Node.js 和前端的 JavaScript 是同一个语言。掌握 JavaScript 后,你可以扩展到后端开发,实现全栈开发能力,这能大大提升你的开发效率和市场竞争力。

6. 增强创造力和自由度

  • 自由实现创意:基础技术让你不受限于现成的库和框架,你可以直接实现自己想要的效果。比如有些动画效果或者交互设计,框架可能不能很好地支持,但你可以通过原生 JS 和 HTML 轻松实现。
  • 深入自定义:你可以根据需求调整和自定义框架中的功能,而不是被现有工具所限制。

7. 前端生态系统的多样性

  • 持续变化的技术栈:前端技术发展非常迅速,新的框架和库层出不穷。但基础技术——HTML、CSS、JavaScript——始终是网页开发的核心。即使有新的工具出现,掌握基础能让你快速适应新的趋势和技术。

总之,学习 JavaScript 和 HTML 这些基础技术,能让你在开发中有更大的灵活性和创造力,帮助你解决更复杂的问题,也为深入掌握前端开发打下坚实的基础。这些技术虽然看似基础,但它们是前端开发的根本,能够为你打开更广阔的可能性。

在ts中编写setTimeout

· 2 min read
陈碧滔
Front End Engineer

使用reactjs拥抱typescript

外部控制倒计时

倒计时 5 已停止

tip
import React, { useState, useEffect } from 'react';

interface Props {
countdown?: number; // 初始倒计时秒数
onEnd?: () => void; // 倒计时结束
onStop?: () => void; // 手动停止/暂停
onCompleted?: () => void; // 停止或结束都会执行
}

export default function CountdownTimer({
countdown = 10,
onEnd = () => {},
onStop = () => {},
onCompleted = () => {},
}: Props) {
const [count, setCount] = useState(countdown);
const [timer, setTimer] = useState<ReturnType<typeof setTimeout> | null>(null);
const [isRunning, setIsRunning] = useState(false);

// 启动倒计时
const start = (currentCount = count) => {
if (timer) clearTimeout(timer); // 避免重复定时器
setIsRunning(true);
setCount(currentCount);

if (currentCount > 0) {
const timerId = setTimeout(() => {
start(currentCount - 1);
}, 1000);
setTimer(timerId);
} else {
// 倒计时结束
setIsRunning(false);
onEnd();
onCompleted();
}
};

// 暂停倒计时
const pause = () => {
if (timer) {
clearTimeout(timer);
setTimer(null);
}
setIsRunning(false);
onStop();
onCompleted();
};

// 继续倒计时
const resume = () => {
if (!isRunning && count > 0) {
start(count);
}
};

// 重置倒计时
const reset = () => {
if (timer) {
clearTimeout(timer);
setTimer(null);
}
setCount(countdown);
setIsRunning(false);
};

// 卸载时清理定时器
useEffect(() => {
return () => {
if (timer) clearTimeout(timer);
};
}, [timer]);

return (
<div>
<div>
倒计时 {count} {isRunning ? '进行中' : '已停止'}
</div>
<div style={{ marginTop: 8 }}>
<button onClick={() => start(countdown)}>开始</button>
<button onClick={pause} disabled={!isRunning}>暂停</button>
<button onClick={resume} disabled={isRunning || count === 0}>继续</button>
<button onClick={reset}>重置</button>
</div>
</div>
);
}