npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lime-painter-richtext

v1.0.3

Published

基于lime-painter海报画板制作的一个富文本解析器,使用HTML生成海报(支持度参考lime-painter,理论上uniapp均支持)

Downloads

10

Readme

基于lime-painter的富文本解析器(typescript) - uni-app

如何使用

安装

支持Uniapp Vue3,如果想用Vue2也是可行的(需要改变语法格式) ,可能还有些缺陷 您也可以修改源码进行改动

基于原作者:陌上华年 lime-painter,开发的扩展插件;使用前请记得插件市场先安装下载 lime-painter ;lime-painter-richtext 是基于 lime-painter 的富文本解析器

您也可以选择直接使用npm安装这个插件,npm安装的方式会更方便一些

npm install lime-painter-richtext

如果是下载这个插件,请将下载的压缩包文件解压以后 放入您自己的文件夹 注意导入路径

使用Vue3

<template>
    <view style="padding: 8px;">
        <l-painter :board="poster" ref="painter" @progress="getPosterProgress"/>
    </view>
</template>

<script lang="ts" setup>
    import { ref } from 'vue';

    // 导入lime-painter组件
    import LPainter from '@/uni_modules/lime-painter/components/l-painter/l-painter';
    // 从node_modules安装lime-painter-richtext插件,导入使用
    import HtmlParser from "lime-painter-richtext";

    const painter = ref<InstanceType<typeof LPainter> | null>(null);

    const htmlContent = `
      <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/static/index/logo.png" style="width:200rpx;height:200rpx;z-index:10;position:absolute" />
      <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/29_174321117967e74aab66586.png" style="object-fit:cover;object-position:50% 50%;width:750rpx;height:1200rpx;border-radius:12rpx" />
       <div style="display:flex;align-items:center;justify-content:space-between;background-color:#F9FCFF;padding:20rpx 32rpx;border-radius:40rpx 40rpx 0 0;position:fixed;bottom:0">
         <div style="display:flex;align-items:center;">
            <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/13_174186170967d2b34dbca24.png" style="width:160rpx;height:160rpx;border-radius:50%" />
            <div style="margin-left:20rpx;">
              <div style="font-size:32rpx;font-weight:bold">昵称</div>
              <div style="font-size:24rpx;color:#FF5310;margin-top:10rpx">邀请用户成为我的客户</div>
            </div>
         </div>
         <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/29_174321640667e75f166de46.png" style="width:120rpx;height:120rpx;border-radius:50%" />
       </div>
    `;

    // 海报数据
    const poster = ref({
        css: {
            backgroundColor: "#ffffff",
        },
        views: []
    });

    // 解析html
    const jsonResult = new HtmlParser().parseHtmlToJson(htmlContent);

    poster.value.views = jsonResult;

    // 获取海报生成进度
    const getPosterProgress = (progress: number) => {
        console.log('海报进度', progress);
    };

    // 生成图片
    const handleTask = () => {
        painter.value.canvasToTempFilePathSync({
            fileType: "jpg",
            // 如果返回的是base64是无法使用 saveImageToPhotosAlbum,需要设置 pathType为url
            pathType: 'url',
            quality: 1,
            success: (res) => {
                console.log(res.tempFilePath);
                // 非H5 保存到相册
                uni.saveImageToPhotosAlbum({
                    filePath: res.tempFilePath,
                    success: function () {
                        console.log('save success');
                    }
                });
            },
        });
    };
</script>

<style></style>

使用Vue2

<template>
    <view style="padding: 8px;">
        <l-painter :board="poster" ref="painter" @progress="getPosterProgress"/>
    </view>
</template>

