手把手教你搭建 React UI 组件库 (二) 实现 Icon 组件(上)

1,815 阅读2分钟

1. 查看已有的开源库framework7, 来参考他们的API

framework7

image.png

2. 第一个小目标:先渲染最简单的Icon文字:

  1. 新建文件@/lib/Icon/index.tsx(@ 表示项目根目录, 如果文件夹没有就创建):
import * as React from 'react';

const Icon: React.FC =()=>{

  return<div>Icon</div>
}
export default Icon;

  1. 修改文件:@/lib/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import Icon from './Icon';


ReactDOM.render(<Icon/>,document.getElementById('root'))
  1. 在项目根目录运行命令:yarn start

  2. 浏览器查看http://localhost:8080/

image.png

  1. 第一个目标实现!

3. 第二个小目标: 让Icon组件能够接受参数

  1. 修改@/lib/Icon/index.tsx
import * as React from 'react';

//告诉Icon组件我需要接受icon参数
interface IconType {
    icon: string
}
                                 //接受icon参数
const Icon: React.FC<IconType> =({icon})=>{

    //展示icon参数
    return<div>{icon}</div>
}
export default Icon;
  1. 修改@/lib/index.tsx:
import React from 'react';
import ReactDOM from 'react-dom';
import Icon from './Icon';

//传递参数
ReactDOM.render(<Icon icon='我是一个参数'/>,document.getElementById('root'))
  1. 保存代码, 查看浏览器:

image.png

  1. 第二个目标实现 !

4. 第三个小目标: 我想要显示svg图标

4.1 下载svg资源

iconfont 搜索并下载微信, 支付宝图标:

image.png image.png

复制到@/lib/assets/icons/

image.png

4.2 代码引入svg

修改@/lib/Icon/index.tsx

import * as React from 'react';
import wechat from '../assets/icons/wechat.svg';

interface IconType {
    icon: string
}

const Icon: React.FC<IconType> =({icon})=>{

    return<div>{icon}</div>
}
export default Icon;

但是发现报错:

image.png

原因是 没有配置路径

4.3 配置svg路径

新建@/types/custom.d.ts文件, 为的是给每个svg加一个export default

declare module '*.svg' {
    const content: any;
    export default content;
}

修改ts配置@/tsconfig.json,告诉ts我们的源文件夹地址

"include": [
  "lib/**/*",
  "types/**/*",
],

image.png

安装 svg加载器: yarn add svg-sprite-loader

修改webpack配置@/webpack.config.js, 告诉webpack怎么使用svg加载器

{
    test: /.svg$/,
    loader: 'svg-sprite-loader',
},

image.png

4.4 显示svg

修改@/lib/Icon/index.tsx

import * as React from 'react';
import wechat from '../assets/icons/wechat.svg';

console.log(wechat);

interface IconType {
    icon: string
}

const Icon: React.FC<IconType> =({icon})=>{

    return<div>
        <svg>
            <use xlinkHref='#wechat'></use>
        </svg>
    </div>
}
export default Icon;

重新启动项目: yarn start

查看浏览器:

image.png

我们目标成功了!

5. 第四个小目标: 根据不同名字显示不同图标

修改@/lib/Icon/index.tsx

import * as React from 'react';
import '../assets/icons/wechat.svg';
import '../assets/icons/alipay.svg';


interface IconType {
    icon: string
}

const Icon: React.FC<IconType> =({icon})=>{

    return<span>
        <svg>
            <use xlinkHref={ `#${icon}` }></use>
        </svg>
    </span>
}
export default Icon;

修改@/lib/index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import Icon from './Icon';


ReactDOM.render(
    <div>
        <Icon icon='wechat'/>
        <Icon icon='alipay'/>
    </div>
    ,
    document.getElementById('root')
)

查看浏览器:

image.png

我们的目标成功了!

6. 第五个小目标: 一次加载所有svg

现阶段, 我们是每个svg 就有一个import语句,当有100个svg文件, 这样import svg 就很麻烦

image.png

所以我们希望能一次性import所有svg

一个个引入称之为静态引入, 一次性全部引入称之为非静态引入. tree-shaking的基础是静态引入. tree-shaking: 就是把苹果树上不需要的苹果摇下来, 需要的苹果留在树上.

新增文件:@/lib/Icon/importAllIcons.js

let importAll = (requireContext) => requireContext.keys().forEach(requireContext)
try {
    importAll(require.context('../assets/icons/', true, /.svg$/))
} catch (error) {
}

修改@/lib/Icon/index.tsx

import './importAllIcons';

image.png

查看浏览器:

image.png

我们的目标成功了!