• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

为什么在vuestyle-components没有火起来

武飞扬头像
三原
帮助1

为什么在vue中style-components没有火起来?

再刚使用reactstyled-components的时候,我是震惊的,震惊的不是该组件有多好用,震惊的是``模板字符串语法竟然可以这么用。 我当时还质疑说,都是阮一峰的《ES6标准入门》中没有说这个语法的锅,我都看了好几篇了指定没有,没发现啊, 最后回家再翻开真的是啪啪打脸。咱们一起回顾下这个模板字符串中的标签语法

它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为标签模板功能(tagged template)。如下:

示例一:

alert`hello`
// 等同于
alert(['hello'])

示例二:
如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数

let a = 5;
let b = 10;
tag`Hello ${ a   b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);

function tag(stringArr, ...values) {
  // ...
}

这么看是不是就比较清晰了,大致就是立即调用该方法(alert示例一),然后把模板语法再没变量的时候整体作为数组字符串传进该方法(alert示例一)。 存在变量的情况下立即调用该方法(tag示例二),会以变量为切割第一个数组是切割后的多搁字符串,切割出来的变量依次当作参数传进该方法中(tag示例二)。

在react 中使用styled-components

简单输出下styled-componentsreact中的用法

示例一:(使用html标签当作组件使用)

import styled from 'styled-components'

// div 标签
const Container = styled.div` 
 display: flex;
 justify-content: space-between;
`;

// span 标签
const CustomSpan = styled.span`
 color: red;
`;

export const Header = () => { 
  return (
    <Container>
      <CustomSpan>text</CustomSpan>
    </Container>
  ) 
}

示例二:(还可以对子元素经行样式修改)

import styled from 'styled-components'

// div 标签
const Container = styled.div` 
 display: flex;
 justify-content: space-between;

 > span {
   color: red;
 }
 ...
`;
export const Header = () => { 
  return (
    <Container>
      <span>text</span>
    </Container>
  ) 
}

示例三:(使用变量)这里是可以使用props 传进来的

const Container = styled.div`
  height: 60px;
  display: flex;
  margin: 8px 8px 0;
  justify-content: space-between;
  background-color: ${(p) => p.titleBackground};
  border-bottom: 1px solid ${(p) => p.borderColor};
`

export const Header = () => { 
  return (
    <Container borderColor="#fff" titleBackground="red">
      <span>text</span>
    </Container>
  ) 
}

使用ts的情况下可以使用泛型约束如下:

const Container = styled.div<{
  borderColor: string;
  titleBackground: string;
}>
`
  height: 60px;
  display: flex;
  margin: 8px 8px 0;
  justify-content: space-between;
  background-color: ${(p) => p.titleBackground};
  border-bottom: 1px solid ${(p) => p.borderColor};
`

export const Header = () => { 
  return (
    <Container borderColor="#fff" titleBackground="red">
      <span>text</span>
    </Container>
  ) 
}

示例四:可以使用传参判断是否需要该样式使用css``方法得到值

import styled, { css } from 'styled-components'

const Button = styled.button<{ $primary?: boolean; }>`
  background: transparent;
  border-radius: 3px;
  border: 2px solid #BF4F74;
  color: #BF4F74;
  margin: 0.5em 1em;
  padding: 0.25em 1em;

  ${props => props.$primary && css`
    background: #BF4F74;
    color: white;
  `}
`;

const Container = styled.div`
  text-align: center;
`

render(
  <Container>
    <Button>Normal Button</Button>
    <Button $primary>Primary Button</Button>
  </Container>
);

styled-componentsreact开发中解决了以下几个问题:

  1. 组件化的样式管理:使用 styled-components,样式与组件紧密集成在一起,每个组件都可以拥有自己的独立样式。这种方式使得开发者可以更轻松地维护和重用样式,而无需关心全局 CSS 类名的命名冲突和样式覆盖的问题。

  2. 动态和响应式样式:styled-components 提供了一种方便的方式来根据组件的状态、属性或上下文动态生成样式。

  3. CSS-in-JS 的好处:styled-components 将 CSS 和组件逻辑紧密结合在一起,将样式定义直接编写在组件代码中。这种方式提供了更强的可读性和可维护性,同时也允许开发者利用 JavaScript 的能力来进行条件渲染和复杂样式逻辑的处理。

  4. 自动前缀和全局样式隔离:styled-components 内置了自动前缀功能,根据浏览器要求自动生成所需的 CSS 前缀。此外,由于其采用了全局样式隔离的方式,避免了全局 CSS 污染和样式冲突的问题。

  5. 更好的开发者体验:styled-components 提供了直观、简洁的 API,使得编写和管理样式变得更加容易和愉快。它还通过标签模板字符串的方式提供了丰富的语法糖,使样式的编写更具可读性和可扩展性。

reactstyled-components实现原理

这个styled-components是怎么实现让返回值像组件一样使用呢?我就看源码找资料如下:

简单重构下styled-components:

const StyledExt = (TargetComponent, style) => class extends React.Component {
  componentDidMount() {
    this.element.setAttribute('style', style);
  }

  render() {
    return (
      <TargetComponent {...this.props} ref={element => this.element = element } />
    );
  }
};

let Styled = (TargetComponent) => ([style]) => StyledExt(TargetComponent, style);
styled.button = ([style]) => StyledExt('button', style);

const Button1 = Styled('button')`
  color: red;
`;
const Button2 = Styled.button`
  color: red;
