第一个组件Icon
iconfont下载svg
在阿里的iconfont网站下载想要的图片,目的是通过svg内置于组件,但是,就目前的配置来说,webpack并不支持svg,所以又需要下载新的loader,来处理svg了。
webpack配置svg
配置 loader,使用svg-sprite-loader
{
// 处理svg图标
test: /\.svg$/,
// 这个loader会把所有svg弄到index.html最上面,root的div之前
loader:'svg-sprite-loader',
}
接着引入svg,发现ts报警告,ts不支持svg,所以又得给ts配置一下
ts配置svg
为了后续的组件类型也得变化,建立一个types文件夹,新建custom.d.ts文件,
// 意思是,声明 所有的svg格式,类型都是any,因为ts就只认识那几种格式的文件
// 给svg文件加了一个默认导出,不然不能用import xx from './xxx.svg'
// 只能import './xxx.svg' ,有当做一个模块xx来使用的目的的时候,就需要有导出,但是svg文件没有,所以需要外部加上
declare module '*.svg' {
const content: any
export default content
}
本来是放在根目录的,但是在配置tsconfig的include的时候,却无法配置成功,不知道为什么include只能识别lib,我家types也没用,在引用的时候还是会报错,所以把types文件夹移入lib文件夹下,就不报错了
以下是tsconfig配置
// ts-loader会报错,要把include入口处定义一下,咱们要转译的就是lib下的所有ts文件
// types文件也得加入,因为要引入这下面的比如svg格式进组件,相当于ts也得识别他们
// 但是加入也没效果,反而是把types放进lib里面就行了
// 总之,ts涉及到的文件夹都应该放入include
"include": [
"lib/**/*",
// "types/**/*",
],
配置Icon组件
要用到svg标签,和use标签
import React from 'react'
import '../icons/wechat.svg'
import '../icons/alipay.svg'
import '../icons/qq.svg'
import '../icons/baidu.svg'
import '../icons/csdn.svg'
// 声明Icon组件接收的类型
interface IconProps {
name: string;
}
// 最好用箭头函数的形式,方便ts进行声明
const Icon: React.FunctionComponent<IconProps> = (props) => {
return (
<span>
<svg>
{/* 这里的wechat是icons文件夹下svg文件的文件名 */}
<use xlinkHref={`#${props.name}`}/>
</svg>
</span>
)
}
export default Icon
这样需要手动添加所有的svg文件,下面配置如何自动添加
新建importIcons.js , 不用ts是这段代码不需要声明,但是ts会多写很多不必要的声明,很麻烦
let importAll = (requireContext) => requireContext.keys().forEach(requireContext )
try{
importAll(require.context('./icons',true,/\.svg$/))
}catch(error){
console.log(error);
}
再引入即可
import React from 'react'
import './importIcons'
// import '../icons/wechat.svg'
// import '../icons/alipay.svg'
// import '../icons/qq.svg'
// import '../icons/baidu.svg'
// import '../icons/csdn.svg'
配置css样式
webpack配置scss的loader
配置sass
{
// scss的loader,支持scss或sass
// test:/\.s([ac])ss$/,
test:/\.s[ac]ss$/,
// 使用顺序是从右往左,pop出去的,先sass-loader
use:['style-loader','css-loader','sass-loader']
}
中途会需要安装node-sass,
但是node-sass一直出错,是真的烦这个,
gyp verb `which` failed at F (D:\workspace\fun-ui\node_modules\which\which.js:68:19)
gyp verb `which` failed at E (D:\workspace\fun-ui\node_modules\which\which.js:80:29)
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\which\which.js:89:16
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\index.js:42:5
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\windows.js:36:5
gyp verb `which` failed at FSReqCallback.oncomplete (fs.js:183:21)
gyp verb `which` failed python2 Error: not found: python2
gyp verb `which` failed at getNotFoundError (D:\workspace\fun-ui\node_modules\which\which.js:13:12)
gyp verb `which` failed at F (D:\workspace\fun-ui\node_modules\which\which.js:68:19)
gyp verb `which` failed at E (D:\workspace\fun-ui\node_modules\which\which.js:80:29)
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\which\which.js:89:16
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\index.js:42:5
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\windows.js:36:5
gyp verb `which` failed at FSReqCallback.oncomplete (fs.js:183:21) {
gyp verb `which` failed code: 'ENOENT'
gyp verb `which` failed }
gyp verb check python checking for Python executable "python" in the PATH
gyp verb `which` succeeded python C:\Users\AS\AppData\Local\Programs\Python\Python37\python.EXE
gyp ERR! configure error
gyp ERR! stack Error: Command failed: C:\Users\AS\AppData\Local\Programs\Python\Python3gyp ERR! stack File "<string>", line 1
gyp ERR! stack import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack ^
gyp ERR! stack SyntaxError: invalid syntax
gyp ERR! stack
gyp ERR! stack at ChildProcess.exithandler (child_process.js:308:12)
gyp ERR! stack at ChildProcess.emit (events.js:315:20)
gyp ERR! stack
找遍了终于找到了可以用的办法
首先版本如下,不能下错了,比如node-sass下4.9.4就一直下不下来
"node-sass": "^4.14.1",
"css-loader": "1.0.0",
"sass-loader": "7.1.0",
"style-loader": "0.23.1",
其他三个loader yarn add --dev就行
node-sass要用如下命令参考1 参考2
npm i node-sass@4.14.1 --save-dev --sass_binary_site=https://npm.taobao.org/mirrors/node-sass@4.14.1/
配置组件的点击事件以及className等属性
需要非静态添加所有dom事件,比如onClick,onMouseEnter等
还需要解构props,分离className,name等
import React from 'react'
import './importIcons'
// import '../icons/wechat.svg'
// import '../icons/alipay.svg'
// import '../icons/qq.svg'
// import '../icons/baidu.svg'
// import '../icons/csdn.svg'
import classes from './helper/classes'
import './icon.scss'
// 声明Icon组件接收的类型
// 这个继承的含义是 继承于React内置的SVGAttributes,
// 然后这个SVGAttributes可以有onClick等一系列事件,并且接收一个参数
// 这个参数就是指定什么元素能响应这些事件,所以就不需要单独每个写onClick事件了
interface IconProps extends React.SVGAttributes<SVGElement> {
// icon的名字
name: string;
// onClick是鼠标点击svg标签的事件
// onClick: React.MouseEventHandler<SVGElement>
// onClick:(e:React.MouseEvent)=>void
}
// 最好用箭头函数的形式,方便ts进行声明
const Icon: React.FunctionComponent<IconProps> = ({
className,
name,
...restProps
}) => {
// 分离出className和其余props,可以直接写到括号里面
return (
<svg
className={classes('fun-ui-icon', className)}
// {}是表示用js语法
{...restProps}
// onClick={props.onClick}
// onMouseLeave={props.onMouseLeave}
// onMouseEnter={props.onMouseEnter}
>
{/* 这里的wechat是icons文件夹下svg文件的文件名 */}
<use xlinkHref={`#${name}`} />
</svg>
)
}
export default Icon
测试className
需要安装babel-preset-react-app@6.1.0
然后又遇到报错gyp这种,又只能像上面那样用npm taobao来下载安装
gyp verb `which` failed at F (D:\workspace\fun-ui\node_modules\which\which.js:68:19)
gyp verb `which` failed at E (D:\workspace\fun-ui\node_modules\which\which.js:80:29)
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\which\which.js:89:16
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\index.js:42:5
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\windows.js:36:5
gyp verb `which` failed at FSReqCallback.oncomplete (fs.js:183:21)
gyp verb `which` failed python2 Error: not found: python2
gyp verb `which` failed at getNotFoundError (D:\workspace\fun-ui\node_modules\which\which.js:13:12)
gyp verb `which` failed at F (D:\workspace\fun-ui\node_modules\which\which.js:68:19)
gyp verb `which` failed at E (D:\workspace\fun-ui\node_modules\which\which.js:80:29)
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\which\which.js:89:16
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\index.js:42:5
gyp verb `which` failed at D:\workspace\fun-ui\node_modules\isexe\windows.js:36:5
gyp verb `which` failed at FSReqCallback.oncomplete (fs.js:183:21) {
gyp verb `which` failed code: 'ENOENT'
gyp verb `which` failed }
gyp verb check python checking for Python executable "python" in the PATH
gyp verb `which` succeeded python C:\Users\AS\AppData\Local\Programs\Python\Python37\python.EXE
gyp ERR! configure error
gyp ERR! stack Error: Command failed: C:\Users\AS\AppData\Local\Programs\Python\Python3gyp ERR! stack File "<string>", line 1
gyp ERR! stack import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack ^
gyp ERR! stack SyntaxError: invalid syntax
gyp ERR! stack
gyp ERR! stack at ChildProcess.exithandler (child_process.js:308:12)
gyp ERR! stack at ChildProcess.emit (events.js:315:20)
gyp ERR! stack
用下面命令,才可以
npm i babel-preset-react-app@6.1.0 --save-dev --sass_binary_site=https://npm.taobao.org/mirrors/babel-preset-react-app/
测试就能运行了
测试icon
哎哟这个是真的难配置,我吐了
此处只说最后结果,过程不再叙述,太漫长了
我发现测试用的依赖包,都得用npm 改到淘宝的办法下载,yarn根本不行,好像是跟那个node-sass有关的,都要调用本地c++库什么原因,
安装如下依赖,全部使用之前的命令
@wojtekmaj/enzyme-adapter-react-17
enzyme
jsdom
jsdom-global
npm i @wojtekmaj/enzyme-adapter-react-17 --save-dev --sass_binary_site=https://npm.taobao.org/mirrors/@wojtekmaj/enzyme-adapter-react-17/
npm i enzyme --save-dev --sass_binary_site=https://npm.taobao.org/mirrors/enzyme/
npm i jsdom --save-dev --sass_binary_site=https://npm.taobao.org/mirrors/jsdom/
npm i jsdom-global --save-dev --sass_binary_site=https://npm.taobao.org/mirrors/jsdom-global/
然后配置setup.Tests.js
// react17的配置
// 这个包也行,不过留一个用的多的就行了
// const Adapter = require('enzyme-adapter-react-17-updated')
const enzyme = require('enzyme')
const Adapter = require('@wojtekmaj/enzyme-adapter-react-17')
enzyme.configure({ adapter: new Adapter() });
icon的测试用例里面,头部要加jsdom,给他一个虚拟环境
import 'jsdom-global/register'
import React from 'react'
import renderer from 'react-test-renderer'
import Icon from '../icon'
import {mount} from 'enzyme'
describe('icon', () => {
it('render successfully', () => {
const json = renderer.create(<Icon name='alipay' />).toJSON()
// 期望json符合快照
expect(json).toMatchSnapshot()
})
it('onClick',()=>{
const fn = jest.fn()
const component = mount(<Icon name='alipay' onClick={fn}/>)
component.find('svg').simulate('click')
// expect(n).toEqual(2)
expect(fn).toBeCalled()
})
})