React--》规划React组件库编码规范与标准 — Button篇

目前前端组件化已经成为前端开发的核心思想之一,在这篇文章中将深入探讨如何规划一个规范的Button组件,让它不仅能高效支持不同的功能需求还能确保跨项目、跨团队的一致性,抛砖引玉的方式引出后面组件库的其他组件的开发!

目录

Button组件搭建

bem命名规范

组件正式编码

样式解决方案

组件单元测试

组件文档搭建 

GitHub Actions

changeset版本

Button组件搭建

        Button按钮本质:一个button按钮之所以有需要样式的选择,究其原因就是class名称的组合,根据赋值的不同类名来实现不同的样式结果,如下所示:

class="ease-button--primary ease-button--larger is-plain is-disabled"

完成一个组件库需要考虑的问题有以下几个方面,根据任务进行需求分析,然后初始化项目确定项目文件结构,接下来就是规范基础写法、样式解决方案以及色彩系统等基础方面内容了:

代码结构;样式解决方案;组件需求分析和编码;组件测用例和编码;代码打包输出和发布;CI/CD及文档生成等

像Button组件大部分关注的只是样式而没有交互,根据分析我们可以得到如下具体的属性列表:

type:不同的样式(default、primary、danager、info、success、warning)
plain:样式的不同展现模式boolean
round:圆角boolean
circle:圆形按钮,适合图标boolean
disabled:禁用boolean
icon:图标添加
loading:加载样式添加

        组件目录结构:后期所有组件的开发按照如下目录进行规范进行,styles文件存储当前组件所有关联的样式;types文件存储当前组件所有关联的类型;其他tsx文件存储当前组件所有的核心代码;index.tsx文件存储当前组件暴露出去的封装组件及类型,如下所示:

bem命名规范

        bem:(Block, Element, Modifier)是一种CSS命名规范,用于使前端代码更加结构化和可维护,它通过三个主要部分来命名CSS类名,如下所示:

1)Block(块):代表一个独立的功能模块,可以是页面中的一个组件或者布局的一部分。例如header、button、menu

2)Element(元素):表示一个块内的子元素,通常是该块的一部分依赖于块的存在,例如header__title(title是header块的元素),button__icon。

3)Modifier(修饰符):用于描述块或元素的不同状态或外观变化,例如button--primary(代表一种主要按钮样式),header__title--large(代表较大的标题样式)

brm的命名规则让类名具有清晰的层级关系和可读性,有助于避免命名冲突和使代码更容易维护,这里我将其抽离到项目的utils文件夹下用来供全局组件进行调用,代码如下所示:

// block代码块 element元素 modifier装饰 state状态
/*** 示例:* ease-button--primary* is-checked*/// 创建BEM命名规范
const createBEM = (prefixName: string) => {const block = (blockSuffix: string = '') => _bem(prefixName, blockSuffix, '', '')const element = (element: string) => element ? _bem(prefixName, '', element, '') : ''const modifier = (modifier: string | undefined) => modifier ? _bem(prefixName, '', '', modifier) : ''const be = (blockSuffix: string = '', element: string = '') => blockSuffix && element ? _bem(prefixName, blockSuffix, element, '') : ''const bm = (blockSuffix: string = '', modifier: string = '') => blockSuffix && modifier ? _bem(prefixName, blockSuffix, '', modifier) : ''const em = (element: string = '', modifier: string = '') => element && modifier ? _bem(prefixName, '', element, modifier) : ''const bem = (blockSuffix: string = '', element: string = '', modifier: string = '') => blockSuffix && element && modifier ? _bem(prefixName, blockSuffix, element, modifier) : ''const is = (name: string, state: boolean | undefined) => (state ? `is-${name}` : "")return { block, element, modifier, be, bm, em, bem, is }
};// BEM命名规范实现
const _bem = (prefixName: string, blockSuffix: string, element: string, modifier: string) => {if (blockSuffix) prefixName += `-${blockSuffix}`;if (element) prefixName += `__${element}`;if (modifier) prefixName += `--${modifier}`;return prefixName;
}// 创建命名空间
export const createNameSpace = (name: string) => {const prefixName = `ease-${name}`return createBEM(prefixName)
};

