当前位置: 首页 > news >正文

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

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%);
}


实例图片

在这里插入图片描述

相关文章:

  • STM32Cubemx-H7-8-维特科技WT61C-TTL陀螺仪获取XYZ角度
  • 抽象工厂模式的C++实现示例
  • 23天 - 线程和进程有什么区别?进程之间的通信方式有哪些?进程的调度算法你知道吗?
  • uv pip install -r requirements.txt-报错,python版本过低
  • 大数据学习(67)- Flume、Sqoop、Kafka、DataX对比
  • 合并pull request的过程
  • 用户模块——握手验证
  • 解决 Linux /dev/mapper/ubuntu--vg-ubuntu--lv 磁盘空间不足的问题
  • Navicat安装流程
  • Linux 命名管道
  • 【AI】技术人如何系统学习AI大模型应用开发?
  • 2025高频面试算法总结篇【持续更新中】
  • 2025年1月-3月Java面试题、笔记、简历模版汇总(需要自取)
  • Linux--操作系统/进程
  • highlight.js
  • 基于微信小程序开发的宠物领养平台——代码解读
  • DataX的python3使用
  • Android Dagger 2 框架的注解模块源码分析(一)
  • 【QT】-解析打包json
  • Java 8 + Tomcat 9.0.102 的稳定环境搭建方案,适用于生产环境
  • 中央结算公司:减免境外央行类机构账户开户费用
  • A股高开高走:沪指涨0.82%,创指涨2.63%,超4100股收涨
  • 这座古村,藏着多少赣韵风华
  • 巴基斯坦外长:近期军事回应是自卫措施
  • 咸宁市委常委、市纪委书记官书云调任湖北省司法厅副厅长
  • 新疆维吾尔自治区乌鲁木齐市米东区政协原副主席朱文智被查