uni-app生成海报看这一篇就够了!(lime-painter)

  • lime-painter是一款canvas海报组件,可以更轻松的生成海报。
  • 本项目基于Vue-cli + uni-app + Vue2 + uView进行开发。
  • 本项目功能包括生成带有个人信息的海报、海报可进行分享微信好友收藏保存到相册,最终实现的效果如下:

使用介绍

引入lime-painter

  • 如果是HBuilderX创建的项目可以在DCloud中直接引用到Hbuildx的项目中去,如果是vue-cli创建的项目可以将代码下载下来然后粘贴到项目中去。下载链接:ext.dcloud.net.cn/plugin?id=2...
  • 本项目采用的是vue-cli的插件方式,将插件下载下来后放到components文件夹下。
  • 在poster文件夹下创建poster.vueadv.vue文件

两种使用方式

  • 本文使用的是JSON的使用方式,欲了解其他可查看官方文档:Lime Ui

方式一 :Template

  • 提供l-painter-viewl-painter-textl-painter-imagel-painter-qrcode四种类型组件
  • 通过 css 属性绘制样式,与 style 使用方式保持一致。
xml 复制代码
<l-painter>
  <l-painter-view
    css="background: #07c160; height: 120rpx; width: 120rpx; display: inline-block"
  ></l-painter-view>
  <l-painter-view
    css="background: #1989fa; height: 120rpx; width: 120rpx; border-top-right-radius: 60rpx; border-bottom-left-radius: 60rpx; display: inline-block; margin: 0 30rpx;"
  ></l-painter-view>
  <l-painter-view
    css="background: #ff9d00; height: 120rpx; width: 120rpx; border-radius: 50%; display: inline-block"
  ></l-painter-view>
</l-painter>

方式二 : JSON

  • 在 json 里四种类型组件的type为view、text、image、qrcode
  • 通过 board 设置海报所需的 JSON 数据进行绘制或ref获取组件实例调用组件内的render(json)

代码实现

一、poster.vue文件

html 复制代码
<template>
  <view class="main">
    <view class="article">
      <view class="cell" v-for="(item, index) in goods" :key="index" @click="createAdv(item, index)">
        <image class="img" :src="item.pic" mode="widthFix"></image>
        <view class="demo-title">{{ item.title }}</view>
      </view>
    </view>
    <!-- 引入生成海报组件 -->
    <adv class="adv" v-if="isShow" ref="advRef" :config="advConfig" @close="closePopup"/>
    <view class="circle" @click="addPhoto">
      <u-icon name="photo" size="50"></u-icon>
    </view>
  </view>
</template>

<script>
import adv from "./adv.vue";
export default {
  name: "poster",
  components: {
    adv,
  },
  data() {
    return {
      isShow: false,
      advConfig: {
        url: null,
      },
      goods: [],
    };
  },
  mounted() {
    this.getDate();
  },
  methods: {
    getDate() {
      setTimeout(() => {
        //模拟向后台发送请求
        const curPageData = [
          //模拟后台返回数据
          {
            id: 1,
            title: "宣传海报1",
            pic: "/static/poster.jpg",
          },
          {
            id: 2,
            title: "宣传海报2",
            pic: "/static/poster.jpg",
          },
          {
            id: 3,
            title: "宣传海报3",
            pic: "/static/poster.jpg",
          },
          {
            id: 4,
            title: "宣传海报4",
            pic: "/static/poster.jpg",
          },
          {
            id: 5,
            title: "宣传海报5",
            pic: "/static/poster.jpg",
          },
          {
            id: 6,
            title: "宣传海报6",
            pic: "/static/poster.jpg",
          },
          {
            id: 7,
            title: "宣传海报7",
            pic: "/static/poster.jpg",
          },
          {
            id: 8,
            title: "宣传海报8",
            pic: "/static/poster.jpg",
          },
        ];
        this.goods = curPageData;
      });
    },
    createAdv(row) {
      this.isShow = true;
      this.advConfig = row;
      setTimeout(() => {
        if (this.$refs.advRef) this.$refs.advRef.init(); //触发子组件,打开弹窗
      }, 500);
    },
    //选择照片生成海报
    addPhoto() {
      let that = this
      uni.chooseImage({
        count: 1,
        sizeType: ["original", "compressed"],
        sourceType: ["album"],
        success: function (res) {
          that.createAdv({
            pic: res.tempFilePaths[0],
          });
        },
      });
    },
    // 销毁组件
    closePopup() {
      this.isShow = false;
    },
  },
};
</script>
<style scoped>
.main {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #ffffff;
  padding: 20rpx;
}
.article {
  display: flex;
  flex-wrap: wrap;
  justify-content: left;
  align-items: center;
}
.img {
  width: 140rpx;
  max-height: 200rpx;
}
.cell {
  display: inline-block;
  margin: 18rpx;
}
.circle {
  width: 150rpx;
  height: 150rpx;
  background-color: #2b993950;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  right: 50rpx;
  bottom: 50rpx;
  box-shadow: 0 0 20rpx 15rpx #f6f6f6;
}
.demo-title {
  font-size: 20rpx;
  margin-top: 5px;
  color: #999999;
  text-align: center;
}
.adv{
  width: calc(100% - 80rpx);
  height: 86vh;
  position: absolute;
  padding: 40rpx;
}
</style>