组件正式编码

        接下来我们开始对button进行正式代码书写,当我们封装一个对应的原生组件的时候,原生属性必须要进行考量是否添加好,这里我们可以参考 MDN 官网提供的文档详细了解原生组件拥有哪些原生属性以及其具体的作用是什么:

typescript类型:当我们编写一个原生组件给其他人使用的时候ts类型尤为重要,只有我们写了ts类型之后用户才会知道我们开发的组件到底有哪些核心参数可以使用,这里我们完全可以参考其他热门组件库文件提供的一些范例来给我们开发组件库提供一些思路:

对于一个button按钮来讲,他有许多常量类型供我们选择、如按钮类型、形状、html类型、 尺寸等常量类型,这里我们可以将其抽离出一个constant.ts文件里面用于定义常量类型,如下所示:

友情提示!!!:我们可以定义代码块用于快速折叠相似功能代码:

// #region 规范按钮组件的常量类型
// 定义包含五种按钮类型的元组
const _ButtonTypes = ['default', 'primary', 'dashed', 'link', 'text'] as const;
export type ButtonType = (typeof _ButtonTypes)[number]; // 限制组件属性的取值范围// 定义包含三种按钮形状的元组
const _ButtonShapes = ['default', 'circle', 'round'] as const;
export type ButtonShape = (typeof _ButtonShapes)[number];// 定义包含三种按钮HTML类型的元组
const _ButtonHTMLTypes = ['submit', 'button', 'reset'] as const;
export type ButtonHTMLType = (typeof _ButtonHTMLTypes)[number];// 定义包含三种按钮尺寸的元组
const _ButtonSizes = ['large', 'middle', 'small'] as const;
export type ButtonSize = (typeof _ButtonSizes)[number];
// #endregion

定义完常量类型之后,我们在types类型文件夹下的入口index.ts文件中开始引入这些常量类型,然后设置props类型并给其赋值,常见的props类型我们可以参考热门组件库文档给出的范例,最终代码如下所示:

import React from 'react'
import { ButtonHTMLType, ButtonSize, ButtonShape, ButtonType } from './constant'interface BaseButtonProps {type: ButtonType; // 按钮类型,默认为 'default'shape: ButtonShape; // 按钮形状,默认为 'default'htmlType: ButtonHTMLType; // 按钮的 HTML 类型,默认为 'button'size: ButtonSize; // 按钮尺寸,默认为 'middle'plain: boolean; // 是否为朴素按钮,默认为 falsedisabled: boolean; // 是否禁用状态,默认为 falseloading: boolean; // 是否为加载中状态,默认为 falsecolor: string; // 按钮颜色children: React.ReactNode; // 按钮内容,默认为 null
}// 合并HTMLAttributes和 ButtonHTMLAttributes的属性,但不包括type、color、disabled、children属性
type MergedHTMLAttributes = Omit<React.HTMLAttributes<HTMLElement> &React.ButtonHTMLAttributes<HTMLElement> &React.AnchorHTMLAttributes<HTMLElement>,'type' | 'color' | 'disabled' | 'children'
>;export interface inheritProps extends BaseButtonProps, MergedHTMLAttributes {href: string;autoInsertSpace: boolean;
}// 使所有属性可选(Partial)且只读(Readonly)
export type ButtonProps = Readonly<Partial<inheritProps>>;

核心代码实现:编写完button组件的ts类型之后,接下来我们开始正式对原生button按钮进行组件化开发,这里我们定义一个组件的基本结构,通过props传递数据,并且借助函数将实例暴露出去,通过bem规范给组件动态设置类名:

import React, { forwardRef, useCallback } from 'react';
import clsx from 'clsx';
import { createNameSpace } from "@ztk63lrd/utils/create"
import type { ButtonProps } from './types';const EButton = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {// #region 组件变量声明const bem = createNameSpace('button');const { type, shape, htmlType = 'button',  size, disabled, loading, color, children, ...rest } = props;// #endregion// #region 组件样式构建const classes = clsx( // 使用 clsx 动态构建类名bem.block(), // 基础类名bem.modifier(type), // type 修改器bem.modifier(shape), // shape 修改器bem.modifier(size), // size 修改器bem.is('disabled', disabled), // disabled 状态bem.is('loading', loading) // loading 状态);// #endregion// #region 组件事件处理const handleClick = useCallback((e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => {if (disabled) {e.preventDefault();return;}props.onClick?.('href' in props? (e as React.MouseEvent<HTMLAnchorElement, MouseEvent>): (e as React.MouseEvent<HTMLButtonElement, MouseEvent>),);}, [props.onClick, disabled]);// #endregionreturn (<buttonclassName={classes} // 直接应用动态类名type={htmlType}disabled={disabled || loading}onClick={handleClick}ref={ref}{...rest}>{children}</button>);
});export default EButton;

接下来我们在组件文件夹的入口文件index.tsx处将封装组件及其类型暴露出去,然后在packages文件夹下的入口文件将所有components文件夹下写的所有组件再暴露一遍出去就可以了:

接下来我们开始在根目录终端执行pnpm run build即可,打包后就会在packages文件下生成build文件目录,并且会按照问你设置的组件目录结构生成相应的js文件和.d.ts类型声明文件,如下:

接下来我们终端运行pnpm run dev命令来执行review文件下测试组件项目的代码,在该文件下设置如下代码来查看我们编写的组件情况,如果我们直接导入ease-reactify就是我们打包好的实际组件代码,如果导入@ztk63lrd/components/button就是我们实时编写的组件代码:

import EButton from "@ztk63lrd/components/button"
// import { EButton } from "ease-reactify";const ButtonView = () => {return (<div><EButton size="middle" type="primary" shape="round" disabled>按钮</EButton></div>)
}export default ButtonView

通过上面我们给封装好的button组件添加类型限制之后,我们的bem规范已经被成功执行并且也出现在我们的运行项目上面了:

样式解决方案

        大家都知道作为一个组件库我们要采用什么样的色彩是尤为重要的,每一个热门的组件库都有它一套特定的色谱或者说是色彩系统,所以这时候我们就需要了解一下颜色对一个组件库的构成模式,这里我们可以参考antd的对于色彩的一些讲解:地址 文章还是比较详细的介绍了系统色以及产品色的一些概念内容,对我们设计组件库颜色方案给到了一个很好的启发:

        了解好样式解决方案之后,接下来我们可以访问 地址 来选择我们开发组件的一个默认样式:

        除上面我们可以选择颜色内容之后,我们也可以访问如下网站来设计一下我们的button组件:

确认好最终的一个样式方案之后,接下来我们开始正式对组件进行样式的调整,这里我们采用的css预处理scss进行样式调整,后期有精力的话也按照antd来设计全部用ts来写样式,目前的方案还是采用css处理器解决样式问题,目前的话还是根据不同的作用划分css文件,然后定义一些常用的方法和变量名来实现css样式内容:

然后根据我们要设计的组件,给button设计不同状态下的css样式,其中用到了封装好的公共的变量和css方法,如下所示:

最终我们在预览界面中实现的效果如下所示:

组件单元测试

        当我们编写完组件之后,为了确保后期组件的稳定性,即使后面项目的迭代和变更也不会影响原组件的功能,这里我们需要借助组件的单元测试来确保组件的稳定性,我们组件开发使用单元测试的重要性主要有以下几点原因:

1)高质量代码

2)更早的发现bug,减少成本

3)让重构和升级变得更加容易和可靠

4)让开发流程更加敏捷

        单元测试的方法有很多,因为我们采用的是vite作为打包器进行构建项目,所以这里我们也采用vite一派的单元测试工具 vitest 进行操作,详情可以参考我之前的文章:地址 ,vitest是兼容Jest的,所以说Vitest的api与Jest非常相似,用户从Jest迁移到Vitest基本上没啥学习成本:

接下来我们终端执行如下命令安装测试插件:

pnpm install -D vitest

安装完成之后,我们在vite的配置文件当中配置一下单元测试的一些关键配置:

当我们在相关组件下新建tests文件夹,就可以实现对组件的一些单元测试了:

浏览器模式与框架无关因此不提供任何渲染组件的方法。不过可以使用框架的测试工具包,这里我们采用如下的包进行组件测试,终端执行如下命令安装:

pnpm install @testing-library/react @testing-library/jest-dom @testing-library/user-event -D

然后这里我们使用该三方库中的render函数来测试渲染的组件库内容,如下可以看到我们给按钮设置的名称通过函数拿到按钮的文本,测试案例也正常通过了:

当然testing library旗下还有许多其他的工具,通过地址我们可以了解更多的测试工具的使用:

了解了一些工具的使用之后,接下来我们开始正式的对EButton组件进行单元测试,如下:

import { expect, test, describe, it, vi } from "vitest";
import { render, fireEvent } from "@testing-library/react"
import EButton, { ButtonProps } from "../index";
import '@testing-library/jest-dom'const defaultProps = {onClick: vi.fn()
}
const testProps: ButtonProps = {type: "primary",size: 'large',className: 'ease-test',
}
const disabledProps: ButtonProps = {disabled: true,onClick: vi.fn()
}describe("test EButton components", () => {it("应呈现正确的默认按钮", () => {const wrapper = render(<EButton {...defaultProps}>测试按钮</EButton>);const element = wrapper.getByText("测试按钮") as HTMLButtonElement; // 获取文本为"测试按钮"的元素expect(element).toBeInTheDocument(); // 断言该元素存在于文档中expect(element.tagName).toBe("BUTTON"); // 断言该元素的标签名为"BUTTON"expect(element).toHaveClass("ease-button"); // 断言该元素具有类名"ease-button"expect(element.disabled).toBeFalsy(); // 断言该元素未被禁用fireEvent.click(element);expect(defaultProps.onClick).toHaveBeenCalled(); // 断言onClick函数被调用});it("应根据不同的props渲染正确的组件", () => {const wrapper = render(<EButton {...testProps}>测试按钮</EButton>);const element = wrapper.getByText("测试按钮");expect(element).toBeInTheDocument();expect(element).toHaveClass("ease-button ease-button--primary ease-button--large ease-test");});it("禁用时应呈现禁用按钮设置为true", () => {const wrapper = render(<EButton {...disabledProps}>测试按钮</EButton>);const element = wrapper.getByText("测试按钮") as HTMLButtonElement;expect(element).toBeInTheDocument(); // 断言该元素存在于文档中expect(element.disabled).toBeTruthy(); // 断言该元素已被禁用expect(disabledProps.onClick).not.toHaveBeenCalled(); // 断言onClick函数未被调用})
});

最终可以看到我们的测试用例代码都通过了:

组件文档搭建 

        项目采用组件文档进行代码和具体相关展示,组件库文档有很多选择,可以参考文章了解一下其他组件库插件的实现,这里我们还是以vite衍生的组件库文档vitePress来实现,VitePress可以单独使用也可以安装到现有项目中,在这两种情况下都可以使用以下方式安装它:

npm add -D vitepress
npx vitepress init

安装完插件之后根据自身情况进行选择即可,如果正在构建一个独立的VitePress站点可以在当前目录 (./) 中搭建站点,但是如果在现有项目中与其他源代码一起安装VitePress,建议将站点搭建在嵌套目录(例如 ./docs)中以便它与项目的其余部分分开:

安装好插件之后,vitepress会自动帮助我们配置好环境命令,我们直接运行即可:

pnpm install markdown-it markdown-it-container markdown-it-mathjax3 -D

然后根据具体的一些官网配置进行调配即可:

GitHub Actions

        GitHub Actions:是GitHub提供的一个自动化工具,它可以帮助开发者自动执行构建、测试、部署等任务,通过GitHub Actions开发者可以定义一系列的工作流(workflow),并且这些工作流可以在GitHub上的代码库发生特定事件时触发,比如推送代码、发起 pull 请求、发布版本等。

一个工作流通常由多个步骤(steps)组成,每个步骤可以执行不同的命令或者运行一个自定义的脚本,工作流是由yaml文件描述的,存放在项目的.github/workflows 目录中,其特点主要包括:

1)自动化流程:自动执行重复的任务减少手动操作

2)GitHub紧密集成:可以直接在GitHub上定义和管理工作流

