npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ui-type-writer

v1.0.7

Published

An NPM package/book that can have a typewriter like effect

Downloads

14

Readme

描述

An NPM package/book that can have a typewriter like effect

一个可以如同打字机效果的npm包/hook

效果

Untitled.gif

应用示例

1、模拟流式文本消息推送:

以下示例展示如何模拟SSE(Server-Sent Events)文本消息推送,模拟实时数据流的场景。

export const simulateWebSocketPush = (text, onDataReceived) => {
    const words = text.split(/([\s,。;:!、])/); // 在标点符号前后插入分隔符,以便保留标点符号
    let currentIndex = 0;

    // 模拟推送函数
    function pushNextChunk() {
        const chunkSize = Math.floor(Math.random() * 5) + 1; // 随机生成 1 到 5 的字数
        const currentChunk = words.slice(currentIndex, currentIndex + chunkSize).join('');
        currentIndex += chunkSize;

        // 模拟推送,实际中需要通过 WebSocket 推送给客户端
        // 这里将数据通过回调函数传递给调用方
        onDataReceived(currentChunk);

        // 继续推送,直到所有文字都被推送完
        if (currentIndex < words.length) {
            const interval = Math.floor(Math.random() * 500) + 1000; // 随机生成时间间隔
            setTimeout(pushNextChunk, interval);
        }
    }

    // 开始推送
    pushNextChunk();
};

2. 使用示例React

此示例展示如何在应用中模拟文本数据传入,实现打字机效果。

import {useEffect, useState} from 'react';
import {TypingWriter} from 'ui-type-writer';
import {simulateWebSocketPush} from '@/utils';
import {mockMarkdownStr} from '@/mock/index'

export default function App() {
    const [markdownContent, setMarkdownContent] = useState(' ');

    useEffect(
        () => {
        // 在组件挂载时开始模拟WebSocket推送
            simulateWebSocketPush(mockMarkdownStr, data => {
            // 这里处理每次推送的数据,可以将数据存储到状态中,或者进行其他操作
                // 在每次推送时拼接数据
                setMarkdownContent(data);
            });
            // 清理定时器或其他资源
            return () => {};
        },
        []
    );

    return (
        <TypingWriter text={markdownContent} />
    );
}

代码实现

实现打字机效果涉及三个部分:

  • 核心逻辑TypeWriterCore
  • Hook封装useTypeWriter
  • React组件实现TypeWriter Components 三个部分业务侧可按需取用,以下部分将详细介绍每一部分的实现逻辑及关键代码。

1. TypeWriterCore.ts - 打字机核心逻辑

TypeWriterCore.ts文件中定义了TypeWriterCore类,这个类封装了打字机效果的核心逻辑。通过构造函数,我们可以传入不同的配置选项,如打字速度、暂停时间等,以适应不同的使用场景。

interface TypeWriterCoreOptions {
    onConsume: (str: string) => void; // 定义一个回调函数,用于消费(处理)字符
    maxStepSeconds?: number; // 可选属性,定义最大步进间隔(毫秒)
}

export default class TypeWriterCore {
    onConsume: (str: string) => void; // 消费(处理)字符的回调函数
    queueList: string[] = []; // 存储待消费字符的队列
    maxStepSeconds: number = 50; // 默认最大步进间隔为50毫秒
    maxQueueNum: number = 2000; // 队列中最大字符数
    timer: number | undefined; // 用于控制下一次消费的定时器

    constructor({onConsume, maxStepSeconds}: TypeWriterCoreOptions) {
        this.onConsume = onConsume; // 初始化消费字符的回调

        if (maxStepSeconds !== undefined) {
            this.maxStepSeconds = maxStepSeconds; // 如果提供了最大步进间隔,则使用提供的值
        }
    }

    // 动态计算消费字符的速度
    dynamicSpeed() {
        const speedQueueNum = this.maxQueueNum / this.queueList.length; // 根据队列长度动态调整速度
        const resNum = +(
            speedQueueNum > this.maxStepSeconds
                ? this.maxStepSeconds : speedQueueNum
        ).toFixed(0); // 确保结果为整数

        return resNum;
    }

    // 将字符串添加到队列中
    onAddQueueList(str: string) {
        this.queueList = [...this.queueList, ...str.split('')]; // 分解字符串为字符数组并追加到队列
    }

    // 添加字符串到队列的公共方法
    add(str: string) {
        if (!str) return; // 如果字符串为空,则不执行任何操作
        this.onAddQueueList(str); // 调用内部方法添加字符串到队列
    }

    // 从队列中消费一个字符
    consume() {
        if (this.queueList.length > 0) {
            const str = this.queueList.shift(); // 从队列头部移除一个字符
            str && this.onConsume(str); // 如果字符存在,则调用消费函数处理该字符
        }
    }

    // 定时消费队列中的字符
    next() {
        this.timer = setTimeout(() => {
            if (this.queueList.length > 0) {
                this.consume(); // 消费一个字符
                this.next(); // 递归调用,继续消费下一个字符
            }
        }, this.dynamicSpeed()); // 根据动态速度设置定时器
    }

    // 开始消费队列中的字符
    start() {
        this.next(); // 调用next方法开始消费字符
    }

    // 渲染完成后的清理工作
    onRendered() {
        clearTimeout(this.timer); // 清除定时器,防止继续消费字符
    }

    // 清空队列并停止当前的消费过程
    onClearQueueList() {
        this.queueList = []; // 清空字符队列
        clearTimeout(this.timer); // 清除定时器
    }
}

2. useTypeWriter.ts - Hook封装

通过HookuseTypeWriter封装TypeWriterCore类,提供简洁的接口,使得在React或Vue组件中易于实现打字机效果。

代码示例如下:

import {useEffect, useState, useMemo} from 'react';
import TypeWriterCore from './TypeWriterCore';

interface UseWriterOptions {
    maxStepSeconds?: number; // 将 maxStepSeconds 定义为可选的
}

export const useTypeWriter = (
    {text, options}:
    { text: string, options?: UseWriterOptions }
) => {
    const [typedText, setTypedText] = useState('');

    const typingCore = useMemo(
        () => new TypeWriterCore(
            {
                onConsume: (str: string) => setTypedText(prev => prev + str),
                ...options,
            }
        ),
        []
    );

    useEffect(
        () => {
            typingCore.onRendered(); // 渲染完成 => 清空定时器
            typingCore.add(text);
            typingCore.start();

            return () => typingCore.onRendered(); // 渲染完成 => 清空定时器
        },
        [text]
    );

    return [typedText];
};

3. index.tsx - 组件实现示例

这个文件展示了如何在React组件中使用useTypeWriterHook来实现打字机效果。以下是实现的关键部分:

import React from 'react';
import ReactMarkdown from 'react-markdown';
import {useTypeWriter} from './useTypeWriter'; // 替换为实际的导入路径
import TypeWriterCore from './TypeWriterCore';


interface TypingWriterProps {
  text: string;
  options?: {
    maxStepSeconds?: number;
  };
}

const TypingWriter: React.FC<TypingWriterProps> = ({text, options = {}}) => {
    const [typedText] = useTypeWriter({text, options});

    return (
        <div>
            <ReactMarkdown>
                {typedText}
            </ReactMarkdown>
        </div>
    );
};


export {
  TypingWriter,
  TypeWriterCore,
  useTypeWriter,
};

通过这三个文件的详细解析和代码实现,我们展示了从核心逻辑的构建到在React组件中的应用,如何逐步开发一个打字机效果的流式组件。