简介
-
echarts的formatter函数中如果要自定义渲染样式只有写html字符进去,非常恶心,极其不方便。
-
所以使用jsx的开发形式代替这种字符形式就会好很多
-
这里引入的
Text是虚拟dom的dom类型(文本类型--如下图所示),还有文档片段、注释等等类型。
- 这里使用
nameSpace是因为:只能使用全局样式,为了避免命名冲突,事件函数也一样,只能挂载到window上面,为了避免命名冲突。 - 需要使用到
sass
定义bem.scss
@use "sass:string";
@use "sass:list";
@mixin b($namespace, $block) {
$B: $namespace + $block; //局部变量
//插值语法#{}
.#{$B} {
@content; //内容替换
}
}
@mixin e($element) {
$a:list.nth(string.split(#{&},"_"), 1);
$b:$a+'_'+$element;
@at-root #{$b} {
@content;
}
}
- 定义jsx所使用的样式文件
test.module.scss - 将定义的
.scss文件在App.vue或者main.js中引入,作为全局样式
$name: test_;//命名空间必须以 "_" 结束
:export {
nameStr: $name;//必须导出 供函数命名处使用
}
//混入使用示例
@include b($name, box) { -->test_box
font-size: 12px;
text-align: left;
@include e(erBox) {-->test_erBox
font-weight: bold;
display: flex;
align-items: center;
@include e(item) {-->test_item
display: flex;
align-items: center;
}
@include e(title) {-->test_title
margin-left: 4px;
}
@include e(val) {-->test_val
color:#0D867F;
}
}
}
主要代码
import { Text } from "vue";
const isArray = (tar: any) => tar instanceof Array;
export class jsxToString {
nameSpace: string;
constructor(nameSpace: string) {
this.nameSpace = nameSpace;
}
toString(jsx: any) {
const curType = jsx?.type;
if (curType !== Text) {
let str = "";
if (typeof jsx === "string") return jsx;
if (jsx.children && jsx.children.length > 0) {
str = this.createChildren(jsx.children);
}
return this.appendEl(curType, str, jsx.props);
}
return jsx.children;
}
/**
* @description: 处理子节点
* @param {any} children 所有子节点
* @return {*}
*/
createChildren(children: any) {
let str = "";
for (let i = 0; i < children.length; i++) {
// 如果子节点是使用循环方式渲染,那么该节点又是一个数组
if (isArray(children[i])) str = this.createChildren(children[i]);
else if (children[i]) str += "\n" + this.toString(children[i]);
}
return str;
}
/**
* @description: 创建标签字符
* @param {string} type 标签类型
* @param {string} tar 标签中间的值
* @param {any} Attr 标签的属性
* @return {*} 标签字符
*/
appendEl(type: string, tar: string, Attr: any) {
let atr = "";
let temp = "";
Attr &&
Object.keys(Attr).forEach(key => {
let curKey = key.toLocaleLowerCase(); //作为写入attrubuite的key,不作为取值所用的key
if (typeof Attr[key] === "function") {
(window as any)[`${this.nameSpace}${Attr[key].name}`] = Attr[key];
temp = `${curKey}="${this.nameSpace}${Attr[key].name}()" `;
} else temp = `${curKey}="${key === "class" ? this.nameSpace + Attr[key] : Attr[key]}"`;
atr += ` ${temp}`;
});
return `<${type} ${atr.trim()}>${tar}</${type}>`;
}
}
使用示例
import styleSass from "./test.module.scss";
import { jsxToString } from "./useJsxToString";
const click = () => {
console.log("click");
};
const data = [
{
name:'张三'
},
{
name:'李四'
},
{
name:'王五'
}
]
const a = (
<div class="box">
{
data.map(item=><div>{item.name}</div>)
}
<div>mimi</div>
</div>
);
console.log(a);
const instance = new jsxToString(styleSass.nameStr)
const res =instance.toString(a)
console.log(res,'res')
export { res };
验证效果
<div id="box">
12231231
<div ref="testRef"></div>
</div>
</template>
<script setup lang="ts">
import { ref ,onMounted} from "vue"
const testRef = ref()
onMounted(() => {
testRef.value.innerHTML = res
})
</script>
还有待完善的地方,欢迎大家指正!