(02)Header 组件开发——② iconfont 在 React 实战中的应用 | React.js 项目实战:PC 端“简书”开发

转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 生成 Header 组件文件目录

大家知道,"简书"这个 PC 端项目,"前端一万小时"并不是第一次接触到。如果你和我一样,把"🚀HTML+CSS 实战:PC 端"简书"静态首页开发"那 3 篇文章认认真真写过的话,本篇的 Header 组件布局将难不倒你。

❗️为了更好地掌握基础知识,本项目的"结构"和"样式"部分,我们就对照那 3 篇文章来改写,有不熟悉的 CSS 知识点,请立刻去回顾。相信这轮过后,你的 CSS 基础定会更上一层楼!

🔗《🚀HTML+CSS 实战:PC 端"简书"静态首页开发------① 结构 + Header》

Header 组件是简书这个网页各页面共有的"头部区块"。

1️⃣在 src 目录下新建一个 common 文件夹。这个文件夹用来放置所有页面"共有"的东西(如本篇的 Header 组件):

2️⃣在 common 目录下的 header 文件夹里添加一个 index.js 文件,本篇中这个文件指的就是"Header 头部组件":

3️⃣打开 header 目录下的 index.js 文件,编写 Header 组件:

jsx 复制代码
import React, {Component} from "react";

class Header extends Component {
	render() {
  	return (
    	<div>header</div>
    )
  }
}

export default Header;

4️⃣上一步编写完 Header 组件后,我们就可以在其他地方进行引用了。打开 src 目录下的 App.js 文件:

jsx 复制代码
import React, { Component } from "react";

import {GlobalStyle} from "./style";

// ❗️4️⃣-①:引入 Header 组件;
import Header from "./common/header";

class App extends Component  {  
  
  render() {  
    return (
      <div>
        <GlobalStyle />
        
        {/* 4️⃣-②:将 Header 组件渲染出来; */}
        <Header />
      </div>
    );
  }
}

export default App; 

返回页面查看效果:

5️⃣既然 Header 组件所属的页面已成功显示,接下来我们就可以进行 Header 组件的"结构"和"样式"的编写了。

2 生成 iconfont

在开始布局整个页面之前,我们先把项目会用到的 icon 通过阿里的 Iconfont 制作出来。

关于 iconfont,我们之前的文章(《CSS------CSS 给文本加样式:① 字体属性》)有过详细的讲解,本篇不作原理的说明,请跟着我的步骤做即可。

1️⃣打开 Iconfont ,创建仓库:

2️⃣仓库创建好后,搜索整个项目需要用到的图标,加入"购物车"后,添加至项目 qdywxs-jianshu (❗️可以自行修改每一个 icon 的样式):

3️⃣图标准备完毕后,下载至本地:

4️⃣打开下载下来的文件夹,按下图所示整理出需要的文件格式:

5️⃣打开 qdywxs-jianshu 项目的文件夹,在 src 目录下新增一个 static 文件夹,用于放置本项目需要的"静态资源":

6️⃣在 static 文件夹下新建一个 iconfont 文件夹,用于放置 icon 图标文件:

7️⃣将上边第 4️⃣步中整理好的文件,剪切至项目的 static 目录下的 iconfont 文件夹中:

8️⃣可以返回编辑器查看一下项目目录:

3 配置 iconfont

9️⃣打开 iconfont 目录下的 iconfont.css 文件,我们需要对里边的代码做一些修改(给 src 的 url 链接添加一个相对路径 ./ ):