页面实现效果如下:

二、adv.vue文件

  • 点击poster页面中的图片,弹出adv页面,uni.getStorageSync("userInfo")是获取提前保存到storage缓存的数据
js 复制代码
<template>
  <view class="main">
    <u-popup ref="popupRef" mode="center" width="80%" height="auto" :custom-style="customStyle"
      :safe-area-inset-bottom="true" :closeable="!show" v-model="pop" :mask-close-able="false"
      :close-icon-size="36" close-icon-color="#d53228">
      <view class="content">
        <scroll-view scroll-y="true" class="scroll"> 
          <image v-if="!show" class="main-image" mode="widthFix" :src="path" bg-color="white"></image>
            <view v-else style="text-align: center;">
              <u-loading :show="show" class="loading" size="84" mode="flower"></u-loading>加载中...
            </view>
          <l-painter ref="painterRef" :board="poster" isCanvasToTempFilePath @success="path = $event;show = false;" hidden/>
        </scroll-view>
      </view>
    </u-popup>
    <view v-if="!show" class="bottom">
      <button class="b-btn" type="primary" @click="share" :loading="loading" :disabled="loading" throttle-time="500">
        <text class="button-text">一键分享</text>
      </button>
    </view>
  </view>
</template>
<script>
export default {
  name: "adv",
  props: {
    config: Object,
  },
  data() {
    return {
      customStyle: {
        backgroundColor: "transparent",
        height: "90vh",
        marginTop:"20rpx",
      },
      path: "",
      pop: true,
      loading: false,
      show: true,
      poster: {
        views: [
          {
            css: {
              boxSizing: "border-box",
              background: "#fff",
              width: "100%",
              boxShadow: "0 20rpx 20rpx #e4e4e4",
            },
            views: [
              {
                src: this.config.pic,
                type: "image",
                css: {
                  objectFit: "fill",
                  objectPosition: "50% 50%",
                  width: "100%",
                  height: "100%",
                },
              },
              {
                css: {
                  marginTop: "10rpx",
                  marginLeft: "10rpx",
                },
                views: [
                  {
                    src: uni.getStorageSync("userInfo").profile,
                    type: "image",
                    css: {
                      background: "#fff",
                      objectFit: "cover",
                      marginRight: "20rpx",
                      marginTop: "10rpx",
                      marginBottom: "10rpx",
                      marginLeft: "10rpx",
                      border: "2rpx solid #fff",
                      boxSizing: "border-box",
                      height: "80rpx",
                      width: "80rpx",
                      borderRadius: "50%",
                    },
                  },
                  {
                    type: "view",
                    css: {
                      display: "flex",
                      flexDirection: "column",
                      width: "70%",
                      marginTop: "12rpx",
                    },
                    views: [
                      {
                        css: {
                          display: "flex",
                        },
                        views: [
                          {
                            text: uni.getStorageSync("userInfo").name,
                            type: "text",
                            css: {
                              display: "flex",
                              color: "#050505",
                              fontSize: "30rpx",
                              marginRight: "10rpx",
                            },
                          },
                          {
                            text: uni.getStorageSync("userInfo").mobile,
                            type: "text",
                            css: {
                              display: "flex",
                              color: "#6a6a6a",
                              fontSize: "25rpx",
                              marginTop: "5rpx",
                            },
                          },
                        ],
                      },
                      {
                        css: {
                          display: "flex",
                        },
                        views: [
                          {
                            text: uni.getStorageSync("userInfo").job,
                            type: "text",
                            css: {
                              display: "flex",
                              color: "#6a6a6a",
                              fontSize: "23rpx",
                              marginRight: "5rpx",
                              marginTop: "2rpx",
                            },
                          },
                          {
                            text: uni.getStorageSync("userInfo").company,
                            type: "text",
                            css: {
                              display: "flex",
                              color: "#6a6a6a",
                              fontSize: "23rpx",
                              marginTop: "2rpx",
                            },
                          },
                        ],
                      },
                    ],
                  },
                  {
                    type: "image",
                    src: uni.getStorageSync("userInfo").qrCode,
                    css: {
                      objectFit: "fill",
                      width: "85rpx",
                      height: "85rpx",
                      marginLeft: "0rpx",
                      marginTop: "5rpx",
                    },
                  },
                ],
                type: "view",
              },
            ],
            type: "view",
          },
        ],
      },
    };
  },
  watch: {
    pop: {
      handler(newval, oldVal) {
        if (!newval) {
          this.$emit("close");
        }
      }
    },
  },
  methods: {
    //父组件ref触发打开弹窗
    init() {
      this.pop = true;
    },
    share(){
      this.$refs.painterRef.canvasToTempFilePathSync({
        fileType: "jpg",
        pathType: "url",
        quality: 1,
        success: (res) => {
          //调出微信分享窗口
          wx.showShareImageMenu({
            path: res.tempFilePath
          })
        },
      })
      //非小程序,自定义保存到相册按钮
      // uni.getSetting({
      //   success: (res) => {
      //     //如果没有相册权限
      //     if (!res.authSetting["scope.writePhotosAlbum"]) {
      //       uni.authorize({
      //         scope: "scope.writePhotosAlbum",
      //         success: () => {
      //           //授权成功保存图片到系统相册
      //           this.loading = true;
      //           this.$refs.painterRef.canvasToTempFilePathSync({
      //             fileType: "jpg",
      //             pathType: "url",
      //             quality: 1,
      //             success: (res) => {
      //               // 非H5 保存到相册
      //               uni.showToast({
      //                 title: "保存成功",
      //                 icon: "none",
      //               });
      //               console.log(res, "res");
      //               this.loading = false;
      //               this.$refs.popupRef.close();
      //               uni.saveImageToPhotosAlbum({
      //                 filePath: res.tempFilePath,
      //               });
      //             },
      //             fail: (err) => {
      //               uni.showToast({
      //                 title: "保存失败",
      //                 icon: "none",
      //               });
      //             },
      //           });
      //         },
      //         fail: (err) => {
      //           uni.showToast({
      //             title: "没有授权,请在设置中开启相册权限!",
      //             icon: "none",
      //           });
      //         },
      //       });
      //     } else {
      //       //如果已有相册权限,直接保存图片到系统相册
      //       this.loading = true;
      //       this.$refs.painterRef.canvasToTempFilePathSync({
      //         fileType: "jpg",
      //         pathType: "url",
      //         quality: 1,
      //         success: (res) => {
      //           // 非H5 保存到相册
      //           uni.showToast({
      //             title: "保存成功",
      //             icon: "none",
      //           });
      //           console.log(res, "res");
      //           this.loading = false;
      //           this.$refs.popupRef.close();
      //           // H5 提示用户长按图另存
      //           uni.saveImageToPhotosAlbum({
      //             filePath: res.tempFilePath,
      //             success: function () {
      //               console.log("save success");
      //             },
      //           });
      //         },
      //         fail: (err) => {
      //           uni.showToast({
      //             title: "保存失败",
      //             icon: "none",
      //           });
      //         },
      //       });
      //     }
      //   },
      // })
    }
  },
};
</script>
<style lang="scss" scoped>
.main {
  width: 100vw;
  height: auto;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  z-index: 10;
  .content{
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    background-color: transparent;
    .scroll{
      height: 100%;
      background-color: transparent;
      min-height: 50%;
    }
  }
  .bottom{
    position: fixed;
    bottom: 10rpx;
    left: 0;
    padding: 20rpx;
    width: 100%;
    height: 100rpx;
    background-color: transparent;
    z-index: 100751;
    .b-btn{
      border-color: #2b9939;
      background-color: #ffffff;
      color: #2b9939;
      line-height: 70rpx
    }
  }
  .main-image {
    width: 100%;
    height: 90vh;
  }
}
</style>
  • 页面实现效果如下:
  • 点击一键分享,使用wx.showShareImageMenu调出分享页面,可分享至微信好友、收藏及保存到手机相册。页面展示效果如下:

