微信小程序 商品报价表格 兼容PC端、手机端

本文介绍了一款兼容电脑和手机端的表格组件的设计与实现细节,包括固定表头、图片预览、筛选条件置顶等功能,并支持触底加载更多及文字复制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.固定表头、表格行高由内容撑开

2.图片自适应居中、图片预览

3.筛选条件置顶、显示所选的筛选分类

4.触底加载下一页

5.表格文字可复制

6.支持手机横屏、竖屏切换。横屏时隐藏底部 tabbar 导航栏

兼容电脑、手机端,文字是可以复制的,模拟器上可能看不出效果,但是在手机端长按文字可以选择复制、电脑端使用鼠标选中快捷键复制!

上效果图

wxml

<view class="containers">
  <view class="head" catchtouchmove='catchTouchMove' style="width: {{isWindows?'980px':'100%'}};">
    <view class="head__search" wx:if="{{filtrate_show}}">
      <view class="search__left">
        <text class="iconfont icon-sousuo"></text>
        <input class="search__input" confirm-type="search" type="text" bindinput="bindKeyInput" bindconfirm='searchClick' placeholder="请输入内容" />
        <view class="search__btn" bindtap="searchClick">搜索</view>
      </view>
      <!-- <view class="search__right" bindtap="xingshiClick">
      <block wx:if="{{layout_type}}">
        <view>收起筛选<text class="iconfont icon-weibiaoti33"></text></view>
      </block>
      <block wx:else>
        <view>展开筛选<text class="iconfont icon-xia"></text></view>
      </block>
    </view> -->
    </view>
    <view class="head__filtrate" wx:if="{{filtrate_show}}">
      <block wx:for="{{cate_list}}" wx:for-index="i" wx:key="i">
        <scroll-view scroll-x="true" class="filtrate__item">
          <view class="filtrate__item__row">
            <block wx:for="{{item.cate_two}}" wx:for-item="items" wx:key="index">
              <view class="filtrate__item__title {{item.index == items.id ? 'disabled':''}}" bindtap="geshitap" data-item="{{items}}" data-index="{{i}}">
                {{items.cate_name}}
              </view>
            </block>
          </view>
        </scroll-view>
      </block>
    </view>
    <view class="open__filtrate" catchtouchmove="catchTouchMove">
      <view class="open__filtrate_btn" bindtap="openFiltrate" wx:if="{{!filtrate_show}}">展开筛选<text class="iconfont icon-xia"></text></view>
      <view class="open__filtrate_btn" bindtap="openFiltrate" wx:else>收起筛选<text class="iconfont icon-weibiaoti33"></text></view>
      <view class="selected__type" wx:if="{{filtrateList!=''}}">所选分类:
        <block wx:for="{{filtrateList}}" wx:key="index"><text>{{item.cate_name}}</text></block>
      </view>
    </view>
  </view>
  <view class='centre__container'>
    <view class='table' style="margin-top: {{filtrate_show?headHeight+'px':'30px'}};">
      <view class='table__thead' style="top: {{filtrate_show?headHeight+'px':'30px'}};">
        <view class="th" style='width:70px;'>序号</view>
        <view class='th' style='width:150px;'>图片</view>
        <view class='th' style='width:70px;'>型号</view>
        <view class='th' style='width:70px;'>颜色</view>
        <view class='th' style='width:100px;'>色号</view>
        <view class='th' style='width:70px;'>规格</view>
        <view class='th' style='width:150px;'>尺寸</view>
        <view class='th' style='width:70px;'>件数</view>
        <view class='th' style='width:70px;'>价格</view>
        <view class='th' style='width:150px;'>备注</view>
      </view>
      <block wx:for="{{list}}" wx:key="index">
        <view class='table__tbody'>
          <view class='td' style='width:70px;font-weight: bold;'>{{index+1}}</view>
          <view class="td" style='width:150px;'>
            <image src="{{item.image}}" mode="aspectFit" bindtap="imgClick" data-index="{{index}}" lazy-load style="height: 120px;margin: auto;"></image>
          </view>
          <view class="td" style='width:70px;'>{{item.param_model}}</view>
          <view class="td" style='width:70px;'>{{item.param_color}}</view>
          <view class="td" style='width:100px;'>{{item.param_color_num}}</view>
          <view class="td max__td">
            <view wx:for="{{item.param_sku}}" wx:for-item="item2" wx:for-index="index2" wx:key="index2" class="max__td__row">
              <view class="max__td__row__item" style="width: 70px;">{{item2.sku}}</view>
              <view class="max__td__row__item" style='width:150px;'>{{item2.size}}</view>
              <view class="max__td__row__item" style="width: 70px;">{{item2.num}}</view>
              <view class="max__td__row__item" style="width: 69px;font-weight: bold;">{{item2.price}}</view>
            </view>
          </view>
          <view class='td' style='width:150px;'>{{item.param_custom_remark == null?"":item.param_custom_remark}}</view>
        </view>
      </block>
    </view>
  </view>
  <view class='mask' hidden='{{!filtrate_show}}' catchtouchmove='catchTouchMove' bindtap='close'></view>
