uniapp开发微信小程序使用takeSnapshot截图保存分享

截图功能实现

核心技术说明

takeSnapshot 是微信官方提供的截图 API,用于截取当前页面中指定元素的内容。

重要提醒:

  • 微信小程序默认使用 WebView 渲染模式
  • takeSnapshot 只在 Skyline 渲染模式 下生效
  • 需要手动配置 Skyline 渲染引擎才能使用此功能

📖 参考文档 : takeSnapshot API 文档

配置步骤

1. 启用 Skyline 渲染引擎

manifest.json"mp-weixin" 配置中添加:

json 复制代码
{
  "mp-weixin": {
    "rendererOptions": {
      "skyline": {
        "defaultDisplayBlock": true,
        "disableABTest": true,
        "sdkVersionBegin": "3.0.1",
        "sdkVersionEnd": "15.255.255"
      }
    },
    "style": "v2",
    "componentFramework": "glass-easel"
  }
}

配置说明:

  • defaultDisplayBlock: 控制元素默认显示模式
  • disableABTest: 禁用 A/B 测试
  • sdkVersionBegin/End: 定义支持的微信 SDK 版本范围
  • style: "v2": 使用 v2 样式版本,支持现代化技术栈
  • componentFramework: 使用 glass-easel 组件框架

📖 参考文档 : Skyline 渲染引擎迁移指南

2. 配置页面渲染模式

pages.config.ts 中为需要截图的页面添加 Skyline 配置:

typescript 复制代码
{
  path: "sub-share/create-message-img-wx",
  style: {
    navigationBarTitleText: "分享页面",
    navigationStyle: "custom",
    renderer: "skyline",           // 启用 Skyline 渲染
    componentFramework: "glass-easel"
  }
}

实现代码

3. 页面截图实现

vue 复制代码
<template>
  <!-- 截图容器 -->
  <snapshot id="snapshotImg" class="screenshot-container">
    <!-- 你的页面内容 -->
    <view class="content">
      <!-- 这里放置需要截图的内容 -->
    </view>
  </snapshot>
</template>

<script setup lang="ts">
// 截图方法
const takeHiddenSnapshot = () => {
  uni
    .createSelectorQuery()
    .select("#snapshotImg")
    .node()
    .exec((res) => {
      if (!res || !res[0] || !res[0].node) {
        console.error("页面节点查询失败:", res);
        return;
      }
      const node = res[0].node;
      node.takeSnapshot({
        type: "arraybuffer",
        format: "png",
        success: ({ data }) => {
          console.log("隐藏页面截图成功", data);
          const fs = wx.getFileSystemManager();
          const filePath = `${wx.env.USER_DATA_PATH}/hidden_poster.png`;
          fs.writeFileSync(filePath, data, "binary");

          // 本地调试使用
          // saveImage(filePath); //保存图片
          // shareImage(filePath); //分享图片

          // 真机&体验版&线上 使用
          wxImageUploadBinary(filePath) //上传图片
            .then((uploadData) => {
              operationImage("share", uploadData.imageUrl);
            })
            .catch((error) => {
              console.error("截图上传失败:", error);
              reject(error);
            });
        },
        fail: (err) => {
          console.error("隐藏页面截图失败:", err);
          reject(err);
        },
      });
    });
};

const operationImage = (type, filePath) => {
  uni.downloadFile({
    url: filePath,
    success: (res) => {
      if (res.statusCode === 200) {
        console.log("下载成功");
        if (type === "share") {
          shareImage(res.tempFilePath);
        } else {
          saveImage(res.tempFilePath);
        }
      }
    },
    fail: (err) => {
      console.error("下载文件失败:", err);
    },
  });
};

const shareImage = (filePath) => {
  //分享图片
  wx.showShareImageMenu({
    path: filePath,
  });
};
const saveImage = (filePath) => {
  //保存图片
  wx.saveImageToPhotosAlbum({
    filePath,
    success: () => {
      console.log("图片已保存到相册");
      resolve(filePath);
    },
    fail: (err) => {
      console.error("保存失败:", err);
      reject(err);
    },
  });
};

