在使用easyv组件开发工具开发react组件的时候,有时我们需要用伪元素和伪类来达到一些效果,比如:hover,::after等,但是这些css代码只能写在css文件中,不能在js代码中直接编写,没办法动态修改样式。下面我会介绍几种比较原始的方法,让开发者在不使用第三方库的情况下来动态修改伪元素和伪类的样式。
先看以下代码:
index.jsx:
import css from './styles/index.module.css';
export default function (props) {
const { left, top, width, height, id, configuration } = props;
const { hoverColor, afterContent } = configuration;
const styles={
position:"absolute",
left, top, width, height
}
return (
<div className="__easyv-component" style={styles} id={id}>
<div className={css.test}>按我</div>
</div>
)
}
main.json:
{
"base": {
"name": "测试",
"module_name": "test",
"version": "1.0.0",
"show": 1
},
"width": 200,
"height": 70,
"configuration": [
{
"name":"hoverColor",
"displayName":"悬浮色",
"type":"color",
"value":"red"
},
{
"name":"afterContent",
"displayName":"伪元素文本",
"type":"input",
"value":"text"
}
]
}
index.module.css:
.test{
width:100px;
height:60px;
background:blue;
}
这里我们创建了一个简单的函数式组件,hoverColor对应悬浮时的组件背景色,afterContent对应组件的伪元素 ::after 的内容,可以看到,我们的css文件也非常简单,只是给test类的元素赋予了一定的宽高和背景色。
那么接下来,如果我们要给test添加一个hover样式,正常来讲,我们会在css文件中这样写:
.test:hover{
background:red;
}
.test:hover{
background:var(--color);
}
import css from './styles/index.module.css';
export default function (props) {
const { left, top, width, height, id, configuration } = props;
const { hoverColor, afterContent } = configuration;
const styles={
position:"absolute",
left, top, width, height
}
//btnStyle不一定非得给className=test的元素,给className=__easyv-component的元素也有效
const btnStyle={
"--color":hoverColor //此处根据配置项中的hoverColor来给--color赋值,达到动态修改--color的效果
}
return (
<div className="__easyv-component" style={styles} id={id}>
<div className={css.test} style={btnStyle}>按我</div>
</div>
)
}
.test::before{
content:attr(data-txt);
position:absolute;
right:0;
width:60px;
height:60px;
background: var(--color);
}
index.jsx:
import css from './styles/index.module.css';
export default function (props) {
const { left, top, width, height, id, configuration } = props;
const { hoverColor, afterContent } = configuration;
const styles={
position:"absolute",
left, top, width, height
}
//btnStyle不一定非得给className=test的元素,给className=__easyv-component的元素也有效
const btnStyle={
"--color":hoverColor //此处根据配置项中的hoverColor来给--color赋值,达到动态修改--color的效果
}
return (
<div className="__easyv-component" style={styles} id={id}>
{/* 这里给test添加一个自定义的属性data-txt,它的值由afterContent修改,
css里会获取到data-txt属性的值并赋予content */}
<div className={css.test} data-txt={afterContent} style={btnStyle}>按我</div>
</div>
)
}
在html页面中,<style>标签内可以书写css代码,这也意味着如果我们可以动态创建style标签,也就能动态创建伪元素和伪类。只要做好<style>标签的管理,避免样式覆盖或内存泄漏等问题,就可以用这个方法来解决任何js动态控制css样式的问题。我们可以通过以下几个步骤来动态生成style标签:
1.使用document.createElement("style")来创建style标签,这里需要先验证一下,是否已创建过style标签,如果已创建过了,就不必二次创建了。
2.将创建好的style标签插入到<head>标签中,使其生效,同时将style标签绑定到react的ref上,这样后续可以通过ref来修改style标签的内容,也能通过ref来判断是否已创建过style标签。
3.通过修改style标签的innerHTML的值来动态生成样式,这里我们可以利用模板字符串,书写css样式和插入js变量会更方便。
4.在组件卸载时,需要将生成的style标签移出dom,避免内存泄漏。
下面是示例代码,运行后和方法一的效果是一样的。
import React,{useEffect, useRef} from "react";
export default function(props) {
const { left, top, width, height, id, configuration } = props;
const { hoverColor, afterContent } = configuration;
const styles={
position:"absolute",
left, top, width, height
}
const styleRef = useRef(); //这个ref用于绑定style标签的dom实例
//这个useEffect用于监听配置项,当配置项变化时,需要动态修改style标签的innerHTML
useEffect(()=>{
//先对styleRef进行判断,如果styleRef未绑定style标签,则需要生成一个新的style标签并绑定
if(!styleRef.current){
let styleDom = document.createElement("style");
document.head.appendChild(styleDom);
styleRef.current = styleDom;
}
//这一步动态生成css样式,部分不需要动态生成的样式其实可以写到css文件里,比如下面的.test
//这里我偷懒了,直接写一块儿了。
styleRef.current.innerHTML=`
.test{
width:100px;
height:60px;
background:blue;
}
.test:hover{
background:${hoverColor};
}
.test::before{
content:"${afterContent}";
position:absolute;
right:0;
width:60px;
height:60px;
background: ${hoverColor};
}
`;
},[hoverColor, afterContent]);
//这个useEffect用于将style标签从dom中移除。避免内存泄漏
useEffect(()=>{
return ()=>{
if(styleRef.current){
styleRef.current.remove();
}
}
},[]);
return (
<div className="__easyv-component" style={styles} id={id}>
<div className="test">按我</div>
</div>
)
}
方法二其实是有弊端的,我们都知道useEffect是异步执行的,这意味着如果线程被阻塞了,style标签将无法被及时插入,样式的修改会很慢。所以我们可能会更期望样式的变化在dom变化之前完成,而react官方给出的解决方案就是useInsertionEffect这个hook,它的用法和useEffect类似,但执行时机是在dom变化之前(比useLayoutEffect的时机更加靠前,useLayoutEffect是在dom变化之后,组件渲染之前),所以用它来插入style标签可以避免阻塞问题。不过这个属于react18新特性,有兴趣的同学可以自行了解。
以上三种方法个人还是比较推荐第一种,没有太多风险和性能浪费,其次是第三种,不过需要用到react18,如果是旧版本的react的话,还是用第二种好了,不过不是特别推荐,毕竟频繁的修改style标签内容,也是一种性能的浪费。
文章
3.2K人气
8粉丝
1关注
©Copyrights 2016-2022 杭州易知微科技有限公司 浙ICP备2021017017号-3 浙公网安备33011002011932号
互联网信息服务业务 合字B2-20220090