3)多平台支持:支持Linux、macOS 和 Windows环境

4)自定义工作流:可以根据自己的需求创建自定义的工作流和步骤

5)与其他工具服务集成:可以与其他工具API或者云服务集成,扩展功能

此次我们组件库的工作流,目前主要有两个,如下所示:

部署组件库文档:该工作流设置了名称,通过on来构建触发工作流的时机是提交代码

name: 'Deploy Docs'  # 工作流名称on:push:branches:- masterjobs:build-and-deploy:runs-on: ubuntu-latestpermissions:contents: write  # 添加写入权限steps:- name: 读取仓库内容uses: actions/checkout@v4  # 必须有uses来获取代码- name: 安装pnpmuses: pnpm/action-setup@v2  # 添加这一步安装pnpm- name: 安装依赖run: pnpm install --no-frozen-lockfile   # 运行pnpm install来安装依赖- name: 项目测试run: pnpm run test  # 运行pnpm测试项目- name: 构建项目run: pnpm run docs:build  # 运行构建文档的命令- name: 部署GitHub Pagesuses: JamesIves/github-pages-deploy-action@v4  # 使用GitHub Actions来部署到gh-pageswith:branch: gh-pages  # 指定部署的分支folder: 'docs/dist'  # 指定构建后的文件夹路径clean: true  # 清理旧的部署文件

发布npm平台:该工作流设置了名称,通过on来构建触发工作流的时机是package发生变化

name: Release Packageon:push:branches:- masterpaths:- 'packages/package.json'  # 如果是 monorepo,监听所有子包的 package.jsonjobs:release:runs-on: ubuntu-lateststeps:- name: 读取仓库内容uses: actions/checkout@v4with:fetch-depth: 0  # 获取完整历史,用于版本计算- name: Setup Node.jsuses: actions/setup-node@v3with:node-version: 21registry-url: https://registry.npmjs.org/- name: 安装pnpmuses: pnpm/action-setup@v2- name: 安装依赖(跳过锁文件检查)run: pnpm install --no-frozen-lockfile- name: 项目测试run: pnpm run test- name: 构建项目run: pnpm run build- name: 检查待发布的包run: npx changeset status- name: 创建版本号run: npx changeset version --snapshot ${{ github.event.inputs.release-type }}- name: 登录到npmrun: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc- name: 发布到npmrun: npx changeset publish --only ease-reactifyenv:NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

当我们提交代码的时候就会触发自动化流程,GitHub Actions就会自动帮我们执行对应的部署:

changeset版本

与git结合使用的一个特定文件或目录结构,用于跟踪和管理代码的变更集,这通常出现在需要对代码进行分组提交的场景或者在使用某些自动化工具、工作流、或 CI/CD过程中,终端执行如下命令进行安装:

pnpm add @changesets/cli -D

其常用命令如下所示:

# 初始化
npx changeset init# 添加 changeset
npx changeset add
npx changeset# 版本
npx changeset version# 发布
npx changeset publish

这里我将其命令放在package中的配置脚本中,想要发布的时候执行如下命令即可:

目前部署的组件库文档:地址 ,后期内容会不断完善!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91700.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91700.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中科米堆CASAIM金属件自动3d测量外观尺寸三维检测解决方案