</view>

<block wx:if="{{isPhone}}">
  <phoneNumber isPhone='{{isPhone}}'></phoneNumber>
</block>
<block wx:if="{{!iShidden}}">
  <authorize bind:onLoadFun='onLoadFun' iShidden="{{iShidden}}" isAuto="{{isAuto}}"></authorize>
</block>

wxss 样式这里统一使用 px  因为rpx可以根据屏幕宽度进行自适应,电脑端字体会变大、表格行高也会因为窗口大而变大等等...这样就做不到兼容电脑端了,所以不用rpx,直接用px写死

page {
  width: 100%;
  height: 100%;
  white-space: nowrap;
  overflow: scroll;
  box-sizing: border-box;
  font-size: 14.5px;
  font-family: '宋体';
}

.containers {
  width: 980px;
  height: auto;
  margin: 0 auto;
  background-color: #fff;
}

.head {
  width: 100%;
  padding: 0 10px; 
  position: fixed;
  top: 0;
  z-index: 99;
  background-color: #fff;
  overflow: hidden;
}

/* search */
.head__search {
  /* width: 980px; */
  width: 100%;
  height: auto;
  padding: 10px 0px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.search__left {
  /* width: 600px; */
  flex: 1;
  height: 30px;
  position: relative;
  vertical-align: middle;
  border-radius: 15px;
  padding-left: 25px;
  display: flex;
  align-items: center;
  border: 1px solid #ccc;
}

.search__left text {
  font-size: 16px;
  position: absolute;
  top: 6.5px;
  left: 15px;
}

.search__input {
  padding-left: 12.5px;
  /* width: 500px; */
  flex: 1;
}

.search__btn {
  width: 100px;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  border-radius: 0px 15px 15px 0px;
  color: #555;
  background-color: #eee;
  border-left: 1px solid #ccc;
}

@media (max-width: 430px) {
  /* 仅在 480px 或更宽的屏幕上生效的样式规则 */
  .search__btn {
    width: 60px;
  }
}

.search__right {
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  width: 83px;
  height: 25px;
  border: 1px solid #e8e8e8;
  background-color: #f5f5f5;
  color: #6b6b6b;
  cursor: pointer;
}

/* filtrate */
.head__filtrate {
  /* width: 100%; */
  height: auto;
  overflow: hidden;
}

.filtrate__item {
  padding-bottom: 10px;
}

.filtrate__item__row {
  display: flex;
  align-items: center;
  /* flex-wrap: wrap; */
}

.filtrate__item__title {
  padding: 0 10px;
  height: 30px;
  line-height: 30px;
  white-space: nowrap;
  font-size: 13px;
  font-family: PingFang;
  font-weight: 500;
  color: #010000;
  border-radius: 15px;
}

.filtrate__item__row .disabled {
  background-color: #F0F1F3;
  font-weight: 800;
}

/* open__filtrate */
.open__filtrate {
  width: 980px;
  height: 30px;
  font-size: 12px;
  padding: 0 30px;
  display: flex;
  align-items: center;
}

.open__filtrate_btn {
  width: 85px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  background-color: #f8f8f8;
  border: 1px solid #f8f8f8;
}

.selected__type {
  margin-left: 20px;
}

.selected__type text{
  margin-right: 10px;
}

/* centre */
.centre__container {
  width: 100%;
  height: 100%;
  display: flex;
  background-color: white;
}

.table {
  margin: 0 auto;
  display: inline-flex;
  flex-direction: column;
  border: 1px solid rgba(218, 217, 217, 1);
  border-bottom: 0;
}

.table__thead {
  width: 100%;
  height: 40px;
  border-top: 1px solid rgba(218, 217, 217, 1);
  border-width: thin;
  display: inline-flex;
  position: -webkit-sticky;
  position: sticky;
  top: 50px;
  z-index: 87;
}

.th,
.td {
  width: 200px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: #FFFF00;
  border-right: 1px solid rgba(218, 217, 217, 1);
  border-bottom: 1px solid rgba(218, 217, 217, 1);
  border-width: thin;
  font-weight: bold;
}

.table__tbody {
  width: 100%;
  display: inline-flex;
  flex-direction: row;
  border-bottom: 1px solid rgba(218, 217, 217, 1);
}

.td {
  background: white;
  min-height: 90px;
  font-weight: normal;
  text-align: center;
  word-wrap: break-word;
  word-break: break-all;
  white-space: pre-line;
  /* 文字可复制 */
  user-select: text;
  -moz-user-select: text;
  -webkit-user-select: text;
  -ms-user-select: text;
}

.max__td {
  width: 360px;
}

.max__td__row {
  width: 100%;
  display: flex;
  border-bottom: 1px solid rgba(218, 217, 217, 1);
  flex-basis: auto;
  flex-grow: 1;
  -webkit-flex-grow: 1;
}

.max__td__row:last-child {
  border-bottom: none;
}

.max__td__row__item {
  width: 200.5px;
  border-right: 1px solid rgba(218, 217, 217, 1);
  border-width: thin;
  min-height: 30px;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.max__td__row__item:last-child {
  border-right: none;
}

.mask {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 98;
}
/* ----end */

js 处理逻辑

// 导入接口
import { getIndexData, cateIndex, goodsList } from '../../api/api.js';

Page({

  /**
   * 页面的初始数据
   */
  data: {
    cate_list: [],
    list: [],
    inputValue: '',
    ids: '',
    page: 1,
    loading: true,
    up_show: false,
    layout_type: true,
    userInfo: "",
    iShidden: true,
    isAuto: false,
    isPhone: false, 
    inter: '',
    headHeight:0,
    filtrate_show: false,
    isWindows: false,
    filtrateList:[],
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    //获取系统信息
    wx.getSystemInfo({
      success: (res) => {
      if(res.platform == "windows") {
        this.setData({
          isWindows: true
        })
      }
      }
    })

    //请求筛选列表
    cateIndex().then(res => {
      if (res.status == 200) {
        let all = {
          cate_name: "全部",
          id: 0,
        }
        res.data.forEach((e) => {
          e.index = 0;
          e.cate_two = [all, ...e.cate_two];
        })
        this.setData({
          cate_list: res.data
        })
      }
    })

    //请求商品列表
    this.dataGoods();
  },

  //商品列表
  dataGoods() {
    let data = {
      cate_ids: this.data.ids,
      page: this.data.page,
      keywords: this.data.inputValue,
    }
    getIndexData(data).then(res => {
      if (res.status == 200) {
        if (res.data.length != 0) {
          this.setData({
            list: [...this.data.list, ...res.data]
          })
        } else {
          this.setData({
            loading: false
          })
        }
      }
    })
  },

    // 键盘输入时触发事件 
    bindKeyInput: function (e) {
      this.setData({
        inputValue: e.detail.value
      })
    },

    //搜索按钮点击 or 点击键盘搜索按钮时触发
    searchClick() {
      let result = this.islogin();
      if(result){
        this.setData({
          page: 1,
          list: [],
          loading: true
        })
        this.dataGoods();
      }
    },

  //收起 | 展开筛选
  xingshiClick() {
    this.setData({
      layout_type: !this.data.layout_type,
    })
    wx.pageScrollTo({
      scrollTop: 0,
      duration: 0
    })
  },

  // 点击分类筛选
  geshitap(e) {
    let result = this.islogin();
    if(result){
      let dataset = e.currentTarget.dataset;
      var listIndex = "cate_list[" + dataset.index + "].index";
      this.setData({
        [listIndex]: dataset.item.id,
        page: 1,
        list: [],
        loading: true
      })
      let ids = [];
      this.data.cate_list.forEach(item => {
        if (item.index != 0) {
          ids.push(item.index)
        }
      })
      this.setData({
        ids: ids.join(','),
      })

      // 处理所选的分类
      let newlist = []
      newlist.push({id:dataset.index,cate_name:dataset.item.cate_name})
      if(this.data.filtrateList.length==0){
        //console.log('--空数组,直接赋值')
        this.setData({
          filtrateList: newlist,
        })
      } else {
        //console.log('--非空数组,合并数组')
         let isRow = false;
         let index = 0;
        for(var k = 0;k<this.data.filtrateList.length;k++){
          if(dataset.index==this.data.filtrateList[k].id){
            //console.log('循环判断用户点击的是否是同一行')
            isRow = true
            index = k
          }
        }

        if(isRow){
          //console.log('点击的是同一行,替换')
          let list = this.data.filtrateList
          list[index].cate_name = dataset.item.cate_name
          this.setData({
            filtrateList: list
          })
        } else {
          //console.log('点击的不是同一行,合并');
          this.setData({
            filtrateList: this.data.filtrateList.concat(newlist)
          })    
        }
      }
      //console.log(this.data.filtrateList);
      this.dataGoods();
      }
  },


  //点击图片预览事件
  imgClick(e){
    let result = this.islogin();
    if(result){
      let index = e.currentTarget.dataset.index;
      let list = this.data.list;
      // wx.previewImage({
      //   current: list[index].image, 
      //   urls: list[index].slider_image,
      //   success: function(res) {}
      // })

      //查看图片要添加记录,所以请求一次接口
      goodsList(list[index].id).then(res => {
        if (res.status == 200) {
          wx.previewImage({
            current: res.data.storeInfo.image, 
            urls: res.data.storeInfo.slider_image,
            success: function(res) {}
          })
        } 
      })

    }
  },

  //用户是否登录、封装为公共函数
  islogin() {
    let userInfo = wx.getStorageSync('USERINFO');
    if (!userInfo) {
      this.setData({
        iShidden: false,
      });      
      return false
    }

    if (!userInfo.phone) {
      this.setData({
        isPhone: true,
      });
      return false
    }

    return true
  },

  /**
   * 
   * 生命周期函数--监听屏幕滚动
   */
  onPageScroll (e) {
    // if(e.scrollTop > 0 ) {
    //   this.setData({
    //     filtrate_show: false,
    //   });
    // }
  },

  // 展开筛选
  openFiltrate () {
    this.setData({
      filtrate_show: !this.data.filtrate_show,
    })
    let query = wx.createSelectorQuery();
    query.select('.head').boundingClientRect(rect=>{
      //console.log('head的高度是',rect.height)
      this.setData({
        headHeight: rect.height
      })
    }).exec();
  },    

  //关闭蒙版
  close() {
     this.openFiltrate()
  },

  //禁止滑动
  catchTouchMove(){
    return false;
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    // wx.hideHomeButton();
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 
   * 生命周期函数--监听屏幕旋转事件
   */
  onResize:function(res) {
    console.log('屏幕方向旋转',res.deviceOrientation)
    if(res.deviceOrientation == 'landscape'){
      wx.hideTabBar();
    }else{
      wx.showTabBar();
    }
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
      
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    if (this.data.loading) {
      let page = this.data.page + 1;
      this.setData({
        page: page
      })
      this.dataGoods();
    }
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

然后配置单页面的json文件  注意不是app.json !  "pageOrientation": "auto" (手机横竖屏自适应) 

<think>我们正在微信小程序环境中使用Vue3开发,需要将PC数据导出为PDF。微信小程序本身没有直接生成PDF的API,但我们可以借助第三方库或服务。以下是几种实现方案:###方案1:使用jsPDF(纯前端生成)**原理**:在前端使用jsPDF库将HTML内容转换为PDF。但微信小程序环境与浏览器不同,需注意兼容性。**步骤**:1.**安装jsPDF**:由于小程序不支持npm包直接引入,需手动下载jsPDF的单个文件(如`jspdf.min.js`)放入小程序项目目录。2.**生成PDF内容**:将需要导出的数据渲染为HTML结构(可使用canvas或利用小程序的WXML转图片再插入PDF)。3.**使用jsPDF**:-创建jsPDF实例-将HTML内容或图片添加到PDF-保存PDF文件**示例代码**(Vue3组合式API):```javascriptimport{ref}from'vue';importjspdffrom'@/utils/jspdf.min.js';//路径根据实际位置调整exportdefault{setup(){constexportPDF=()=>{constdoc=newjspdf.jsPDF();doc.text('Helloworld!',10,10);doc.save('test.pdf');//在微信小程序中无法直接保存到本地,需使用小程序的保存文件API};return{exportPDF};}};```**小程序适配**:-小程序无法直接使用`doc.save()`下载,需改用`wx.saveFile`保存到本地缓存,然后提示用户下载。-若包含图片,需先通过`wx.canvasToTempFilePath`将canvas转成临时路径。**限制**:复杂表格或样式支持有限。---###方案2:后生成PDF(推荐)**原理**:前端将数据发送到后,后使用如`pdf-lib`(Node.js)等库生成PDF并返回文件地址。**步骤**:1.前端(小程序)收集数据,通过微信小程序`wx.request`发送到后API。2.后接收数据,生成PDF文件。3.后返回PDF文件的URL(或直接返回文件流)。4.小程序使用`wx.downloadFile`下载PDF,并配合`wx.openDocument`打开预览。**后示例**(Node.js+pdf-lib):```javascriptconst{PDFDocument}=require('pdf-lib');asyncfunctiongeneratePDF(data){constpdfDoc=awaitPDFDocument.create();constpage=pdfDoc.addPage();page.drawText(data.text,{x:50,y:50});returnawaitpdfDoc.save();}```**小程序**:```javascriptwx.request({url:'https://your-api.com/generate-pdf',method:'POST',data:{/*你的数据*/},success(res){constfilePath=res.data.url;//假设返回PDF的URLwx.downloadFile({url:filePath,success:(res)=>{wx.openDocument({filePath:res.tempFilePath,showMenu:true//显示菜单,支持分享、保存等});}});}});```**优点**:处理复杂样式更灵活,不依赖前端性能。---###方案3:使用云函数生成PDF若使用微信云开发,可直接在小程序云函数中生成PDF。**步骤**:1.创建云函数,安装依赖(如`jspdf`)。2.云函数中生成PDF并返回文件ID。3.小程序调用云函数后下载文件。**云函数示例**:```javascriptconstjsPDF=require('jspdf');exports.main=async(event,context)=>{constdoc=newjsPDF();doc.text(event.text,10,10);constbuffer=doc.output('arraybuffer');//上传到云存储constfile=awaitcloud.uploadFile({cloudPath:'pdfs/test.pdf',fileContent:buffer});return{fileID:file.fileID};};```**小程序调用**:```javascriptwx.cloud.callFunction({name:'generatePDF',data:{text:'Hellofromcloud!'},success:res=>{constfileID=res.result.fileID;wx.cloud.downloadFile({fileID,success:res=>wx.openDocument({filePath:res.tempFilePath})});}});```---###总结-**简单文本/表格**:可尝试纯前端方案(jsPDF),但需处理小程序兼容性。-**复杂需求**:推荐后生成或云函数方案,更稳定可靠。§§相关问题§§1.微信小程序中如何实现PDF的预览和分享?2.使用jsPDF时如何处理中文字体缺失问题?3.如何在小程序中将HTML页面(含样式)完整转换为PDF?</think>在微信小程序中使用 Vue3 实现 PC 数据导出为 PDF,需要结合前端生成和后处理技术。以下是完整实现方案: ### 一、前端实现(Vue3 + 小程序) #### 1. 准备数据并生成 HTML ```vue <template> <view> <button @click="exportPDF">导出PDF</button> <!-- 隐藏的PDF内容容器 --> <view style="display:none"> <div ref="pdfContent"> <h1>销售报告</h1> <table> <tr v-for="item in reportData" :key="item.id"> <td>{{ item.product }}</td> <td>{{ item.quantity }}</td> <td>{{ item.price }}</td> </tr> </table> </div> </view> </view> </template> <script setup> import { ref } from 'vue'; const reportData = ref([ { id: 1, product: '手机', quantity: 100, price: 2999 }, { id: 2, product: '笔记本', quantity: 50, price: 5999 } ]); const pdfContent = ref(null); const exportPDF = async () => { // 获取HTML内容 const htmlContent = pdfContent.value.innerHTML; // 发送到后生成PDF const res = await wx.request({ url: 'https://your-api.com/generate-pdf', method: 'POST', data: { html: htmlContent }, header: { 'Content-Type': 'application/json' } }); // 下载PDF文件 wx.downloadFile({ url: res.data.pdfUrl, success: (res) => { wx.openDocument({ filePath: res.tempFilePath, showMenu: true }); } }); }; </script> ``` #### 2. 关键注意事项 1. **样式处理**:使用内联样式确保PDF样式正确 ```html <table style="border-collapse: collapse; width: 100%;"> <tr style="border: 1px solid #ddd;"> ``` 2. **图片处理**:将图片转换为 Base64 编码 ```javascript // 在小程序中转换图片 wx.getFileSystemManager().readFile({ filePath: 'image.png', encoding: 'base64', success: (res) => { const base64Img = `data:image/png;base64,${res.data}`; } }); ``` 3. **跨平台兼容**:使用条件编译处理小程序和PC差异 ```javascript // #ifdef MP-WEIXIN wx.downloadFile(...) // #endif ``` ### 二、后实现(Node.js + pdf-lib) #### 1. 安装依赖 ```bash npm install pdf-lib html-pdf ``` #### 2. PDF 生成服务 ```javascript const express = require('express'); const htmlPdf = require('html-pdf'); const app = express(); app.post('/generate-pdf', (req, res) => { const { html } = req.body; const options = { format: 'A4', border: { top: '20px', right: '20px', bottom: '20px', left: '20px' }, }; htmlPdf.create(html, options).toBuffer((err, buffer) => { if (err) return res.status(500).send(err); // 返回PDF下载链接(实际项目需存储到云存储) const pdfUrl = `data:application/pdf;base64,${buffer.toString('base64')}`; res.json({ pdfUrl }); }); }); app.listen(3000); ``` ### 三、微信小程序配置 1. **配置合法域名**: ```json // app.json { "requestWhiteList": [ "https://your-api.com" ] } ``` 2. **文件下载权限**: ```json // manifest.json { "requiredPrivateInfos": [ "downloadFile", "openDocument" ] } ``` ### 四、替代方案(纯前端方案) 如果数据量小,可使用纯前端库(需注意小程序兼容性): ```javascript // 安装jspdf(需手动导入) import jsPDF from '@/utils/jspdf.min.js'; const generatePDF = () => { const doc = new jsPDF(); doc.text('销售报告', 20, 20); reportData.value.forEach((item, i) => { doc.text(`${item.product} - ${item.quantity}件`, 20, 30 + i * 10); }); // 小程序保存文件 const pdfData = doc.output('arraybuffer'); wx.saveFile({ tempFilePath: pdfData, success: (res) => wx.openDocument({ filePath: res.savedFilePath }) }); }; ``` ### 常见问题解决 1. **中文乱码**: ```javascript // 添加中文字体 doc.addFont('simhei.ttf', 'SimHei', 'normal'); doc.setFont('SimHei'); ``` 2. **样式丢失**: - 使用内联样式 - 避免使用 Flex/Grid 等复杂布局 - 使用表格实现简单布局 3. **性能优化**: - 分页处理大数据 - 后生成避免阻塞主线程 - 使用微信云函数托管生成服务[^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值