PosterRender 实现微信下程序 分享商品生成海报

发布于:2025-03-15 ⋅ 阅读:(10) ⋅ 点赞:(0)

PosterRender 是什么

PosterRender 是一种专注于生成高质量海报图像的技术或工具,常用于生成静态图片,特别是适合用于营销、宣传和展示的图形设计。它通常用于在服务端或客户端渲染复杂的图像,包括文字、图形、图标、背景等,生成可供下载或直接使用的最终图片格式(如 PNG 或 JPEG)。

PosterRender 用来做什么

  • 营销海报生成:
    用于快速生成电商平台的商品促销海报、活动宣传海报等。
  • 用户内容分享:
    在社交媒体上分享的内容卡片、个人成就海报(如运动记录、学习记录等)。
  • 模版化设计:
    通过可配置的模板,快速生成批量的海报,适合规模化需求。
  • 动态内容渲染:
    根据用户数据动态生成个性化的海报,如公众号文章分享页、个人二维码推广图等。

PosterRender 的优点

  • 高效性:
    能快速生成高质量的图像,特别适合批量任务。
  • 灵活性:
    支持高度定制化设计,可以通过模板调整文字、颜色、布局等细节。
  • 跨平台支持:
    可以在服务端或客户端完成渲染,适合多种技术栈(如 Node.js、Python、前端浏览器)。
  • 自动化:
    可结合动态数据生成个性化内容,减少人工设计成本。
  • 高质量输出:
    支持高清图片输出,满足打印与显示需求。

PosterRender 的缺点

  • 复杂性:
    对于初学者来说,模板配置与设计可能存在一定学习成本。
  • 性能依赖:
    如果在服务端渲染,生成大量高分辨率图片可能消耗较多的计算资源;如果在客户端渲染,可能受限于设备性能。
  • 开发成本:
    自定义模板和动态渲染的实现需要一定的开发工作量。
  • 实时性限制:
    对于需要实时生成大量图片的场景(如高并发访问),可能需要额外优化或使用缓存机制。

PosterRender实例

  • 实例是结合taro+react 实现微信小程序分享商品
  • 通过样式增加遮照,设置z-index 浮在页面上
  • PosterRender list进行x,y轴坐标布局
  // 父组件代码
  import type { QrcodeRenderRef } from '@/components/Qrcode/QrcodeRender';
  import QrcodeRender from '@/components/Qrcode/QrcodeRender';

  const ref = useRef<QrcodeRenderRef>(null);
  <QrcodeRender ref={ref} />
// 子组件代码
import type { ForwardRefRenderFunction } from 'react';
import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';
import type { PosterRenderRef } from '@poster-render/taro-react';
import { PosterRender } from '@poster-render/taro-react';
import { View } from '@tarojs/components';
import Taro, { pxTransform } from '@tarojs/taro';
import classNames from 'classnames';

import { getRoutineCode } from '@/services/promotion';

import styles from './styles.modules.less';
//设置海报的宽度和高度
const SIZE = {
  width: 315,
  height: 365
};

export interface QrcodeRenderRef {
  // 子组件暴露给父组件的方法
  open: () => Promise<void>;
}

const QrcodeRender: ForwardRefRenderFunction<QrcodeRenderRef> = (_, ref) => {
  const posterRender = useRef<PosterRenderRef>(null);
  // const [qrcode, setQrcode] = useState('');
  const [rendered, setRendered] = useState(false);
  const [visible, setVisible] = useState(false);
  const [data, setData] = useState<Promotion.CodeInfo>();

  // 请求接口 获取要渲染的数据
  const handleShow = useCallback(async () => {
    Taro.showToast({
      title: '正在生成',
      icon: 'loading',
      mask: true
    });
    const res = await getRoutineCode();
    if (res?.status !== 200) {
      Taro.showToast({
        title: '生成失败,请重试',
        icon: 'none'
      });
      return;
    }

    setData(res?.data);
    setVisible(true);
  }, []);

  useImperativeHandle(
    ref,
    () => ({
      open: async () => {
        handleShow().then().catch();
      }
    }),
    [handleShow]
  );

  const onRender = useCallback(async () => {
    Taro.hideLoading();
    setRendered(true);
  }, []);

  const handleHide = useCallback(async () => {
    setVisible(false);
    setRendered(false);
  }, []);

  const handleSave = useCallback(() => {
    posterRender.current?.savePosterToPhoto();
  }, []);

  return (
    <>
      <View
        catchMove
        className={classNames({
          [styles.qrcodeWrap]: true,
          [styles.qrcodeWrapShow]: rendered
        })}
      >
        <View className={styles.masker} onClick={handleHide} />
        <View className={styles.container}>
          <View className={styles.containerBox}>
            {visible && (
              <PosterRender
                disableRerender
                ref={posterRender}
                canvasId="taro-poster-render"
                renderType="image"
                canvasWidth={SIZE.width}
                canvasHeight={SIZE.height}
                debug={false}
                style={{
                  width: pxTransform(SIZE.width),
                  height: pxTransform(SIZE.height)
                }}
                showMenuByLongpress
                onRender={onRender}
                onLongTap={handleSave}
                onRenderFail={(err) => console.error('onRenderFail', err?.message)}
                onSave={(url) => {
                  console.warn('onSave', url);
                  Taro.showToast({
                    title: '保存成功',
                    icon: 'none',
                    duration: 2000
                  });
                }}
                onSaveFail={(err) => console.error('onSaveFail', err?.message)}
                list={[
                  {
                    type: 'rect',
                    x: 0,
                    y: 0,
                    width: SIZE.width,
                    height: SIZE.height,
                    backgroundColor: '#fff',
                    borderWidth: 7,
                    radius: 16,
                    borderColor: '#00C8C8'
                  },
                  {
                    type: 'image',
                    width: 240,
                    height: 240,
                    backgroundColor: '#333333',
                    src: `${data?.url}`,
                    x: 37,
                    y: 47,
                    radius: 120,
                    mode: 'cover'
                  },
                  {
                    type: 'text',
                    x: (tw) => (SIZE.width - tw) * 0.5,
                    y: 310,
                    text: '长按识别或扫描二维码识别',
                    fontSize: 14,
                    color: '#999999',
                    width: (tw) => tw,
                    height: 19,
                    lineHeight: 19
                  }
                ]}
              />
            )}
            <View className={styles.desc}>扫描该二维码与您绑定推广关系</View>
            <View onClick={handleSave} className={styles.close}>
              保存图片
            </View>
          </View>
        </View>
      </View>
    </>
  );
};

export default forwardRef(QrcodeRender);
// styles.modules.css 代码
}
.qrcodeWrap {
  position: fixed;
  top: -100%;
  left: -200%;
  z-index: -1;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.qrcodeWrapShow {
  top: 0;
  left: 0;
  z-index: 9999999999;
}
.masker {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
}
.container {
  width: 100vw;
  height: 100vh;
}

.containerBox {
  position: relative;
  top: 50%;
  width: 315px;
  //height: 503px;
  margin: 0 auto;
  transform: translateY(-50%);
}

.desc {
  margin-top: 35px;
  color: #fff;
  font-weight: 400;
  font-size: 14px;
  font-style: normal;
  line-height: normal;
  text-align: center;
}

.close {
  position: absolute;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 249px;
  height: 40px;
  margin-top: 30px;
  color: #fff;
  font-weight: 500;
  font-size: 18px;
  background-color: @primary-color;
  border-radius: 249px * 0.5;
  transform: translateX(-50%);
}


实例图片

在这里插入图片描述