从零搭建react+ts组件库(二)less模块化与svg引入配置
在上一篇《从零搭建react+ts组件库(一)项目搭建与封装antd组件》介绍了使用webpack来搭建一个基于antd的组件库的基本框架,但是作为一个组件库,实际上还有很多的都还未引入,本篇将会补充less模块化以及svg引入的基本方式。
本文所有修改的代码分支为chapter02位于w4ngzhen/r-ui (github.com)仓库的chapter02_less_and_svg
分支,该分支基于上一篇文章的chapter01_init
分支而来(main分支总是显示最新的内容)。
为了讲解如何进行less模块化配置以及如何引入svg作为组件库的一部分,我们设想这样一个需求:一个搜索输入框,左侧是一个svg的icon搜索图标,右侧是输入框。
组件规划
首先考虑组件具备的属性,作为一个简单的搜索框,我们至少有3个属性:
- 输入框初始默认值(defaultValue)
- 占位提示信息(placeholder)
- 输入改变事件(onChange)
对于UI结构来说,我们可以使用一个div作为整体包裹,然后左侧是图标的区域(使用一个div),右侧是输入框(input)。
综上,我们的初始代码如下:
import * as React from "react";
interface SearchInputProps {
defaultValue?: string;
placeholder?: string;
onChange?: (value: string, e: React.ChangeEvent<HTMLInputElement>) => void;
}
const SearchInput: React.FC<SearchInputProps> = (props) => {
const {
defaultValue,
placeholder,
onChange,
} = props;
const inputOnChange: React.ChangeEventHandler<HTMLInputElement>
= (e: React.ChangeEvent<HTMLInputElement>) => {
if (onChange) {
onChange(e.target.value, e);
}
}
return (
// 包裹
<div>
{/*存放icon*/}
<div></div>
{/* 输入框*/}
<input defaultValue={defaultValue}
placeholder={placeholder}
onChange={inputOnChange}></input>
</div>
);
}
less样式模块化配置
首先我们编写less样式文件,当然,对于该文件我们不赘述实现。
@input-size: 32px;
.centerAll() {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.searchInputWrap {
width: 100%;
height: @input-size;
background-color: #f4f4f4;
border-radius: 5px;
.centerAll();
.searchInputIconBox {
width: @input-size;
height: @input-size;
background-color: transparent;
.centerAll();
}
.searchInput {
width: calc(100% - @input-size);
height: 100%;
border: none;
outline: none;
background-color: transparent;
}
.searchInput:focus {
border: none;
outline: none;
}
}
修改组件代码,改动如下:
- 以模块化的方式引入less文件
import * as React from "react";
+import styles from './index.module.less';
- 针对每个元素配置其less样式,采用
styles.xxx
方式使用
return (
// 包裹
- <div>
+ <div className={styles.searchInputWrap}>
{/*存放icon*/}
- <div></div>
+ <div className={styles.searchInputIconBox}></div>
{/* 输入框*/}
- <input defaultValue={defaultValue}
+ <input className={styles.searchInput}
+ defaultValue={defaultValue}
placeholder={placeholder}
onChange={inputOnChange}></input>
</div>
)
webpack对于css-loader需要进行简单的配置:
{
loader: MiniCssExtractPlugin.loader,
},
- 'css-loader',
+ {
+ loader: "css-loader",
+ options: {
+ modules: true
+ }
+ },
'less-loader'
对于该处的配置,详细可以查看关于css-loader的文档webpack-contrib/css-loader: CSS Loader (github.com)
此时,如果有同学在使用IDEA会发现有编译报错。有同学会发现,我们的项目里面没有直接安装typescript,那么为什么IDEA能够检测到我们代码呢?实际上这是IDEA自带的ts在进行类型检测,仅仅是类型检查,实际上编译过程我们是调用的babel-loader+preset/typescript这条链路来完成的,所以并不影响编译后的内容。当然,为了能够进行正确的类型检查,我们在项目根目录下添加tsconfig.json:
{
"compilerOptions": {
"noEmit": true,
"esModuleInterop": true,
"jsx": "react"
},
"include": [
"src",
"./src/external.d.ts"
]
}
其中,"noEmit": true
表明由ts进行类型检查,但是不编译文件。include中的./src/external.d.ts
中的内容如下:
// less模块声明
declare module '*.module.less' {
const content: { [className: string]: string };
export = content;
}
也就是说,希望IDEA的内置ts读取tsconfig.json,并添加关于import*.module.less
时候得到的模块的类型定义。这样,IDEA的ts类型检查在这句话的时候就不会报错了:
import styles from './index.module.less';
总结一下,想要在ts+babel-loader项目中使用样式模块化。
在类型检查阶段,需要:
- 单独配置tsconfig.json
- 编写d.ts,并被tsconfig.json配置包含在类型定义查找的范围(inlcude)
在编译阶段,需要只需要配置css-loader的module为true即可。
这一块我会再写一篇文章来单独讲解webpack+ts+babel的方案。
效果演示
编写样例html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>r-ui example</title>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="r-ui.umd.js"></script>
<link href="r-ui.umd.css" rel="stylesheet"/>
</head>
<body>
<div id="example"></div>
<script>
// window上存在rui,是因为我们将组件包导出为了umd包,取名为rui
const button = React.createElement(rui.SearchInput, {
placeholder: '占位符',
defaultValue: 'hello, world',
onChange: (value, e) => console.log(value, e)
});
ReactDOM.render(button, document.getElementById('example'));
</script>
</body>
</html>
编译r-ui后打开样例界面,可以看到如下效果:
svg引入配置
实际上,react中想要使用svg有这很多种方式,像是直接编写react组件,并返回svg代码:
import * as React from "react";
const IconSearch = () => {
return (
<svg className="icon"
viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="4136" width="25" height="25">
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6c3.2 3.2 8.4 3.2 11.6 0l43.6-43.5c3.2-3.2 3.2-8.4 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
p-id="4137"></path>
</svg>
);
}
这种方式弊端在于,每次svg有修改的时候,都需要重新复制svg代码对代码文件进行修改,且很多svg的数据较为复杂,容易出错。
将svg作为react组件来使用
我们知道,对于webpack来说,可以将一切的东西都是为模块,对于任何import进来的,webpack都可以通过匹配的规则(rules)调用对应的loader来进行处理。
那么,是否存在这样一种方式:
import IconSearch from 'path/to/search.svg'
// IconSearch是一个React组件,可以在其他组件中使用
个人最常使用的方案是svgr/webpack
(Webpack - SVGR (react-svgr.com))
只需要三个步骤的配置:
- 引入@svgr/webpack
yarn add -D @svgr/webpack
- 配置webpack,处理svg
{
test: /\.svg$/,
use: ['@svgr/webpack'],
}
- external.d.ts配置(配置理由和上述less配置一样,为了达到类型检查)
// svg类型
declare module '*.svg' {
const content: React.FunctionComponent<React.SVGAttributes<React.ReactSVGElement>>
export default content
}
完成配置以后,我们就可以通过import XXX from 'path/to/xxx.svg',来使用SVG组件了:
import * as React from "react";
import styles from './index.module.less';
+import IconSearch from "../../assets/svg/search.svg";
interface SearchInputProps {
defaultValue?: string;
// ... ...
// 包裹
<div className={styles.searchInputWrap}>
{/*存放icon*/}
- <div className={styles.searchInputIconBox}></div>
+ <div className={styles.searchInputIconBox}>
+ <IconSearch width={18} height={18}/>
+ </div>
{/* 输入框*/}
效果演示
从零搭建react+ts组件库(二)less模块化与svg引入配置的更多相关文章
- 从零搭建react+ts组件库(封装antd)
为什么会有这样一篇文章?因为网上的教程/示例只说了怎么做,没有系统详细的介绍引入这些依赖.为什么要这样配置,甚至有些文章还是错的!迫于技术洁癖,我希望更多的开发小伙伴能够真正的理解一个项目搭建各个方面 ...
- beeshell —— 开源的 React Native 组件库
介绍 beeshell 是一个 React Native 应用的基础组件库,基于 0.53.3 版本,提供一整套开箱即用的高质量组件,包含 JavaScript(以下简称 JS)组件和复合组件(包含 ...
- react_app 项目开发 (4)_ React UI 组件库 ant-design 的基本使用
最流行的开源 React UI 组件库 material-ui 国外流行(安卓手机的界面效果)文档 ant-design 国内流行 (蚂蚁金服 设计,一套 PC.一套移动端的____下拉菜单.分页.. ...
- React Native组件解析(二)之Text
React Native组件解析(二)之Text 1. 概述 Text组件对应于iOS的UILabel,Android的TextView,用来显示文本.但是Text组件的内部使用的并不是flexbox ...
- 从0搭建Vue3组件库(二):Monorepo项目搭建
本篇文章是从0搭建Vue3组件库系列文章第二篇,本篇文章将带领大家使用pnpm搭建一个简单的Monorepo项目,并完成包的关联与测试 什么是 Monorepo 其实很简单,就是一个代码库里包含很多的 ...
- 前端如何搭建vue UI组件库/封装插件(从零到有)
需求 因之前是做外包项目居多,经常用到相同的组件,之前的办法是在一个项目中写一个组件,其他项目直接将compents下的组件复制,粘贴到项目中使用,缺点是维护起来,改一个项目,其他项目也需要修改,所以 ...
- 从零搭建react hooks项目(github有源代码)
前言 首先这是一个react17的项目,包含项目中常用的路由.状态管理.less及全局变量配置.UI等等一系列的功能,开箱即用,是为了以后启动项目方便,特地做的基础框架,在这里分享出来. 这里写一下背 ...
- React Native组件(二)View组件解析
相关文章 React Native探索系列 React Native组件系列 前言 了解了RN的组件的生命周期后,我们接着来学习RN的具体的组件.View组件是最基本的组件,也是首先要掌握的组件,这一 ...
- 通过create-react-app从零搭建react环境
一. 快速开始: 全局安装脚手架: $ npm install -g create-react-app 通过脚手架搭建项目: $ create-react-app <项目名称> 开始项目: ...
- Vitepress搭建组件库文档(上)—— 基本配置
在 vite 出现以前,vuepress 是搭建组件库文档不错的工具,支持以 Markdown 方式编写文档.伴随着 vite 的发展,vitepress 已经到了 1.0.0-alpha.22 版本 ...
随机推荐
- 如何在 Mac 上配置 VirtualBox Host-Only 网络适配器
默认Mac 上安装 VirtualBox 后,没有自动配置Host-Only 网络适配器,需要我们手工添加.方法如下: 打开VirtualBox软件, 依次点击 "管理 -> 工具 - ...
- Exadata健康检查工具EXAchk
本文根据MOS文章:Oracle Exadata Database Machine EXAchk (Doc ID 1070954.1)整理关键步骤. 注:通常都会要求使用当前最新可用的EXAchk版本 ...
- Mac 上 redis 的安装方法
1.由于需要用到编译,所以先安装xcode,注意利用appstore安装xcode后,记得打开xcode 点install,也可以建立一个macos项目,运行下 试下. 2. 去官网下载:https: ...
- C 语言常用头文件解释
C系统提供了丰富的系统文件,称为库文件,整理一下以后好实用: <stdio.h> 定义了三个变量类型.一些宏和各种函数来执行输入和输出 https://www.runoob.com/cpr ...
- .net core微服务之服务发现
一:nacos https://nacos.io/docs/latest/what-is-nacos/ https://github.com/alibaba/nacos 二:consul https: ...
- 【解决方案】Java 互联网项目如何防止集合堆内存溢出(一)
目录 前言 一.代码优化 1.1Stream 流自分页 1.2数据库分页 1.3其它思考 二.硬件配置 2.1云服务器配置 三.文章小结 前言 OOM 几乎是笔者工作中遇到的线上 bug 中最常见的, ...
- Java设计模式-备忘录模式Memento
介绍 备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 可以这里理解备忘录模式:现实生 ...
- Oracle 中LONG RAW BLOB CLOB类型介绍
说明: RAW: 未加工类型,可存储二进制数据或字节符 LONG: 可变长的字符串数据,最长2G,LONG具有VARCHAR2列的特性,可以存储长文本一个表中最多一个LONG列[不建议使用] LONG ...
- B - Bracket Sequence题解
B - Bracket Sequence 思路: 用一个flag来标记括号的数目,如果括号数目是个偶数的话,就代表当前要执行'+'操作,反之就是'*'操作.对于最外层的数,是没有计算的. 所以最后要单 ...
- Innodb存储引擎的文件
目录 概述 参数文件 日志文件 错误日志 慢查询日志 查询日志 二进制日志 binary log 二进制日志的配置 二进制日志的作用 二进制日志的保存 socket 套接字文件 pid文件 MySQL ...