<script>
  export default {
    data() {
        return {
            htmlContent: `
              <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/static/index/logo.png" style="width:200rpx;height:200rpx;z-index:10;position:absolute" />
              <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/29_174321117967e74aab66586.png" style="object-fit:cover;object-position:50% 50%;width:750rpx;height:1200rpx;border-radius:12rpx" />
               <div style="display:flex;align-items:center;justify-content:space-between;background-color:#F9FCFF;padding:20rpx 32rpx;border-radius:40rpx 40rpx 0 0;position:fixed;bottom:0">
                 <div style="display:flex;align-items:center;">
                    <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/13_174186170967d2b34dbca24.png" style="width:160rpx;height:160rpx;border-radius:50%" />
                    <div style="margin-left:20rpx;">
                      <div style="font-size:32rpx;font-weight:bold">昵称</div>
                      <div style="font-size:24rpx;color:#FF5310;margin-top:10rpx">邀请用户成为我的客户</div>
                    </div>
                 </div>
                 <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/29_174321640667e75f166de46.png" style="width:120rpx;height:120rpx;border-radius:50%" />
               </div>
            `,
            poster: {
                css: {
                    backgroundColor: "#ffffff",
                },
                views: []
            }
        }
    },
    mounted() {
        // 解析html
        const jsonResult = new HtmlParser().parseHtmlToJson(this.htmlContent);
        this.poster.views = jsonResult;
    },
    methods:{
        getPosterProgress(progress) {
            console.log('海报进度', progress);
        },
        handleTask() {
            this.$refs.painter.canvasToTempFilePathSync({
                fileType: "jpg",
                // 如果返回的是base64是无法使用 saveImageToPhotosAlbum,需要设置 pathType为url
                pathType: 'url',
                quality: 1,
                success: (res) => {
                    console.log(res.tempFilePath);
                    // 非H5 保存到相册
                    uni.saveImageToPhotosAlbum({
                        filePath: res.tempFilePath,
                        success: function () {
                            console.log('save success');
                        }
                    });
                },
            });
        }
    }
</script>

<style></style>

关于objectToString函数,这是将对象转为字符串的函数

这是一个将style样式对象转为字符串的处理函数,您也可以不用这个函数;lime-painter本身也支持object style不过好像会有点小问题

 <script lang="ts" setup>

const nicknameStyle = {
    fontSize: '32rpx',
    fontWeight: 'bold',
}

 const htmlContent = `
      <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/static/index/logo.png" style="width:200rpx;height:200rpx;z-index:10;position:absolute" />
      <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/29_174321117967e74aab66586.png" style="object-fit:cover;object-position:50% 50%;width:750rpx;height:1200rpx;border-radius:12rpx" />
       <div style="display:flex;align-items:center;justify-content:space-between;background-color:#F9FCFF;padding:20rpx 32rpx;border-radius:40rpx 40rpx 0 0;position:fixed;bottom:0">
         <div style="display:flex;align-items:center;">
            <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/13_174186170967d2b34dbca24.png" style="width:160rpx;height:160rpx;border-radius:50%" />
            <div style="margin-left:20rpx;">
              <div :style="nicknameStyle">昵称</div>
              <div style="font-size:24rpx;color:#FF5310;margin-top:10rpx">邀请用户成为我的客户</div>
            </div>
         </div>
         <img src="https://ljx-1301875625.cos.ap-shanghai.myqcloud.com/gxfangchan/202503/29_174321640667e75f166de46.png" style="width:120rpx;height:120rpx;border-radius:50%" />
       </div>
    `;
 </script>
/**
 * 获取一个值的类型字符串。
 * @param value 要检测的值。
 * @returns 返回值的类型。
 */
export const getType = (value : any) : string => {
    const temp = Object.prototype.toString.call(value);
    const type = temp.replace(/\[/g, "").replace(/\]/g, "");
    const index = type.lastIndexOf(" ");
    const str = type.substring(index + 1, type.length);
    return str;
};

/**
 * 判断一个值是否有效(即不为 undefined、null 或空字符串)。
 * @param val 要检查的值。
 * @returns 如果值有效,则返回 true;否则返回 false。
 */
export const isEffective = (val : any) : boolean => {
 return val !== undefined && val !== null && val !== "";
};

/**
 * 驼峰转小写-连接
 * @param {string} str 需要转换的字符串
 * @param {string} mark 转换符号,默认为 "-"
 * @return {string} 转换后的字符串
 * @example toLine('borderRadius')  // 返回 border-radius
 */
export const toLine = (str: string = "", mark: string = "-"): string => {
  return str.replace(/([A-Z])/g, `${mark}$1`).toLowerCase();
};

/**
 * 去掉字符串的空格
 * @param {string} str 需要处理的字符串
 * @param {string} pos 去除空格的位置:both: 左右两边空格,left: 左边空格,right: 右边空格,all: 所有空格
 * @return {string} 返回去除空格后的字符串
 */
export const trim = (str: string, pos: string = "both"): string => {
  str = String(isEffective(str) ? str : "");
  switch (pos) {
    case "both":
      return str.trim();
    case "left":
      return str.replace(/^\s*/, "");
    case "right":
      return str.replace(/(\s*$)/g, "");
    case "all":
      return str.replace(/\s+/g, "");
    default:
      return str;
  }
};

/**
 * object 转 css 字符串
 * @param styleList 样式对象或字符串数组
 * @return {string} 返回字符串 style,兼容其它端
 * @example objectToString('width:10rpx', { height: '20rpx', zIndex: 2 }, 'border:2rpx')
 * @returns 'width:10rpx;height:20rpx;z-index:2;border:2rpx'
 */
export const objectToString = (...styleList : (string | Record<string, string | number>)[]) : string => {
    const styleObj : Record<string, string> = {};

    const addStyle = (name : string, value : string | number) => {
        name = trim(name);
        if (['String', 'Number'].includes(getType(value))) {
            value = trim(String(value));
            if (name && value) {
                styleObj[toLine(name)] = value;
            }
        }
    };

    styleList.forEach((style) => {
        const type = getType(style);
        if (type === 'String' && style) {
            const trimmedStyle = trim(style as string);
            if (trimmedStyle) {
                trimmedStyle
                    .replace(/^;+|;+$/, '')
                    .split(/;+/)
                    .map((str) => str.split(/:+/))
                    .forEach(([k, value]) => addStyle(k, value));
            }
        } else if (type === 'Object') {
            Object.entries(style as Record<string, string | number>).forEach(([k, v]) => addStyle(k, v));
        }
    });

    return Object.entries(styleObj)
        .map(([k, v]) => `${k}:${v}`)
        .join(';');
};