金属零部件的外观尺寸检测直接关系到产品的装配精度和使用性能。CASAIM基于激光扫描技术的自动化三维扫描系统&#xff0c;为金属加工行业提供了高效的自动3D测量解决方案&#xff0c;有效解决了传统检测方式效率低、覆盖面有限等问题。激光扫描技术在金属件测量中优势明显。与…

开源数据同步中间件,支持MySQL、Oracle

DBSyncer&#xff08;英[dbsɪŋkɜː(r)]&#xff0c;美[dbsɪŋkɜː(r) 简称dbs&#xff09;是一款开源的数据同步中间件&#xff0c;提供MySQL、Oracle、SqlServer、PostgreSQL、Elasticsearch(ES)、Kafka、File、SQL等同步场景。支持上传插件自定义同步转换业务&#xff0…

中英混合的语音识别XPhoneBERT 监督的音频到音素的编码器结合 f0 特征LID

完整项目包获取点击文末名片完成一个 Code-Switching&#xff08;中英混合&#xff09;的语音识别系统&#xff0c;整个流程如下思路进行&#xff1a; 163. (Step 1) 训练音频到音素的编码器&#xff08;Audio → Phoneme Encoder&#xff09; 你已经完成了此部分。核心思路是利…

Param关键字的使用

1&#xff1a;当一个方法的某一个参数个数不固定的时候&#xff0c;可以使用Param2:可变的方法参数必须定义为数组类型3&#xff1a;该参数必须放在方法参数的最后&#xff0c;应且只有一个4&#xff1a;参数必须为一维数组5&#xff1a;params不能和ref和out组合使用namespace…

京东云轻量云服务器与腾讯云域名结合配置网站及申请SSL证书流程详解

京东云轻量云服务器与腾讯云域名结合配置网站及申请SSL证书流程详解 1. 需求及实现效果 1.1. 需求 先说一下我当前情况&#xff0c;我目前有一个京东云服务器和一个在腾讯云旗下买的域名&#xff08;不要问为啥一个在京东云&#xff0c;一个在腾讯云&#xff0c;那自然是哪个…

Python入门Day14:面向对象编程初步(OOP入门)

学习目标&#xff1a;理解面向对象编程&#xff08;OOP&#xff09;的基本思想&#xff1a;类&#xff0c;对象掌握类的定义&#xff0c;构造方法&#xff0c;实例属性和方法熟悉self的含义与作用学会用类组织和封装代码&#xff0c;初步构建自己的“对象世界”一、什么是面向对…

日志和指标标签规范化方案

好的&#xff0c;设计一个有效的日志和指标标签规范化方案对于构建可观测性强、易于维护、关联分析顺畅的系统至关重要。混乱的标签命名会极大增加查询、聚合、告警和故障排除的难度。 以下是一个综合性的标签规范化方案建议&#xff0c;结合了行业最佳实践&#xff1a; 核心目…

Windows和Linux的tree工具

目录 1.前言 2.Linux的tree工具 2.1.安装tree 2.2.常用命令与参数 2.3.常见应用场景 2.4.注意事项 3.Windows的tree工具 3.1.基础语法 3.2.核心参数详解 3.3.常见应用场景 3.4.局限性与增强方案 4.Windows 与 Linux tree 的核心差异 5.tree工具优势 5.总结 相关…

[echarts] 更新数据