三、生成带参数的小程序码

可修改poster.vue中的createAdv方法,后端调用微信生成小程序码的api接口(文档:生成小程序码api),我们只需要调用后端接口GetMiniprogramQRCode拿到数据即可,需要后端配合。

js 复制代码
createAdv(row){
    const res_data = {
        page: "pages/index/index", //生成二维码的页面路径
        scene: String(uni.getStorageSync("userInfo").usrId), //页面携带的参数
    };
    GetMiniprogramQRCode(res_data).then((data) => {
        if (data.data.code === 200) {
            isShow.value = true;
            advConfig.value = row;
            advConfig.value.wxQRCode = data.data.data; //保存生成的小程序码
            setTimeout(() => {
                if (advRef.value) {
                    advRef.value.init("center", "data");
                }
            }, 500);
        }
    })
};
  • adv.vue的poster变量添加如下代码,显示生成的小程序码,可添加到与uni.getStorageSync("userInfo").qrCode并列处.
js 复制代码
{
    src: `data:image/png;base64,${this.config.wxQRCode}`,
    type: "image",
    css: {
        objectFit: "fill",
        width: "85rpx",
        height: "85rpx",
        marginTop: "5rpx",
        marginLeft: "25rpx",
    },
},

结语

以上就是这篇文章的全部介绍,如果对你有用请点赞收藏哦,谢谢支持!有问题或者有更好的建议也可以下方评论区评论。

往期推荐

相关推荐
还是大剑师兰特1 小时前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
man20171 小时前
【2024最新】基于springboot+vue的闲一品交易平台lw+ppt
vue.js·spring boot·后端
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
吖秧吖1 小时前
three.js 杂记
开发语言·前端·javascript
前端小超超1 小时前
vue3 ts项目结合vant4 复选框+气泡弹框实现一个类似Select样式的下拉选择功能
前端·javascript·vue.js
大叔是90后大叔1 小时前
vue3中查找字典列表中某个元素的值
前端·javascript·vue.js