- 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.vue
和adv.vue
文件
两种使用方式
- 本文使用的是JSON的使用方式,欲了解其他可查看官方文档:Lime Ui
方式一 :Template
- 提供
l-painter-view
、l-painter-text
、l-painter-image
、l-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",
},
},
结语
以上就是这篇文章的全部介绍,如果对你有用请点赞收藏哦,谢谢支持!有问题或者有更好的建议也可以下方评论区评论。