option {title: { text: 销售数据 },tooltip: { trigger: axis },legend: { data: [销量, 库存] },xAxis: {type: category,data: [衬衫, 羊毛衫, 雪纺衫]},yAxis: { type: value },series: [{ name: 销量, type: bar, data: [5, 20, 36] },{ name: 库存, type: line, data: […

通过el-image实现点击文字查看图片,及其图片列表

场景一&#xff1a;表格中有时候会有点击文字查看图片的功能&#xff08;因为表格的一个单元格不方便显示多个图片&#xff09;如下图所示&#xff1a;对于这个需求&#xff0c;我们可以应对的方案是&#xff1a;在文字旁边写一个el-image图默认显示多张图片中的第一张&#xf…

003 实习(前端jquery之轮播图,学校网页)

web前端,查询官网:w3schoolHTML:负责网页结构&#xff08;页面元素和内容&#xff09;CSS:负责网页的表现&#xff08;网页元素的外观、位置等页面样式&#xff0c;如颜色&#xff0c;大小&#xff09;JAVAScript:负责网页的行为&#xff08;交互效果&#xff09;<a>:超链…

Mysql group by

临时表与内存表 内存表是 Memory 引擎表&#xff0c;表的数据行都在内存。 临时表可以使用各种引擎。 临时表是线程私有表&#xff0c;其他线程不可见&#xff0c;不需考虑重名问题。 session 结束时临时表会被自动删除。 如果 Binlog_format row&#xff0c;则临时表语句不进…

Linux(15)——进程间通信

目录 一、进程间通信的介绍 ✍️进程间通信的目的 ✍️进程间通信的本质 进程间通信的分类 ✍️管道 ✍️System V IPC ✍️POSIX IPC 二、管道 &#x1f9e0;什么是管道 ✍️匿名管道 &#x1f4dd;匿名管道的原理 &#x1f4dd;pipe函数 &#x1f4dd;匿名管道…

【Flutter】双路视频播放方案

最近在做双路视频播放&#xff0c;就是在一个页面播放两个视频。我遇到的问题就是音频焦点冲突问题&#xff0c;在下面说明。什么是双路视频播放&#xff08;来自AI&#xff09;双路视频播放&#xff08;Dual-Video Playback&#xff09;&#xff0c;从字面上理解&#xff0c;就…

笔试——Day25

文章目录第一题题目思路代码第二题题目&#xff1a;思路代码第三题题目&#xff1a;思路代码第一题 题目 笨小猴 思路 模拟 统计每个字符出现的次数&#xff0c;用最大减最小&#xff0c;判断是不是质数&#xff1b; 质数的判断使用试除法&#xff1b; 代码 第二题 题目&…

【C#学习Day15笔记】拆箱装箱、 Equals与== 、文件读取IO

前言在C#第15天的学习中&#xff0c;我深入探索了类型转换机制、对象比较原理和文件操作技术三大核心主题。这些知识是构建高效、健壮程序的关键基础。本文完整保留我的课堂实践代码和命名体系&#xff0c;通过结构化梳理帮助大家掌握这些核心概念。所有代码示例均来自我的实际…

发电类电力业务许可证申请条件

基本条件&#xff1a;法人资格&#xff1a;申请人必须是依法注册的企业法人。 财务能力&#xff1a;应具有与所申请从事的电力业务相适应的财务能力。 专业人员要求&#xff1a;生产运行负责人、技术负责人、安全负责人和财务负责人需具备至少3年以上与申请从事的电力业务相关的…

JavaScript 高效入门指南:从基础到实战(VSCode 版)

废话不多说&#xff0c;直接上干货&#x1f600; 一、先搞定工具&#xff1a;VSCode 配置成「JS 开发神器」 工欲善其事&#xff0c;必先利其器。用 VSCode 写 JavaScript&#xff0c;这几个配置能让你效率翻倍&#xff1a; 1. 必装插件&#xff08;直接在 VSCode 插件商店搜…

《人形机器人的觉醒:技术革命与碳基未来》——类人关节设计:柔性驱动革命之液压人工肌肉

目录&#xff1a;一、人工肌肉的种类及人形机器人适用情况二、人形机器人用人工肌肉科研机构及其最新成果进展三、液压人工肌肉种类及工作机制四、液压人工肌肉适用人形机器人的性能要求和局限性五、液压人工肌肉材料技术进展及其限制与突破六、波士顿动力Spot的液压静液传动系…

26数据结构-顺序表

&#x1f4cc;有序顺序表的合并 #define MAX_SIZE 20 struct SeqList {int data[MAX_SIZE];int length; }; void mergeArray(SeqList &L1,SeqList &L2,SeqList &L) {int i0,j 0;while(i<L1.length && j<L2.length){if(L1.data[i]<L2.data[j])L.da…