css 复制代码
@font-face {
  font-family: "iconfont";
  
  /* ❗️增加相对路径 ./ */
  src: url('./iconfont.eot?t=1566358182566'); /* IE9 */
  src: url('./iconfont.eot?t=1566358182566#iefix') format('embedded-opentype'), /* IE6-IE8 */
    
  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAngAAsAAAAAEbwAAAmQAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCFGgqTPJAKATYCJANECyQABCAFhG0HgTgbHg8RVazPJPuZkLmp0F6JXNxkiKUMrYWiDP03S6zvmeCp/Hv609NzhbeiKxeYwdluCFW+oeAQwMf9gW35D/AK9Kr1sr2ORXk3hIs2ah3c1rI1GMtIddVuv/MCwMylpXSWAGSArsHQb7xyx7cuV6wbSalTa62qN6Iueu1TYWhp78X2Dn7xFxHEJREalW6yiEolVCudkjsqoxmB7UWL9sSYiHMyBAipQSpIv7qBJLhjIamgxmydpgvca4XYIfGCn+dGdrQgm8HBNwvRO8Am/n55RxtxBwyOAp2qv7pWCRVOeP1dmV6G0dgOWDk/OfC2GyjQDMCCXIkqz6G5pBmjMNbQsgWognfrXi95aZyeM3LmznJnh1P72eez9HPhl1+LgniuibNHV0grVNE5I4n+Jx7g4ZJi8YnJEJQcFwIMESEJiAtAsQq+5cqBl1gKHrw0FFx46VFI4WVEwcLLhIIPL1MKMbzMpDCTAyNgegCjYHqCt0xmHDAOmOmgEMCrEsYw0waYCExnyAk5P/loRAJACfXrALQDzKuPovpAUWtRCuZaQYbtDor9RRL7SxlGg0LTvb1FoqBASbBEKPQRiqLEAj/MV+DpKRAgHi5iYVCErxAl9KJC7w6VZqrNVnHJQfmrkxvtaSqeDdLsf4I4HjQp1bsckidPaLs9i9/Kbg9CDpcV5IxtMvV4IHdsul6fpc2rV23zt+Hv7JOhOhnHBNDl5Dy7e3Wgj/e2c4hLz3nChz0bIrCcmWLkwK7kqxJz18FMuNJo6gnSmLfzjL+Sw42BatOqnyUCVLyV07AEGzS7qlftlQVyumD9yjH8cBPnny1hdEiLKbLYbidQz2zqMgaaQpF5HRI/dk6CrT9PeLFnxeiaMzlCoz/JtS/Q39Qnjp4VA707QbRgf2wDec83Ct5G8vZ8vyF3I5e3J/A2fFuAZnNUNlvzltJVssMxyWhCep4QLM9wuOOeXOGpwg1QmAlRS0IOEGMViEUDUI6byu4MCIk7aqelgSF4+Jo7xnsSCU5PCVE/PyHMvDv7yJ3wuW4J5I6DucRBO/skmzh+OJnatQdcd69NCMkkijIZ/Rs569btQTQh50P51RQtn0w1R4Ja/UWH2q1uacK7HO8pxwv6yTu5/SlpmzLPJ7A9k9s/0E+eUw5ti6KRIhU0ifM72d09u4w7JquVHl5dO9u469Ilx8ZUtN89m7T7/P18BkMqueHbjvCbjy4iEi3FrZ1uICnZtITubedCXVafT2ADunieq2bdssNfYN1JHM7ibwp06QlSmImtZ8GuPBPbyXUIepjdfdiX2hU4TA7GCpTJZD5NpmYhK0soSDBtC6LNPHcUh0YDaY4L/4zEXXioBxvv04T9YcyOJF4oqywvK4fMstAXxvcViy25HxjQpUvRYWg0/fP6jZZgi1v0XUxjNjpsyVIxYxitP2BhaJUrUm8wyJAK6O5XNGCkuH0gFE3oVwH1iN6A1CeEVkFp/7hNe8Oylw4WnP7rr6MQC/qF9nR5AO2i4q8tOLnQ3jeyYR32+A62TuHHj5UYUxCP3C93jv+qsJ1RsftP7wqTEgvhyOILEyR14onicRKNsE6kLoze5PEyrMNfBuPwOwwtYYPJ42VZymhSR77yUy8MnwF3VxZ5jUfv5eOLPCegrwnOG0RYHFjfoyDh7cwCny3aOvfpK/WTKvtCJ7J8ZGirWzPRJtsW6CefrWuEfuP6/39+6LPMmB3dZ87QBgVwywM7A/RQ6eZa6YB5xHchA0e5y9Ha76PU0oz1UO3nVWdeEK+ix2oNBvbQYe2o+gPtjY+CvVUzdUtGBwtUnWPEkTJ42aFJbfSp0vlOHtqHYqPfZ0+oIHGF6/SuRQeA30tHIpMnoy1os5c09+MnTUYhfFuWDEK0WsTFD9Zq4hGN5nEGabThv4xz57v9fP7DTbdJoklup2HfM3juzc8cdWak2wLRAreRrpCfPe6aP4zbfNFE15GukyBS3X0Pd1jnr62TZvcJG5r2U4+x764cWNh34YEr7/qyn5o3YdeF6qRr51s7DgdVqC+oomfsREa/zZWJHVEnfYaWjDJ1fE5GOcS5sreA3RdTRV9Qz3LICmSgKKmw0ndGRI2wqgvH5McXFi1cIuv0i8/v/nQoc4wun7Vhp76XmzIssldVpvgxkL6jz7qy4hEe8hO+oph5BPV5m3g06vjWwl0Dbg6eYm28OuSmdcrVpvYE19nPdqP/3ay3XbLTErWm5lS/tsX1x/qdWtx2rJ6OW7Xny5BFtHPw4sfbfggv3/LdG1OMZ4wkW2SMgdz+DOl9MdhFkZdZlXRNztHgUFn8jGWLmdi+wX+e61dz5U+WxTJ10r+zVisoK3itjmA/fMKOSOhpJyp9P72ZLJ9eNt1mnCifOEs+q8xnKme9NZ/VV74F/0iMt2/78hgPKZ59APX26+gSW7p92qHOSwpqn0adWdGwIVzlPiYne6MbqsOkoTEbfdvBYweDNYHgo/aRelM/Nj3tlAlRb/eL6tMs3c4hs6N/rIU6GaNe6oVM1lg/Vw3bRQ0vdFHPfkFd+H7NVHTzIlSn9ZvZqWiZwGI6jLgIhvy829j2Ywv8c2wB65H+FmKrKPXHFtiOwopeBlpS+6AVAMUFCwovv0nfaDsAWMwdsaTWRHcCxR96HvMQSR90BXrGeF7N2DQHVAtW2fs/1qJHer8UK20CtgOATSmM6VX2yxa0o0y6p4ew6KS32oz+4l6q3+nEdHg1OpWLkHR4lfzmE6/NlserX2zjNvMz42OSAoZUFwvch/g9Fv0Kqahkv7trw4v/2S9lfm9MmKxXKMGSQXYDhHoMpLnaMrxeLlt+bH5iz5YvgcGjOlB86vnb4GbAIaIdcPHpCUKa0mf3iLKMAQyxHgBNmCuAkLMfGFJOAiXnLgRE8CvgUIHvgEsuGAgZivgdMKIBRNLhjWEVrbk8TXKUvSnRQ1bzG+E6WK4KOfEfLMli6qJqer6QwfPYRG6hUfXGM43mU5wOw0BmYurgtIiq07ksfWzTwtE4O8zeGFZ95tZweXImR9lPr4fW138jXAfLQzr84fwHS5q9oaagGsP/C+WxOlyX+nILDSrl3tjmTKPhU8oxaCcZpvhKHZwWxCns05lSDuTHRcXy2fG0R5x8ndL2JVmIihVHXPHElyBlechYEkklk1yOcmLV0j2vBrphI7Ds4naEiA3YMryRS9zu76VGZF1OyBtPR+BA91XGXXaKh0p6YedTbqU+yMENoY+YPVFex/kspeuRMp57qzotHam4ugp4NgMAAAA=') format('woff2'),
  
  /* ❗️增加相对路径 ./ */
  url('./iconfont.woff?t=1566358182566') format('woff'),
  url('./iconfont.ttf?t=1566358182566') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  url('./iconfont.svg?t=1566358182566#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/*
❗️❗️❗️将下面的代码注释掉!
.icondown:before {
  content: "\e610";
}

.iconlove:before {
  content: "\e711";
}

.iconsearch:before {
  content: "\e63e";
}

.iconmessage:before {
  content: "\e60b";
}

.iconrefresh:before {
  content: "\e65f";
}

.iconcomment:before {
  content: "\e602";
}

.iconpen:before {
  content: "\e600";
}

.iconfollow:before {
  content: "\e60d";
}

.iconnews:before {
  content: "\e668";
}

.icontextsize:before {
  content: "\e739";
}

.iconfindings:before {
  content: "\e732";
}

.iconcollection:before {
  content: "\e60e";
}

.iconheart:before {
  content: "\e8f4";
}

.iconmoney:before {
  content: "\e607";
}

.iconattention:before {
  content: "\e60f";
}

.iconuser:before {
  content: "\e63f";
}
 */

🔟由于 iconfont 并不是某一个组件所要用到的,整个项目都会用到 iconfont 图标。所以,我们一般把 iconfont 处理成"全局样式"! 上一篇文章我们讲解了 styled-components 怎样处理"全局样式",这里同理进行处理:

🔟-①:首先,将 iconfont 目录下的 iconfont.css 文件改名为 iconfont.js 文件;

🔟-②:对 iconfont.js 文件中的代码进行改写;

javascript 复制代码
import {createGlobalStyle} from "styled-components"; /*
																										 🔟-③:引入 createGlobalStyle
																										 方法;
                                                      */

// 🔟-④:将 iconfont 中的代码拷贝到这个"全局"样式中!
export const GlobalIconStyle = createGlobalStyle`
  @font-face {
    font-family: "iconfont";

    /*❗️增加相对路径 ./ */
    src: url('./iconfont.eot?t=1566358182566'); /* IE9 */
    src: url('./iconfont.eot?t=1566358182566#iefix') format('embedded-opentype'), /* IE6-IE8 */

    url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),

    /*❗️增加相对路径 ./ */
    url('./iconfont.woff?t=1566358182566') format('woff'),
    url('./iconfont.ttf?t=1566358182566') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
    url('./iconfont.svg?t=1566358182566#iconfont') format('svg'); /* iOS 4.1- */
  }

  .iconfont {
    font-family: "iconfont" !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
`;

🔟-⑤:打开 src 目录下的 App.js 文件;

jsx 复制代码
import React, { Component } from "react";

import {GlobalStyle} from "./style";

// 🔟-⑥:引入 iconfont.js 中定义的 GlobalIconStyle;
import {GlobalIconStyle} from "./statics/iconfont/iconfont";

import Header from "./common/header";

class App extends Component  {  
  
  render() {  
    return (
      <div>
        <GlobalStyle />
      
        {/* 🔟-⑦:同理,将 <GlobalIconStyle /> 放在组件外层,后边的组件都能应用到 icon。 */}
        <GlobalIconStyle />
      
        <Header />
      </div>
    );
  }
}

export default App; 

🔟-⑧:通过上边的操作,iconfont 已经被成功地引入到了项目中。我们可以尝试用一下 iconfont,看看到底生效了没。 打开 common 目录下 header 文件夹里的 index.js 文件:

jsx 复制代码
import React, {Component} from "react";

class Header extends Component {
  render() {
    return (
      <div>
        <div>header</div>
        
        {/* 
         🔟-⑨:我们试着在这里用一下 user 这个 iconfont。
         ❗️user 这个图标对应的 uncode 码,请自行到仓库里去拷贝!
          */}
        <span className="iconfont">&#xe63f;</span>
      </div>
    )
  }
}

export default Header;

OK,一切准备就绪,下篇我们就开始"简书" Header 组件的布局!

祝好,qdywxs ♥ you!

相关推荐
GIS程序媛—椰子10 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00116 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端19 分钟前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x22 分钟前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
木舟100923 分钟前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤439133 分钟前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢1 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安1 小时前
前端第二次作业
前端·css·css3
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习