如何在 react 改变css样式中运用 CSS

如何在 React 中运用 CSS_百度知道
如何在 React 中运用 CSS
提问者采纳
那要看在什么时代CSS和网页分离的好处是显而易见的、手机甚至是给视觉障碍的人用的声音设备,Web Component 不得不带来了 Shadow DOM 的新概念。React Component是适应 Web App 化的。此时,你仍然可以通过为 React Component 设置 className 属性,inline style 的作用自然就会被加强。在需要全局 CSS 的时候,只能通过 CSS 声明(className)来实现,来制定对应的 CSS Class。为了解决这个问题。而今天:visited)。从传统 HTML 的观点来看,“内容”(HTML)和其渲染方式 (CSS)是可以分离的,因此很自然,这样分隔就是合理的,而可能是污染了,CSS的全局性带来的就不是方便,而是由一个一个Web组件组成的应用程序窗口。基于内容传播。用户看到的已经不再是整个 HTML,Web已经从相互连接的HTML变成了相互连接的 Web App,例如PC,例如同样的文章可以被CSS渲染到不同的设备上。Inline style也有一些限制,例如声明伪类属性 (a
来自团队:
其他类似问题
为您推荐:
react的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁React 测试入门教程 - 阮一峰的网络日志
React 测试入门教程
越来越多的人,使用开发Web应用。它的测试就成了一个大问题。
React的组件结构和JSX语法,不适用传统的测试工具,必须有新的测试方法和工具。
本文总结目前React测试的基本做法和最佳实践,手把手教你如何写React测试。
一、Demo应用
请先安装。
$ git clone /ruanyf/react-testing-demo.git
$ cd react-testing-demo && npm install
$ npm start
然后,打开 http://127.0.0.1:8080/,你会看到一个 Todo 应用。
接下来,我们就要测试这个应用,一共有5个测试点。
应用标题应为"Todos"
Todo项的初始状态("未完成"或"已完成")应该正确
点击一个Todo项,它就反转状态("未完成"变为"已完成",反之亦然)
点击删除按钮,该Todo项就被删除
点击添加按钮,会新增一个Todo项
这5个都已经写好了,执行一下就可以看到结果。
$ npm test
下面就来看,测试用例应该怎么写。测试框架我用的是Mocha,如果你不熟悉,可以先读我写的。
二、测试工具库
React测试必须使用官方的,但是它用起来不够方便,所以有人做了封装,推出了一些第三方库,其中Airbnb公司的最容易上手。
这就是说,同样的测试用例至少有两种写法,本文都将介绍。
官方测试工具库的写法
Enzyme的写法
三、官方测试工具库
我们知道,一个React组件有两种存在形式:虚拟DOM对象(即<ponent的实例)和真实DOM节点。官方测试工具库对这两种形式,都提供测试解决方案。
Shallow Rendering:测试虚拟DOM的方法
DOM Rendering: 测试真实DOM的方法
3.1 Shallow Rendering
Shallow Rendering (浅渲染)指的是,将一个组件渲染成虚拟DOM对象,但是只渲染第一层,不渲染所有子组件,所以处理速度非常快。它不需要DOM环境,因为根本没有加载进DOM。
首先,在测试脚本之中,引入官方测试工具库。
import TestUtils from 'react-addons-test-utils';
然后,写一个 Shallow Rendering 函数,该函数返回的就是一个浅渲染的虚拟DOM对象。
import TestUtils from 'react-addons-test-utils';
function shallowRender(Component) {
const renderer = TestUtils.createRenderer();
renderer.render(&Component/>);
return renderer.getRenderOutput();
第一个,是测试标题是否正确。这个用例不需要与DOM互动,不涉及子组件,所以使用浅渲染非常合适。
describe('Shallow Rendering', function () {
it('App\'s title should be Todos', function () {
const app = shallowRender(App);
expect(app.props.children[0].type).to.equal('h1');
expect(app.props.children[0].props.children).to.equal('Todos');
上面代码中,const app = shallowRender(App)表示对App组件进行"浅渲染",然后app.props.children[0].props.children就是组件的标题。
你大概会觉得,这个属性的写法太古怪了,但实际上是有规律的。每一个虚拟DOM对象都有props.children属性,它包含一个数组,里面是所有的子组件。app.props.children[0]就是第一个子组件,在我们的例子中就是h1元素,它的props.children属性就是h1的文本。
第二个,是测试Todo项的初始状态。
首先,需要修改shallowRender函数,让它接受第二个参数。
import TestUtils from 'react-addons-test-utils';
function shallowRender(Component, props) {
const renderer = TestUtils.createRenderer();
renderer.render(&Component {...props}/>);
return renderer.getRenderOutput();
下面就是测试用例。
import TodoItem from '../app/components/TodoItem';
describe('Shallow Rendering', function () {
it('Todo item should not have todo-done class', function () {
const todoItemData = { id: 0, name: 'Todo one', done: false };
const todoItem = shallowRender(TodoItem, {todo: todoItemData});
expect(todoItem.props.children[0].props.className.indexOf('todo-done')).to.equal(-1);
上面代码中,由于是的子组件,所以浅渲染必须在TodoItem上调用,否则渲染不出来。在我们的例子中,初始状态反映在组件的Class属性(props.className)是否包含todo-done。
3.2 renderIntoDocument
官方测试工具库的第二种测试方法,是将组件渲染成真实的DOM节点,再进行测试。这时就需要调用renderIntoDocument 方法。
import TestUtils from 'react-addons-test-utils';
import App from '../app/components/App';
const app = TestUtils.renderIntoDocument(&App/>);
renderIntoDocument 方法要求存在一个真实的DOM环境,否则会报错。因此,测试用例之中,DOM环境(即window, document 和 navigator 对象)必须是存在的。 库提供这项功能。
import jsdom from 'jsdom';
if (typeof document === 'undefined') {
global.document = jsdom.jsdom('&!doctype html>&html>&body>&/body>&/html>');
global.window = document.defaultV
global.navigator = global.window.
将上面这段代码,保存在test子目录下,取名为 。然后,修改package.json。
"scripts": {
"test": "mocha --compilers js:babel-core/register --require ./test/setup.js",
现在,每次运行npm test,setup.js 就会包含在测试脚本之中一起执行。
第三个,是测试删除按钮。
describe('DOM Rendering', function () {
it('Click the delete button, the Todo item should be deleted', function () {
const app = TestUtils.renderIntoDocument(&App/>);
let todoItems = TestUtils.scryRenderedDOMComponentsWithTag(app, 'li');
let todoLength = todoItems.
let deleteButton = todoItems[0].querySelector('button');
TestUtils.Simulate.click(deleteButton);
let todoItemsAfterClick = TestUtils.scryRenderedDOMComponentsWithTag(app, 'li');
expect(todoItemsAfterClick.length).to.equal(todoLength - 1);
上面代码中,第一步是将App渲染成真实的DOM节点,然后使用scryRenderedDOMComponentsWithTag方法找出app里面所有的li元素。然后,取出第一个li元素里面的button元素,使用TestUtils.Simulate.click方法在该元素上模拟用户点击。最后,判断剩下的li元素应该少了一个。
这种测试方法的基本思路,就是找到目标节点,然后触发某种动作。官方测试工具库提供多种方法,帮助用户找到所需的DOM节点。
:找出所有匹配指定className的节点
:与scryRenderedDOMComponentsWithClass用法相同,但只返回一个节点,如有零个或多个匹配的节点就报错
:找出所有匹配指定标签的节点
:与scryRenderedDOMComponentsWithTag用法相同,但只返回一个节点,如有零个或多个匹配的节点就报错
:找出所有符合指定子组件的节点
:与scryRenderedComponentsWithType用法相同,但只返回一个节点,如有零个或多个匹配的节点就报错
:遍历当前组件所有的节点,只返回那些符合条件的节点
可以看到,上面这些方法很难拼写,好在还有另一种找到DOM节点的替代方法。
3.3 findDOMNode
如果一个组件已经加载进入DOM,react-dom模块的findDOMNode方法会返回该组件所对应的DOM节点。
我们使用这种方法来写第四个,用户点击Todo项时的行为。
import {findDOMNode} from 'react-dom';
describe('DOM Rendering', function (done) {
it('When click the Todo item,it should become done', function () {
const app = TestUtils.renderIntoDocument(&App/>);
const appDOM = findDOMNode(app);
const todoItem = appDOM.querySelector('li:first-child span');
let isDone = todoItem.classList.contains('todo-done');
TestUtils.Simulate.click(todoItem);
expect(todoItem.classList.contains('todo-done')).to.be.equal(!isDone);
上面代码中,findDOMNode方法返回App所在的DOM节点,然后找出第一个li节点,在它上面模拟用户点击。最后,判断classList属性里面的todo-done,是否出现或消失。
第五个测试用例,是添加新的Todo项。
describe('DOM Rendering', function (done) {
it('Add an new Todo item, when click the new todo button', function () {
const app = TestUtils.renderIntoDocument(&App/>);
const appDOM = findDOMNode(app);
let todoItemsLength = appDOM.querySelectorAll('.todo-text').
let addInput = appDOM.querySelector('input');
addInput.value = 'Todo four';
let addButton = appDOM.querySelector('.add-todo button');
TestUtils.Simulate.click(addButton);
expect(appDOM.querySelectorAll('.todo-text').length).to.be.equal(todoItemsLength + 1);
上面代码中,先找到input输入框,添加一个值。然后,找到Add Todo按钮,在它上面模拟用户点击。最后,判断新的Todo项是否出现在Todo列表之中。
findDOMNode方法的最大优点,就是支持复杂的CSS选择器。这是TestUtils本身不提供的。
四、Enzyme库
是官方测试工具库的封装,它模拟了jQuery的API,非常直观,易于使用和学习。
它提供三种测试方法。
4.1 shallow
方法就是官方的shallow rendering的封装。
下面是第一个,测试App的标题。
import {shallow} from 'enzyme';
describe('Enzyme Shallow', function () {
it('App\'s title should be Todos', function () {
let app = shallow(&App/>);
expect(app.find('h1').text()).to.equal('Todos');
上面代码中,shallow方法返回App的浅渲染,然后app.find方法找出h1元素,text方法取出该元素的文本。
关于find方法,有一个注意点,就是它只支持简单选择器,稍微复杂的一点的CSS选择器都不支持。
component.find('.my-class'); // by class name
component.find('#my-id'); // by id
component.find('td'); // by tag
component.find('div.custom-class'); // by compound selector
component.find(TableRow); // by constructor
component.find('TableRow'); // by display name
4.2 render
方法将React组件渲染成静态的HTML字符串,然后分析这段HTML代码的结构,返回一个对象。它跟shallow方法非常像,主要的不同是采用了第三方HTML解析库Cheerio,它返回的是一个Cheerio实例对象。
下面是第二个,测试所有Todo项的初始状态。
import {render} from 'enzyme';
describe('Enzyme Render', function () {
it('Todo item should not have todo-done class', function () {
let app = render(&App/>);
expect(app.find('.todo-done').length).to.equal(0);
在上面代码中,你可以看到,render方法与shallow方法的API基本是一致的。 Enzyme的设计就是,让不同的底层处理引擎,都具有同样的API(比如find方法)。
方法用于将React组件加载为真实DOM节点。
下面是第三个,测试删除按钮。
import {mount} from 'enzyme';
describe('Enzyme Mount', function () {
it('Delete Todo', function () {
let app = mount(&App/>);
let todoLength = app.find('li').
app.find('button.delete').at(0).simulate('click');
expect(app.find('li').length).to.equal(todoLength - 1);
上面代码中,find方法返回一个对象,包含了所有符合条件的子组件。在它的基础上,at方法返回指定位置的子组件,simulate方法就在这个组件上触发某种行为。
下面是第四个,测试Todo项的点击行为。
import {mount} from 'enzyme';
describe('Enzyme Mount', function () {
it('Turning a Todo item into Done', function () {
let app = mount(&App/>);
let todoItem = app.find('.todo-text').at(0);
todoItem.simulate('click');
expect(todoItem.hasClass('todo-done')).to.equal(true);
下面是第五个,测试添加新的Todo项。
import {mount} from 'enzyme';
describe('Enzyme Mount', function () {
it('Add a new Todo', function () {
let app = mount(&App/>);
let todoLength = app.find('li').
let addInput = app.find('input').get(0);
addInput.value = 'Todo Four';
app.find('.add-button').simulate('click');
expect(app.find('li').length).to.equal(todoLength + 1);
下面是Enzyme的一部分API,你可以从中了解它的大概用法。
.get(index):返回指定位置的子组件的DOM节点
.at(index):返回指定位置的子组件
.first():返回第一个子组件
.last():返回最后一个子组件
.type():返回当前组件的类型
.text():返回当前组件的文本内容
.html():返回当前组件的HTML代码形式
.props():返回根组件的所有属性
.prop(key):返回根组件的指定属性
.state([key]):返回根组件的状态
.setState(nextState):设置根组件的状态
.setProps(nextProps):设置根组件的属性
前面的文章介绍了 Systemd 的操作命令和基本用法,今天给出一个实例,如何使用 Systemd 启动一个 Node 应用。
(说明:本文选自我的新书《ES6 标准入门(第二版)》的第一章《ECMAScript 6简介》)
npm 是 Node 的模块管理器,功能极其强大。它是 Node 获得成功的重要原因之一。
如果你经常看这个博客,就会知道我写了一本书。如何在 React 中运用 CSS_百度知道
如何在 React 中运用 CSS
CSS和网页分离的好处是显而易见的?那要看在什么时代。从传统 HTML 的观点来看,“内容”(HTML)和其渲染方式 (CSS)是可以分离的,例如同样的文章可以被CSS渲染到不同的设备上,例如PC、手机甚至是给视觉障碍的人用的声音设备。基于内容传播,这样分隔就是合理的。而今天,Web已经从相互连接的HTML变成了相互连接的 Web App。用户看到的已经不再是整个 HTML,而是由一个一个Web组件组成的应用程序窗口供肌垛可艹玖讹雪番磨。此时,CSS的全局性带来的就不是方便,而可能是污染了。为了解决这个问题,Web Component 不得不带来了 Shadow DOM 的新概念。React Component是适应 Web App 化的,因此很自然,inline style 的作用自然就会被加强。在需要全局 CSS 的时候,你仍然可以通过为 React Component 设置 className 属性,来制定对应的 CSS Class。Inline style也有一些限制,只能通过 CSS 声明(className)来实现,例如声明伪类属性 (a:visited)。
其他类似问题
为您推荐:
react的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁大家对CSS in JS怎么看? - 探讨 - React 中文
04:13:07 UTC
最近在学习React,找到一个UI组件库 material-ui,发现它的css是写在JS里面的,然后找到这个,是Facebook 前端基础设施团队的人写的,感觉说的很有道理。
我现在的看法是,将来如果出现很多组件库的话,将CSS写在JS里面的确是避免冲突的好办法,不知道大家怎么看?
05:56:31 UTC
如果是项目超级大超级复杂,确实能解决css冲突问题,并且能解决css的工程问题。缺点就是css和js紧耦合了,如果需要调整样式可能不太方便了。
06:11:47 UTC
同一控件的CSS和JS本来就是在描述同一个东西所以说不上是耦合
07:32:17 UTC
我觉得是一个不错的方案,但是方案都是有利弊的,在我看来好处就是css不会冲突了,问题是这个方案应该怎么实现?
07:55:02 UTC
实现应该不困难,JSX里本来就是可以写样式的,最后输出的就是内联的样式。然后组件不应该再修改,如果要覆盖样式,可以从外部覆盖。
08:42:36 UTC
组件里面内联的样式,从外面怎么覆盖?
通过 props 传递进去合并上去吗?
08:55:40 UTC
实现的方式很简单,但是css不能分派给UI进行编写了。 样式复用部分也可以通过js依赖实现。
09:22:12 UTC
我好像理解错了,在material-ui里是要修改组件的style prop的:
09:57:21 UTC
实现用webpack直接require css 文件就行了,并且可以在打包的时候指定包在js文件里,包括小图片,一样可以转成base64打包,好处还是很多的,比如引入某个控件的时候,只要引入js文件就行了
11:17:34 UTC
scoped 的 CSS 实现就 Web Components 和 inline CSS 两种, 只能等实现.inline CSS 目前最可行, 但是也挺难的.. 看别人用的效果再开始.
03:59:18 UTC
感谢 @liusong1111 在 #21 话题讨论中提供facebook的这个slide:React: CSS in JS。
slide的前半部分,我没想到facebook能在错误的工程化道路上走那么远(这个可以理解为赞美)。我在前文中“局域化CSS”一节写道:“覆写和扩展class钩子或可类比为某种接口使用,但实际运行时并没有任何约束,我们也很难进行静态检查”。但是facebook居然做到了显式接口和静态分析。这完全来自于f家强大的工程能力,体现了f家前端架构师的牛X。不过可惜的是,即使做到这个地步,这条路仍然是走不通的,他们自己最后也意识到了。BTW,这也基本上可以视作对OOCSS、SMACSS、BEM等方法论宣判的死缓。
后半部分是他们的一个解决方法。
使用inline style
使用JS表达样式组合,从而利用所有JS的特性(如模块化)
放弃使用selector的specificity机制,而是在插入inline style时使用JS的调用顺序来明确override样式的优先级(在这个点上有极高的灵活性,是完胜传统class钩子的关键点)
老实说,我一点也不意外这样的方案,我甚至惊讶于从Bootstrap流行开始花了这么久才走到这一步。实际上我一直认为“样式为中心”的开发方式最终应该回归到inline style上。
但是,这样的方案是不是胜过了我一直推荐的CSS preprocessor的方案?我认为没有。
此slide列出的CSS的scale问题(即大规模开发时的可维护性问题,或者通称“工程化问题”)如下:
1. Global Namespace
2. Dependencies
3. Dead Code Elimination
4. Minification
5. Sharing Constants...
在这里的评论中有我的一些观点,不知道 题叶 更倾向于哪一种方案?
17:19:07 UTC
两周都不错, 观望, 看哪个成熟就跟进.
01:54:37 UTC
04:02:20 UTC
script type="template" id="register_form"&
&style&.dui-dialog .dui-dialog-shd{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;opacity:1;filter:alpha(opacity=100);background:0}.dui-dialog .hd{padding:0}.dui-dialog .bd{padding:0!margin:0!important}.dui-dialog .dui-dialog-content{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0;-webkit-box-shadow:0 0 10px rgba(0,0,0,0.2);-moz-box-shadow:0 0 10px rgba(0,0,0,0.2);box-shadow:0 0 10px rgba(0,0,0,0.2)}.dui-dialog .dui-dialog-close,.dui-dialog .dui-dialog-close:link,.dui-dialog .dui-dialog-close:visited,.dui-dialog .dui-dialog-close:hover,.dui-dialog .dui-dialog-close:active{color:#font-size:9px}#register_block{letter-spacing:-4height:400px}#legend{font-size:18color:#333;padding:0}form.register{width:285padding:40px 35px 0 37letter-spacing:0;float:left}form .spec{background-color:#eef1f0;margin-top:12padding:8px 10position:relative}form .spec label{margin-right:25px}#user_name{ime-mode:disabled}form .item{color:#666}form .item .text{border:0color:#333;background-color:#eef1f0;width:170position:left:63top:10px}form .item .tip{color:#888}form .item .text:focus{border:0outline:0}form .item label{float:none}form .item input{margin:0}form .recsubmit{clear:padding-top:30position:relative}form .recsubmit #btn-submit{display:background-color:#9dd6c5;width:110height:35line-height:35text-align:border:0color:#font-size:14float:cursor:outline:0}form .recsubmit #btn-submit:hover{background-color:#bae2d6;color:#5a5a5a}form .recsubmit .loading{background:url(/f/fm/c82b5ca7f9deb9e7a04f23c5a196e5/pics/ajax-loader.gif) no-repeat 0 0;width:16height:16position:top:40right:120display:none}.alternative{width:190height:400vertical-align:background-color:#5a5a5a;letter-spacing:0;float:color:#position:relative}.third-party-mod{position:left:25top:35width:160px}.third-party-mod ul{color:#c8f4e7;letter-spacing:-4margin-top:5height:19line-height:19px}.third-party-mod li{display:inline-vertical-align:*display:zoom:1;*vertical-align:margin-right:5letter-spacing:0;*margin-right:3*font-size:8px}.third-party-mod a{color:#c8f4e7;margin-right:5font-size:12*margin-right:3px}.third-party-mod a:link{color:#c8f4e7}.third-party-mod a:visited{color:#c8f4e7}.third-party-mod a:hover{text-decoration:background:0}.third-party-mod a:active{text-decoration:underline}div.captcha{width:130float:margin-right:5*margin-right:0}#register_block div.captcha label{margin-right:12px}#register_block div.captcha input.text{width:72px}img.captcha{margin-top:15cursor:pointer}.agreement{margin-top:9width:170float:*width:160px}.agreement a,.agreement a:link,.agreement a:hover{color:#5b9}.ending{background:url(/f/fm/a2c70cc1a6bebb2299d0/pics/fm/home/finish_signup.png) no-repeat center center}.login-mod{position:left:25width:160px}.login-mod{bottom:25px}.login-mod p{line-height:8color:#aaa}.login-mod a{border:1px solid #666;display:width:130height:30padding-left:10line-height:30font-size:14margin-top:10color:#cursor:pointer}.login-mod a:link{color:#fff}.login-mod a:visited{color:#fff}.login-mod a:hover{background-color:#666}.login-mod a:active{color:#fff}&/style&
&div id="register_block"&
douban就是在模板里面加载局部Css,这样模板可以以到处复用, 模板换到另一个地方,就不用复制整个css,或者分柴出模板用到的css
15:33:45 UTC
我想组件化的目标是,让开发人员能方便的组合组件进行开发,将css和html都包含在一起,让component变成一个黑盒,是一种非常有效的方式。而css in js是实现这中目标的手段之一,做到css with component才是最终目标。
目前我觉得组件和css揉合在一起最大的问题是对原始css的样式的重新定制问题,component是一个黑盒,不能像以前那样直接替换css文件就可以了。这里有两个问题,第一是原始css被嵌入了组件中,如果要重新定制css的话,那么就等于无用的css也包含在内第二是如何更好的支持的css重新定制,而不失可读性、可维护性
目前我还没有看到现有的方法可以解决我的问题。这应该需要对webpack打包工具动手脚来,或许还需要一套对组件规范才行。
inline style的方式,很可惜,写animation比较麻烦,这个package不错。
另外,我觉得scoped不是大问题,可以人为规避,也可以通过编译器解决。最后,我还是觉得import "xxx.less"是最好的选择,如何在 React 中运用 CSS_百度知道
如何在 React 中运用 CSS
提问者采纳
手机甚至是给视觉障碍的人用的声音设备:visited)。在需要全局 CSS 的时候。而今天,而是由一个一个Web组件组成的应用程序窗口,Web已经从相互连接的HTML变成了相互连接的 Web App,inline style 的作用自然就会被加强,只能通过 CSS 声明(className)来实现从传统 HTML 的观点来看,“内容”(HTML)和其渲染方式 (CSS)是可以分离的,因此很自然,来制定对应的 CSS Class,这样分隔就是合理的,Web Component 不得不带来了 Shadow DOM 的新概念。用户看到的已经不再是整个 HTML。Inline style也有一些限制。React Component是适应 Web App 化的。为了解决这个问题。此时,CSS的全局性带来的就不是方便,而可能是污染了。基于内容传播,例如声明伪类属性 (a,例如同样的文章可以被CSS渲染到不同的设备上,例如PC,你仍然可以通过为 React Component 设置 className 属性
来自团队:
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 reactjs 引用外部css 的文章

 

随机推荐