浅析React动态class类样式绑定方案:classnames库的使用以及如何不使用classnames库的方案

一、classnames库的使用

  React 原生动态添加多个className会报错:

import style from './style.css'
<div className={style.class1 style.class2}</div>

  想要得到最终渲染的效果是:

<div class='class1 class2'></div>

  引入classnames库:

// 1、安装:
npm install classnames --save

// 2、使用:
import classnames from 'classnames'
<div className=classnames({
  'class1': true,
  'class2': true
)>
</div>

  可以将后面的true省略,但这种我认为是比较直观的,可以对传入的class进行比较明显的动态判断

// 其他用法
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
 
// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
 
// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
// 也可以传入数组对象:
var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'

// 可以传入动态class
let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });

  在 React 中可以直接在classname内部传入动态class并进行条件判断

// 不使用classnames时的书写方式:
    var Button = React.createClass({
      // ...
      render () {
        var btnClass = 'btn';
        if (this.state.isPressed) btnClass += ' btn-pressed';
        else if (this.state.isHovered) btnClass += ' btn-over';
        return <button className={btnClass}>{this.props.label}</button>;
      }
    });
// 使用了之后可以简化:
    var classNames = require('classnames');
    var Button = React.createClass({
      // ...
      render () {
        var btnClass = classNames({
          btn: true,
          'btn-pressed': this.state.isPressed,
          'btn-over': !this.state.isPressed && this.state.isHovered
        });
        return <button className={btnClass}>{this.props.label}</button>;
      }
    });

二、不需要 classnames 这个库

  项目许多库都不是必要的, 我们一个个移除, 今天先移除 classnames

1、使用 classNames 的情况

import classNames from 'classnames';

export default ()=> {
  // className 的值: 'dog cat'
  return <div className={classNames('dog', {'cat':true, 'fish':false})} />
}

2、如果不使用classNames,根据条件组合样式

export default ()=> {
  // className 的值: 'dog cat'
  return <div className={['dog', true && 'cat', false && 'fish'].filter(Boolean).join(' ')} />
}

3、方案1:仅使用字符串。这个方案的缺点是不够直观, 但是它的总长度更短

export default ()=> {
  // className 的值: 'dog cat false'
  return <div className={`dog ${true && 'cat'} ${false && 'fish'}`} />
}

  我们保留最后输出的 false 字符串, 为了减少浏览器查找 flase 样式的时间, 声明一个空的 .false css样式

// css
.false {}

4、方案2:自己简单封装

function names(obj) {
  let className = ''
  for(const k in obj) {
    className += obj[k] || ''
  }
  return className;
}

export default ()=> {
  // className 的值: 'dog cat'
  return <div className={names({dog: 1, cat: 0, fish: 1})} />
}

5、对比:classnames 的写法多样,可读性跟 vue 的 :class 绑定比较类似了。本文主要是给了一个观点:用一个语法能解决的问题不需要引入一个库。

posted @ 2017-06-21 23:25  古兰精  阅读(1407)  评论(0编辑  收藏  举报