使用jsx代替html字符

151 阅读1分钟

简介

  • echarts的formatter函数中如果要自定义渲染样式只有写html字符进去,非常恶心,极其不方便。

  • 所以使用jsx的开发形式代替这种字符形式就会好很多

  • 这里引入的Text 是虚拟dom的dom类型(文本类型--如下图所示),还有文档片段、注释等等类型。

image.png

  • 这里使用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 };

image.png

验证效果

  <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>

image.png

还有待完善的地方,欢迎大家指正!