`;
const StyledExt = (TargetComponent, strs, args) => class extends React.Component {
  initStyle() {
    const style = args.reduce((pre, cur, index) => {
      const isFunc = typeof cur === 'function'; // 判断是不是函数
      const value = isFunc ? cur(this.props) : cur;
      return pre   value   strs[index   1];
    }, strs[0]);

    this.element.setAttribute('style', style);
  }

  componentDidMount() {
    this.initStyle();
  }

  componentDidUpdate() {
    this.initStyle();
  }

  render() {
    return (
      <TargetComponent {...this.props} ref={element => this.element = element } />
    );
  }
};

let Styled = (TargetComponent) => (strs, ...args) => StyledExt(TargetComponent, strs, args);
styled.button = (strs, ...args) => StyledExt('button', strs, args);

const Button1 = Styled('button')`
  color: ${(p) => p.color};
`;
const Button2 = Styled.button`
  color: ${(p) => p.color};
`;

以上可以作为styled-components的实现核心, 方便理解。

vue中使用styled-components

其实在看完reactstyled-components后,我就在想怎么能让vue也能用的上这个组件呢? 下班再地铁上想了一路也没想到要怎么实现,哈哈。 我就再网上查了下发现已经有vue-styled-components ,star:1.3k。 那么咱们下面看下再vue中是怎么实现的呢?

我直接把官方代码拿来了,熟悉vue语法的应该也一眼就能看懂了如下:

  const createStyledComponent = (target, rules, props, options) => {
    const {
      attrs = []
    } = options
    const componentStyle = new ComponentStyle(rules)

    // handle array-declaration props
    const currentProps = normalizeProps(props)
    const prevProps = normalizeProps(target.props)

    const StyledComponent = {
      inject: {
        $theme: {
          default: function () {
            return () => ({ })
          }
        }
      },
      props: {
        as: [String, Object],
        value: null,
        ...currentProps,
        ...prevProps
      },
      data () {
        return {
          localValue: this.value
        }
      },
      render (createElement) {
        const children = []
        for (const slot in this.$slots) {
          if (slot === 'default') {
            children.push(this.$slots[slot])
          } else {
            children.push(createElement('template', { slot }, this.$slots[slot]))
          }
        }

        return createElement(
          // Check if target is StyledComponent to preserve inner component styles for composition
          isVueComponent(target) ? target : this.$props.as || target,
          {
            class: [this.generatedClassName],
            props: this.$props,
            domProps: {
              ...this.attrs,
              value: this.localValue
            },
            on: {
              ...this.$listeners,
              input: event => {
                if (event && event.target) {
                  this.localValue = event.target.value
                }
              }
            },
            scopedSlots: this.$scopedSlots
          },
          children
        )
      },
      methods: {
        generateAndInjectStyles (componentProps) {
          return componentStyle.generateAndInjectStyles(componentProps)
        }
      },
      computed: {
        generatedClassName () {
          const { context, attrs } = this
          const componentProps = { ...context, ...attrs }
          return this.generateAndInjectStyles(componentProps)
        },
        theme () {
          return this.$theme()
        },
        context () {
          return {
            theme: this.theme,
            ...this.$props
          }
        },
        attrs () {
          const resolvedAttrs = {}
          const { context } = this

          attrs.forEach((attrDef) => {
            let resolvedAttrDef = attrDef

            if (typeof resolvedAttrDef === 'function') {
              resolvedAttrDef = resolvedAttrDef(context)
            }

            for (const key in resolvedAttrDef) {
              context[key] = resolvedAttrs[key] = resolvedAttrDef[key]
            }
          })

          return resolvedAttrs
        }
      },
      watch: {
        value (newValue) {
          this.localValue = newValue
        },
        localValue () {
          this.$emit('input', this.localValue)
        }
      },
      extend (cssRules, ...interpolations) {
        const extendedRules = css(cssRules, ...interpolations)
        return createStyledComponent(target, rules.concat(extendedRules), props, options)
      },
      withComponent (newTarget) {
        return createStyledComponent(newTarget, rules, props, options)
      }
    }

    return StyledComponent
  }

大致就是利用vue render语法返回一个vue的模板对象。当然实现起来还有好多细节需要考虑,咱们就了解到基础实现就可以了。

为什么在vue中style-components没有火起来

其实咱们可以从style-componentsreact解决了什么问题的角度去考虑我觉得最大的有点就是样式隔离,但是vue中是支持使用<style scoped></style> scoped关键字做样式隔离的。

像动态样式也可以使用以下方式解决

<template>
  <div :style="computedStyle">123</div>
</template>

<script>
export default {
  name: 'Test',

  data() {
    return {
      color: '#fff',
    };
  },

  computed: {
    computedStyle() {
      return `background: ${this.color}`
    },
  },
}
</script>

还有像vue3语法支持v-bind()语法后感觉就更用不上style-components了,如下:

<script setup>
const theme = {
  color: 'red'
}
</script>

<template>
  <p>hello</p>
</template>

<style scoped>
p {
  color: v-bind('theme.color');
}
</style>

其实style-components我看网上也有说其性能等问题,我觉得就是还是按需要决定要不要使用吧,他确实解决了很多问题是个很好的东西不可否认,假如你对界面性能有极致的需求可以放弃使用,正常的功能还是应用下更方便。

结语

style-componentsCss In JS的思想应该通过以上学习有了一定的了解,你还能从别的方面分析**为什么在vue中style-components没有火起来?**可以在评论区留言,如果对您有帮助欢迎点赞收藏。

参考文章;

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgajbjg
系列文章
更多 icon
同类精品
更多 icon
继续加载