// 上传图片到服务器
const wxImageUploadBinary = (filePath) => {
  const uploadUrl = `xxxxxxxxxxxx/image/upload`; //上传地址
  return new Promise((resolve, reject) => {
    uni.uploadFile({
      url: uploadUrl,
      filePath: filePath, //文件
      name: "image", //后端接收key
      header: {},
      success: (res) => {
        if (res.statusCode === 200) {
          try {
            const result = JSON.parse(res.data);
            if (result.success) {
              resolve(result);
            } else {
              reject(new Error(result.message || "上传失败"));
            }
          } catch (error) {
            reject(new Error("响应解析失败"));
          }
        } else {
          reject(new Error(`上传失败: ${res.statusCode}`));
        }
      },
      fail: (error) => {
        reject(error);
      },
    });
  });
};

</script>


<style lang="scss" scoped>
.screenshot-container {
  width: 100%;
  min-height: 100vh;
  background-color: #f5f5f5;
}

.content {
  padding: 20rpx;
  // 你的样式
}
</style>

重要注意事项

⚠️ Skyline 渲染引擎兼容性问题

  1. 样式兼容性:

    • display: flex 支持有限
    • position: sticky 不完全支持
    • backdrop-filter: blur 不支持
    • overflow-scrolling: touch 处理方式不同
  2. 全局影响:

    • 启用 Skyline 后,所有页面的 button 组件样式可能受影响
    • 需要添加自定义样式覆盖默认样式
    • 建议只在必要的页面启用 Skyline 渲染
  3. 布局差异:

    • Skyline 与 WebView 在文本渲染、间距计算等方面存在差异
    • 可能出现意外的空行或间距问题
    • 需要针对 Skyline 添加特殊样式重置

📱 真机调试说明

  1. 本地路径限制:

    • wx.env.USER_DATA_PATH 在真机上有访问限制
    • 生产环境建议上传到服务器获取在线地址
    • 开发环境可直接使用本地路径
  2. 性能优化:

    • 截图文件建议压缩后上传
    • 大图片可能导致内存问题
    • 及时清理临时文件

🔧 故障排除

常见问题及解决方案:

  1. takeSnapshot 报错:

    • 确认页面已配置 renderer: "skyline"
    • 检查 manifest.json 中的 Skyline 配置
    • 确保微信开发者工具版本支持 Skyline
  2. 截图内容不完整:

    • 检查 snapshot 容器的尺寸设置
    • 确认内容已完全加载
    • 避免使用 position: fixed 等特殊定位
  3. 样式异常:

    • 为 Skyline 页面添加专门的样式重置
    • 使用 :style 而非 class 进行动态样式控制
    • 测试不同版本微信客户端的兼容性

项目特定配置

本项目使用了以下技术栈配置,确保截图功能的稳定性:

  • style: "v2" - 支持现代化 CSS 特性
  • form-data 格式文件上传
  • 多环境构建支持(开发/测试/生产)

API 参考


相关推荐
鹏多多20 小时前
React使用react-fastclick解决移动端触摸延迟300ms
前端
江城开朗的豌豆20 小时前
React Ref揭秘:直接操作DOM的"秘密通道"
前端·react.js
江城开朗的豌豆20 小时前
何时该请出Redux?前端状态管理的正确打开方式
前端·javascript·react.js
玲小珑20 小时前
LangChain.js 完全开发手册(十二)高性能 AI 应用优化技术
前端·langchain·ai编程
小岛前端20 小时前
Vue3 生态再一次加强,网站开发无敌!
前端·vue.js·前端框架
答案answer20 小时前
历时180多天,浅谈我对自由职业的初次探索
前端·程序员·three.js
江城开朗的豌豆20 小时前
Redux的双面人生:天使还是恶魔?
前端·javascript·react.js
JarvanMo20 小时前
为什么 Google 同时投资 Kotlin Multiplatform 和 Flutter
前端
Hello.Reader20 小时前
Flink 容错从状态后端到 Exactly-Once
前端·javascript·flink
小菜全20 小时前
《前端开发中常用的快捷键大全》
前端