总结
- 上一篇笔记中,我们在定义组件样式时,使用过
&.yourClassName
来给使用同一组件名创造的不同组件设置独特的样式- 比如:在style.js中我们给
<A>
组件规定了统一的样式,在统一的样式中又使用&.aa{样式们}
和&.bb{}
设置了不同的样式,那么在index.js中我们就可以使用<A className="aa"><A/>
和<A className="bb" ><A/>
来创建样式有些许不同的A组件了。
- 比如:在style.js中我们给
- 也在定义组件的样式中使用过
&::placeholder
给组件的placeholder
属性 设置样式。 - 之前我们都是给同一层级的组件定义样式。而
.yourClassName
是给组件中的组件(即子组件)设置样式。- 比如:我们在index.js中使用 iconfont图标 时组件是span,这并不是我们自己定义的组件,所以想要修改iconfont图标的部分样式时,我们 可以在SearchWrapper的样式中加入
.iconfont{样式们}
来设置。1
2
3
4<SearchWrapper>
<NavSearch />
<span className="iconfont"></span>
</SearchWrapper>
- 比如:我们在index.js中使用 iconfont图标 时组件是span,这并不是我们自己定义的组件,所以想要修改iconfont图标的部分样式时,我们 可以在SearchWrapper的样式中加入
注意
- 同时调用多个样式名时,用空格分隔样式名。
- &表示当前元素
- 例如下面代码**编译之后就是
a.b{}
**(表示className为b的a组件),没有&就成了a .b
(中间有个空格,b这个class成了a的后代元素的了)。1
2
3a{
&.b {}
}
- 例如下面代码**编译之后就是
使用iconfont嵌入头部图标
需要借助**iconfont官网**完成以下操作。
新建项目
打开iconfont官网-注册登录-“图标管理”-“我的项目”-(点击右边图标)新建项目(图标仓库):
目前我们需要3个图标:
添加图标
1.在顶部搜索框中搜索我们需要的图标-加入“购物车”:
2.点击右上角 购物车图标 -“添加至项目”:
3.修改羽毛颜色后,“下载至本地”:
4.得到压缩文件download
,此时文件中**demo_index.html
教我们如何使用iconfont**,真正有用的是下面5个文件:
5.将有用的6个文件添加至 src\statics下新建的iconfont文件夹中。
使用图标
修改iconfont.css为全局样式组件
iconfont.css是iconfont主要的css文件。
改为相对路径
1.我们需要给iconfont.css中每个url的路径前加./
,将其改为相对路径(以data:
开头的路径不需要加,他是base64的文件)
2.下面的几个class可以先删除:
改为全局样式组件
因为我们整个项目都可能需要用到iconfont,所以iconfont.css 改为全局样式组件会更合适。
- 定义全局样式组件:将iconfont.css重命名为iconfont.js,在iconfont.js中,借助’styled-components’的createGlobalStyle定义全局样式组件GlobalIconFontStyle。
- 使用全局样式组件:在src-App.js中,引入并使用 全局样式组件GlobalIconFontStyle(注意引用路径和Globalstyle不同)
iconfont.js中,定义全局样式组件GlobalIconFontStyle:
1 | import { createGlobalStyle } from 'styled-components' |
App.js中,引入并使用 全局样式组件GlobalIconFontStyle:
1 | import React, { Component,Fragment } from 'react'; |
控制台未报错,说明iconfont成功引入:
使用Aa
图标
根据demo的使用方法,使用<span>
标签替换我们common-header-index.js中的Aa
.
注意:在react中使用className代替class
1.文件夹中的**demo_index.html
-Unicode
拉到最下面有教我们使用方法**:
几年前是<i>
标签用于引用字体图标,现在文档改为了<span>
,其实你写<div>
也可以,但最好和官方保持一致。
文档中的字体编码:
2.common-header-index.js中,使用<span>
标签替换我们原本的字符串Aa
:
1 | <NavItem className="right"> |
注意:在react中使用className代替class
使用羽毛笔图标
common-header-index.js:
1 | <Button className="writting"> |
使用搜索图标(.iconfont
设置图标样式)
- 使用SearchWrapper组件:因为搜索框(input)内不能再放置组件,所以我们只能把搜索图标放在搜索框外,然后使用SearchWrapper组件(div)将他们包裹**起来。
- 使用子绝父相对图标进行定位:为了让图标出现在搜索框内,我们需要将它绝对定位以脱离文档流。为了布局方便,他的父元素SearchWrapper组件需要设置为相对定位。
- 注意:在包裹图标的 父组件样式 中添加
.iconfont
设置(子组件)图标的样式- 回顾:
- 以前我们在定义组件样式时,使用过**
&.yourClassName
来给使用某个className
的样式组件设置不同的样式**(比如<A className="aa" />
和<A className="bb" />
就可以在样式上稍有不同)。 - 也使用过**
&::placeholder
给placeholder
属性 设置样式**。他们都是同一个组件中的内容。 - 而iconfont使用的span组件并不是我们自己定义的,所以他的样式要去父组件中给子组件(即span)设置,我们可以通过在父组件中增加
.iconfont
给组件中的组件(即子组件)设置样式。
common-header-style.js:
复习:line-height
设置
- SearchWrapper组件需要左浮动:因为他前面的组件全都浮动了,浮动的组件脱离了文档流,所以她也需要浮动才能出现在我们希望的位置。
- 图标
line-hight
垂直居中:因为这个图标是<span>
元素,所以可以使用line-hight
实现垂直居中。【绝对定位使得元素成为inline-block,所以虽然表现为块状,但仍然可以使用行内元素的line-hight
属性实现垂直居中】 - 图标
text-align
水平居中:因为这个图标是<span>
元素,所以可以使用text-align
水平居中。
1 | export const SearchWrapper = styled.div` |
common-header-index.js:
1 | <SearchWrapper> |
搜索图标上的绿色背景是为点击以后的动态效果所保留的(具体效果可以从简书官网看到)
实现搜索框动画效果
要实现的效果:点击搜索框时搜索框变长且搜索按钮变为灰底白字。
搜索框两种样式
首先我们不考虑逻辑,只考虑如何做出两个样式。
样式1:我们原本的搜索框样式(窄且按钮无底色)
样式2:点击后显示的样式,搜索框长且按钮为灰底白字。
注意: react中我们尽量不操作DOM,我们使用数据的改变来让页面发生改变。
思路
- 在Header组件的index.js中创造一个构造函数,在state中保存一个变量
focused
表示搜索框是否被选中,选中则为true,未选中则为false。 - 在Header组件的style.js中,给搜索框的样式NavSearch增加
&.focused{}
样式,设置搜索框宽度拉长。 - 在Header组件的style.js中,在
.iconfont{}
中添加&.focused{}
设置点击后背景变为灰色,图标变为白色。 - 在组件的className中结合 三目运算符实现:根据state中
focused
变量 值 改变 样式名。- 假设点击时focused为true,则搜索框的样式对应
&.focused{}
,图标的样式对应.iconfont{}
中添加&.focused{}
- 假设未点击时focused为false,则搜索框的样式对应空(即使用NavSearch组件原本的样式),图标的样式对应 iconfont(即原定样式)
- 当然此时我们还没做逻辑判断,通过手动修改state中focused的值来看两种不同的效果。
- 注意:组件使用多个样式表时,使用 空格 分隔多个样式表名。
- 假设点击时focused为true,则搜索框的样式对应
代码实现
1.Header-index.js:
在Header组件中创造一个构造函数,在state中保存一个变量focused
表示搜索框是否被选中,选中则为true,未选中则为false:
1 | constructor(props) { |
2.Header-style.js:
给搜索框的样式NavSearch增加&.focused{}
样式,设置搜索框宽度拉长:
1 | export const NavSearch = styled.input.attrs({ |
3.在.iconfont{}
中添加&.focused{}
设置点击后背景变为灰色,图标变为白色:
(注意:是在.iconfont{}
中添加,由于iconfont不是我们定义的组件,所以想要给她设置样式则需要通过 在iconfont的父组件中设置子组件的样式 的方式)
1 | export const SearchWrapper = styled.div` |
4.index.js:
在组件的className中结合 三目运算符实现:根据state中 focused
变量 值 改变 样式名:
1 | <SearchWrapper> |
在上面的代码中,我们假设点击时focused为true,则搜索框的样式对应&.focused{}
,图标的样式对应.iconfont{}
中添加&.focused{}
。
假设未点击时focused为false,则搜索框的样式对应空(即使用NavSearch组件原本的样式),图标的样式对应 iconfont(即原定样式)。
注意:组件使用多个样式表时,使用 空格 分隔多个样式表名。
5.效果展示
当然此时我们还没做逻辑判断,可以通过手动修改state中focused的值来看两种不同的效果。
focused: false
时:
focused: true
时:
实现逻辑判断
实现效果:点击搜索框则修改state中的focused值为true,搜索框失去焦点时state中的focused值变为false。
思路
- 在Header组件中,给搜索框NavSearch绑定
onFocus
事件函数handleInputFocus
(记得在构造函数中使用bind()绑定this指向) - 创建handleInputFocus函数,在函数中调用setState()将focused值设为true。
- 给搜索框NavSearch绑定
onBlur
事件函数handleInputBlur
(记得在构造函数中使用bind()绑定this指向) - 创建handleInputBlur函数,在函数中调用setState()将focused值设为 false。
通过focused值的改变就能改变样式,但目前还没有动画效果。
代码实现
Header-index.js
给搜索框NavSearch绑定onFocus
事件函数handleInputFocus
,以及**onBlur
事件函数**handleInputBlur
:
1 | <NavSearch |
记得在构造函数中使用bind()绑定this指向:
1 | constructor(props) { |
创建handleInputFocus函数,在函数中调用setState()将focused值设为true。创建handleInputBlur函数,在函数中调用setState()将focused值设为 false:
1 | handleInputFocus() { |
实现动画效果
要实现动画效果就需要用到之前笔记提到过的**react-transition-group
**(可以在github上搜索到)
**1.在项目中安装react-transition-group
**:
1 | yarn add react-transition-group |
2.使用CSSTransition实现简单的过渡动画(可参考笔记):
header-index.js:
(复习CSS transition属性)
引入CSSTransition组件:
1 | import { CSSTransition } from 'react-transition-group'; |
使用 CSSTransition组件 包裹 NavSearch组件:
1 | <CSSTransition |
注意:classNames
属性值决定了对应的样式前缀
style.js:
由于CSSTransition依旧不是我们自定义的组件,所以想定义他的样式要通过去父组件中给子组件定义的方式来实现:
1 | export const SearchWrapper = styled.div` |
优化代码
动画效果的样式是针对NavSearch组件的,可我们上面把他们放在了CSSTransition的父组件SearchWrapper的样式中,这样虽然执行没问题,但我们应该将它们放到NavSearch组件的样式中会更好:
1 | export const NavSearch = styled.input.attrs({ |
注意:在这里动画样式是针对NavSearch组件的,不再是针对子组件,所以要加上&
!表示当前组件的动画样式
复习:
&表示当前元素,例如:
1 | a{ |
编译之后就是a.b{}
没有&就成了a .b
(中间有个空格,b这个class成了a的后代元素的了)