文生图
功能点
- 页面进来获取背景图url和图片宽高(根据比例和手机屏幕处理过的宽高)
- 渲染图片(背景图最后生成图片模糊,换成img展示解决)
- 添加多个文字,编辑文字内容,拖拽改变文字位置,删除文字
- 编辑文字内容,颜色,字体,大小
- 生成图片预览
- 转发图片给好友、保存
bug点
- 使用背景图最后生成图片模糊,换成img展示解决
- 图片必须转成base64格式,最后才能保存,否则不显示(例如二维码和背景图)
拖拽插件
多个文字框时,点击改变isActive控制编辑状态框的显示隐藏
- 只保留一个clicked 事件
- 在外层添加时间.stop 重置数组激活状态为false
整个页面分为上中下三部分,中间可滚动
- 整体100vh ,采用纵向flex布局
- 上下区域高度不固定,下面样式设置直接写,不采用弹窗形式
- 中间区域 overflow-y: auto;高度超出会自动有滚动条
- 中间图片竖图顶部会遮挡,不能使用center布局即可
解决不同图片尺寸都要居中显示,切最后生成图片又得是图片区域
- 采用父盒子 flex:center,内层盒子居中显示:横图可以,超高竖图顶部会有遮挡;所以判断竖图就定义宽90%,高度auto
- 根据图片比例动态计算宽高,动态设置内层盒子的宽高;盒子里放图片和文字
- 假如是9:16 的图片,固定一个高度,计算固定宽度;其他比例宽度为手机屏幕宽度,高度计算
删除其中一个位置会跑到上个位置
- 拖拽left、top赋值,删除加个show变量false隐藏,不直接删除这一项
添加文字后,第一次点击聚焦拖拽框,文字会移动到左上角的位置
- 添加文字,给了一个默认left、top值让文字显示在中间
- 但是拖拽组件没有设置初始偏移量 x、y
- 保持初始偏移量和添加文字默认位置一致即可解决
vcolorpicker颜色选取插件
切换字体字体包
- vue获取文件夹下所有字体包 生成数组:字体包的名字和下拉选择名字保持一致
- 类名定义为font-索引值
- 这样下拉选中得到索引,动态绑定类名即可切换字体
vue瀑布流插件vue-masonry
第二版小程序
- 第一版公众号无法实现转发图片给好友,只能分享公众号;所以修改为小程序
- 小程序没有找到拖拽插件,所以打算用uniapp生成小程序
- 结果uniapp也没有拖拽插件,最终使用uniapp 嵌入H5页面(编辑贺卡页面)
- uniapp打包小程序弊端:使用uview插件占内存较大很快就超了2M
- 于是采用分包,主包只放tabbar页面,分包可以有多个,但是总限制8M,每个包限制2M
- 分包可以键自己的图片文件夹和插件
- 上线要在编辑器上点击发行,才会运行在生产环境
let url = ''
let url1 = ''
let url2 = ''
if (process.env.NODE_ENV === 'development') {
console.log('开发环境')
url = 'http://192.168.0.19:9888'
url1 = 'http://192.168.2.89:8080'
url2 = 'http://192.168.0.19:9888'
} else {
console.log('生产环境')
url = 'https://wst.maitewang.com/stage-api'
url1 = 'https://wst.maitewang.com'
url2 = 'https://wst.maitewang.com/stage-api'
}
export const baseUrl = url;
export const h5Url = url1;
export const imgUrl = url2;
- 小程序发布之后,H5会有缓存,大概5个小时左右会更新;小程序24小时会基本更新所有用户
uniapp 打包小程序并嵌入H5上线注意事项
小程序里边嵌入H5 使用 web-view
- 上线需要配置业务域名,即H5访问地址
- 域名必须使用https;域名不能带端口号;需要下载文件放服务器上
- web-view会缓存,修改H5之后,线上不会变; 在过一段时间(时间不定,一天或者几小时,无明显规律)是可以进行缓存刷新的:有需要的解决
- 可以ngix配置不缓存html文件,即可解决;还有静态资源的缓存比较麻烦
- 将微信从后台退出再打开并重新进入小程序;
uniapp可以直接调取微信小程序转发图片api
- 转发有发送朋友和保存相册功能
- 发送朋友的图片下面可以带小程序的连接,但是对小程序类别有要求,不是所有的都可以
- 如果类别不符合不能配置转发带链接,否则转发功能也会调不起来
- 上传、下载功能需要配置上传下载接口域名
小程序和H5互相跳转并传参
- 小程序跳转H5直接在链接之后?拼接参数
-<web-view class="menu" v-if="query" :src="h5Url+'/#/detail?query='+ query"></web-view>
- 跳转参数加密
encodeURIComponent(JSON.stringify(query))
- H5在mounted接收参数并解密
JSON.parse(decodeURIComponent(this.$route.query.query))
- H5跳转小程序
let path = `/page_subject/detail/share?imgURL=${path1}&width=${this.width}&height=${this.height}&id=${this.id}`
wx.miniProgram.navigateTo({
url: path,
success() {
Toast.clear();
},
fail() {
Toast('跳转失败');
}, //小程序地址
});
小程序右上角三个点的分享小程序默认分享好友和朋友圈都是灰色的
- 需要写代码开启
- 如果每个页面都需要分享,写一个公共的js文件,采用MiXin 混入的方式
新建公共share.js文件
export default {
data() {
return {
share: {
title: '快来一起制作新年贺卡吧~',
// bug:require本地图片分包之后图片就显示不出来了
// 不设置图片,默认展示页面
// imageUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg',
path: '/pages/home/index'
}
}
},
onLoad: function() {
wx.showShareMenu({
withShareTicket: true,
menus: ["shareAppMessage", "shareTimeline"]
})
},
onShareAppMessage(res) { //发送给朋友
return {
title: this.share.title,
imageUrl: this.share.imageUrl,
path: this.share.path
}
},
onShareTimeline(res) { //分享到朋友圈
return {
title: this.share.title,
imageUrl: this.share.imageUrl,
path: this.share.path
}
},
}
main.js文件混入
import share from './common/share.js'
Vue.mixin(share)
页面内想单独覆盖分享的文字和图片,可在页面内重写data
data() {
return {
share: {
title: '快来一起制作新年贺卡吧~',
// bug:require本地图片分包之后图片就显示不出来了
// 不设置图片,默认展示页面
// imageUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg',
path: '/pages/home/index'
}
}
},
H5禁止默认的长按转发事件
- 给图片设置
img{ pointer-events:none; }
- 如果图片有点击事件,点击事件不会触发,可以将点击事件加载img的外层盒子上
开启微信小程序图片默认长按事件
- 小程序
<image>
默认没有长按识别事件 - 在图片标签上添加属性
show-menu-by-longpress
图片列表使用骨架屏
- 图片加载过程会出现没有高度,所以效果不是很好
- 监听图片加载@load,加载之前显示灰色骨架屏,加载成功显示图片
- bug:在下拉刷新,重新调取接口后@load不执行
- 解决:下拉刷新,先清空数组,在重新调取接口
<view v-show="!item.isLoading"></view>
<image v-show="item.isLoading" :src="baseUrl + item.img" @load="imgLoad(index)"></image>
// load回调证明图片加载完成
imgLoad(index) {
this.imgList[index].isLoading = true;
},
首页关注我们页面内任意拖动
- movable-area 可以放在最外层
- movable-view是movable-area的直接子元素
- movable-area必须设置宽高,子元素只会在这个区域内移动
- movable-area设置宽高会占位置,可以position: absolute就会不占位置
- movable-view会随着页面向上滚动而上去,使用position: fixed即可不动
<!-- 可拖拽关注 -->
<movable-area :style="{ width:`${screenWidth - 52}px`, height: `${screenHeight - 50}px`}" class="focusBox">
<movable-view :x="screenWidth - 52" :y="screenHeight / 2" direction="all" @click="isFocus = true" class="focus">
<image src="../../static/icon/focus.png" alt="" class="focusImg"></image>
</movable-view>
</movable-area>
.focusBox {
position: absolute;
.focus {
position: fixed;
z-index: 999;
.focusImg {
width: 112rpx;
height: 108rpx;
}
}
小程序编辑页面
http://192.168.2.89:8080/#/detail?query=%7B%22url%22%3A%22%2Fprofile%2Fupload%2F2024%2F01%2F25%2F123_20240125204643A031.jpg%22,%22id%22%3A22%7D
<template>
<view>
<web-view class="menu" v-if="query" :src="h5Url+'/#/detail?query='+ query"></web-view>
</view>
</template>
<script>
import {
h5Url,
} from '../../common/http.js'
export default {
data() {
return {
query: '',
h5Url: '',
}
},
onLoad(options) {
console.log('query', JSON.parse(decodeURIComponent(options.query)))
this.query = options.query
this.h5Url = h5Url
console.log(1111, this.h5Url + '/#/detail?query=' + this.query)
// this.getWidth(url).finally(() => {
// this.query = encodeURIComponent(JSON.stringify({
// url: url,
// width: this.width,
// height: this.height
// }))
// console.log(55555, {
// url: url,
// width: this.width,
// height: this.height
// },
// this.query, h5Url + '/#/detail?query=' + this.query)
// })
},
methods: {
// 获取图片宽高
getWidth(url1) {
let _this = this
return new Promise((resolve, reject) => {
let screenWidth = wx.getSystemInfoSync().windowWidth; // 获取当前窗口的宽度
uni.getImageInfo({
src: url,
success(image) {
console.log(222222, image.width, image.height);
let imgRate = image.width / image.height;
console.log(33333, Number((screenWidth / imgRate).toFixed()));
if (imgRate <= 0.5625) {
_this.width = 315;
_this.height = 560;
} else {
_this.width = screenWidth;
_this.height = Number((screenWidth / imgRate).toFixed());
}
resolve()
},
fail(err) {
console.log(44444, err)
_this.width = 310;
_this.height = 551;
reject()
}
});
})
},
}
}
</script>
<style scoped lang="scss">
</style>
H5编辑页面
<template>
<div class="w100 vh100 flex flex-column bg-black">
<div class="flex_r white bg-black w100 pd-30">
<img src="../assets/img/share.png" alt="" style="width: 18px;margin-right: 6px;">
<div @click="preview">转发</div>
</div>
<div @click.stop="onDeactivated" style="width: 100%; overflow-y: auto;" class="bg-black flex-1">
<!-- :style="{ width: `${width}px`, height: `${height}px` }" -->
<div style="width: 85%;" class="imgBox relative" :class="height > 550 ? 'top' : 'middle'">
<img :src="url" alt="" class="w100 h100" style="display: block;pointer-events:none">
<div v-for="(item, i) in arr" :key="i">
<!-- clicked - 单击组件时
activated - 单击组件时调用,以显示句柄
deactivated - 用户单击组件外部的任何位置时调用,以便将其停用
resizing - 组件调整大小时
resizestop - 组件停止调整大小时
dragging - 拖动组件时
dragstop - 组件停止拖动时调用
@deactivated="onDeactivated"
:parentLimitation="true"
-->
<VueDragResize v-if="item.show" :sticks="['mr', 'br', 'bm', 'bl',]" :isActive="item.isEdit" :w="190" :h="80"
:x="70" :y="200" :z="999" @resizing="resize" @dragging="resize" @clicked="onActivated(i)" contentClass="box"
:style="{ 'left': item.left + 'px', 'top': item.top + 'px', }">
<p class="absolute gushi"
:style="{ 'color': item.color, 'font-size': item.size + 'px', 'opacity': item.opacity / 100, 'font-family': item.family, 'font-weight': item.bold, }">
{{ item.text }}</p>
</VueDragResize>
</div>
<!-- 二维码 -->
<img :src="code" alt="" class="absolute code" :class="width < height ? 'center' : 'right'">
</div>
</div>
<div class="w100 bg-white">
<div class="flex bg pd-30 plr-60" :class="isIos ? 'pb-50' : ''" v-show="!index">
<div @click="add" class="flex_l">
<img src="../assets/img/add.png" alt="" style="width: 16px;height: 16px;">
<div class="ml-6">藏头诗</div>
</div>
<div @click="add1" class="flex_l"><img src="../assets/img/add1.png" alt="" style="width: 22px;height: 22px;">
<div class="ml-6">添加祝福语</div>
</div>
<div @click="changeImg" class="flex_l"><img src="../assets/img/add2.png" alt="" style="width: 22px;height: 22px;">
<div class="ml-6">更换背景</div>
</div>
</div>
<div class="flex bg pd-30" v-show="index">
<div @click="del" class="mr-20 flex_l">
<img src="../assets/img/del.png" alt="" style="width: 18px;height: 18px;">
<div class="ml-6">删除</div>
</div>
<div @click="action = 2" :class="action == 2 ? 'red' : ''" class="mr-20 flex_l">
<img v-if="action == 2" src="../assets/img/edit-1.png" alt="" style="width: 18px;height: 18px;">
<img v-else src="../assets/img/edit.png" alt="" style="width: 18px;height: 18px;">
<div class="ml-6">编辑</div>
</div>
<div @click="action = 3" :class="action == 3 ? 'red' : ''" class="mr-20 flex_l">
<img v-if="action == 3" src="../assets/img/color-1.png" alt="" style="width: 18px;height: 18px;">
<img v-else src="../assets/img/color.png" alt="" style="width: 18px;height: 18px;">
<div class="ml-6">颜色</div>
</div>
<div @click="action = 4" :class="action == 4 ? 'red' : ''" class="mr-20 flex_l">
<img v-if="action == 4" src="../assets/img/size-1.png" alt="" style="width: 18px;height: 18px;">
<img v-else src="../assets/img/size.png" alt="" style="width: 18px;height: 18px;">
<div class="ml-6">样式</div>
</div>
<div v-if="action" @click="finish" class="flex_l">
<img src="../assets/img/finish.png" alt="" style="width: 18px;height: 18px;">
<div class="ml-6">完成</div>
</div>
</div>
<div class="pd-30 pb-40" v-if="action == 1">
<!-- show-word-limit -->
<van-field v-model.trim="message" placeholder="输入藏头词:例如新年快乐(10字以内)" clearable type="textarea" autosize rows="1"
maxlength="10">
<template #button>
<van-button size="small" type="info" class="solo" @click="getPoetry">生成</van-button>
</template>
</van-field>
</div>
<div class="pd-30 pb-40" v-if="action == 2 || action == 5">
<van-field v-model="arr[index].text" placeholder="" clearable type="textarea" autosize rows="1" />
</div>
<div class="pd-30 pb-40" v-if="action == 3">
<div class="flex mr-30 mb-30">
<div>透明度</div>
<van-slider v-model="arr[index].opacity" :min="0" :max="100" style="width: 80%;" active-color="#E94467" />
</div>
<div class="flex flex-wrap">
<div class="mlr-12 mt-4">
<colorPicker v-model="arr[index].color" />
</div>
<div v-for="( color, indexs ) in colors " :key="indexs" class="color-option"
:style="{ backgroundColor: color, border: '1px solid #fff5f6' }" @click="selectColor(color)"
:class="{ active: color === arr[index].color, }"></div>
</div>
</div>
<div class="pd-30 pb-40" v-if="action == 4">
<div class="flex mb-30">
<div>字体大小</div>
<van-slider v-model="arr[index].size" :min="10" :max="80" class="flex-1 mlr-30" active-color="#E94467" />
<div @click="changeBold(arr[index].bold)" :class="{ 'bold': arr[index].bold == 700 }" class="red">加粗</div>
</div>
<div class="flex_l flex-top">
<div class="mr-20">选择字体</div>
<div style="max-height: 100px;overflow-y: auto;" class="flex-1">
<div v-for="(item, i ) in fonts" :key="i" :style="{ 'font-family': 'font-' + (i + 1) }" @click="selectFont(i)"
:class="{ 'size-42 red': 'font-' + (i + 1) === arr[index].family }" class="mb-10">
{{
item }}</div>
</div>
</div>
</div>
<div class="plr-30 pb-40" v-if="action == 5">
<div class="flex_l flex-top">
<div style="max-height: 100px;overflow-y: auto;" class="flex-1">
<div v-for="( item, i ) in texts " :key="i" @click="selectText(item)"
:class="{ 'size-36 red': item === arr[index].text }" class="mb-16">{{
item }}</div>
</div>
</div>
</div>
</div>
<!-- 更换背景图组件 -->
<changeImg ref="changeImgRef" @getImg="getImg"></changeImg>
</div>
</template>
<script>
import { Toast, Dialog } from 'vant';
import wx from 'weixin-js-sdk';
import VueDragResize from 'vue-drag-resize';
import html2canvas from "html2canvas";
import changeImg from '../components/changeImg.vue';
export default {
name: 'app',
components: {
VueDragResize,
changeImg,
},
data() {
return {
id: '', //图片id
url: '', // 背景图
width: 315,
height: 560,
message: "", //藏头诗提示语
arr: [], // 文字
index: '', // 当前编辑的文字索引
action: null, // 1 藏头诗 2 编辑文字 3 颜色 4 样式 5 添加祝福语
// ['#fff', '#000000', '#F9E0C6', '#F4C68C', '#F08400', '#F08080', '#FFA07A', '#F44336', '#E91E63', '#F012BE', '#9C27B0', '#673AB7', '#7B68EE', '#3F51B5', '#2196F3',
// '#03A9F4', '#00BCD4', '#009688', '#2ECC40', '#4CAF50', '#8BC34A', '#FFEB3B',
// '#FFFF00', '#FFDC00', '#FFC107', '#FF851B','#FF5722', '#795548', '#9E9E9E', '#607D8B'],
colors:
['#000000', '#FFFFFF', '#F9E0C6', '#FDF6C0', '#F4C68C', '#FFA07A', '#F08080', '#F08400', '#E85500', '#FEC140', '#E6FF00', '#879D13', '#37A75D', '#2ECC40', '#149125',
'#009688', '#29C2BA', '#298CFE', '#3F51B5', '#7B68EE', '#9C27B0', '#E91E63',
'#FC0015', '#C00503', '#8A1F01', '#940304',],
fonts: [],
texts: ['新年快乐', '新春到了,愿你快乐,幸福平安!', '祝你新年快乐,喜事连连!', '恭祝万事顺,幸福不止步', '春节到来之际,送上我最真挚的祝福:新年快乐!',
'新的一年,祝你永怀善意,清澈明朗,无忧无虑,平安顺遂,吉祥圆满。',
'新年新气象,祝福财气旺,祝君事业有成,合家欢乐,步步高升!',
'岁杪春临,辞旧迎新,专此恭祝:吾师尊长,兄姊好友,新岁维祺,万事胜意。',
'新的一年,愿你永怀善意,清澈明朗,无忧无虑,平安顺遂,吉祥如意。',
'岁末将至,敬颂冬绥 。平安喜乐,万事胜意。岁岁常欢愉,年年皆胜意。',
'日迈月征,朝暮轮转,愿新年胜旧年,欢愉且胜意,万事尽可期。',
'大财,小财,意外财,财源滚滚;亲情,友情,爱情,情情如意官运;福运,财运,桃花运,运运亨通。',
'新的一年,愿你将遇之人皆为挚友,愿你去往之地皆为热土。天高地阔,万事胜意。人海沧沧,顺遂无忧。',
'祝你在新的一年里 无疾病侵扰,无岁月白头,无枯木羁绊。四时春秋平安度过,万千山水得以一游。',
'新年到,放鞭炮:一响鸿运照;二响忧愁抛;三响烦恼消;四响财运到;五响收入高;六响身体好;七响心情妙;八响平安罩;九响幸福绕;十响事业节节高!',
'祈家事平和,花朝月夕多胜意。愿人间芳华,岁岁年年长安康。乐亲朋,岁无忧,新春快乐。',
'裁雪为画,揉风作诗。愿岁月温柔,点点滴滴成全人间悲喜;愿你毕生欢愉,朝朝暮暮造就星河奔腾。'],
imgURL: '',
w: 0,
h: 0,
code: '', // 二维码
isIos: false,
}
},
mounted() {
console.log(this.appSource())
this.isIos = Boolean(this.appSource() == 'ios')
console.log(JSON.parse(decodeURIComponent(this.$route.query.query)))
let query = JSON.parse(decodeURIComponent(this.$route.query.query))
this.url = '/stage-api' + query.url
this.id = query.id
this.getBase64(this.url)
let code = require('../assets/img/code.png')
this.getBase64Code(code)
// 字体
//参数:1.路径;2.是否遍历子目录;3.正则表达式
const files = require.context("../assets/fonts", true).keys();
this.fonts = files.map(item => item.split('-')[1].split('.')[0])
console.log(files.map(item => item.split('-')[1].split('.')[0]));
// ['思源黑体', '包图小白体', '峰广明锐体', '豆豆字体', '站酷庆科黄油体', '锐字真言体', '卓健橄榄简体', '演示悠然小楷', '优设标题黑', '沐瑶随心手写体', '青柳隶书', '演示佛系体', '优设好身体', '优设鲨鱼菲特健康体', '阿朱泡泡体', '阿里巴巴普惠体', '庞门正道标题体', '传奇特战体', '思源宋体', '清松手写体', '龚帆免费体', '851力量体', '赤薔薇灰姑娘', '可愛少女体', '胖胖猪肉体', '千图小兔体']
},
methods: {
//判断安卓和ios
appSource() {
const u = navigator.userAgent;
const isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if (isiOS) {
return "ios";
} else {
return "android";
}
},
getBase64(src) {
var image = new Image();
image.crossOrigin = '*'; // 支持跨域图片
image.src = src + '?v=' + Math.random(); // 处理缓存
image.onload = () => {
var base64 = this.getBase64Image(image);
this.url = base64
}
},
getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
var dataURL = canvas.toDataURL("image/png"); // 可选其他值 image/jpeg
return dataURL;
},
// 本地二维码转base64
getBase64Code(imgUrl) {
window.URL = window.URL || window.webkitURL;
const xhr = new XMLHttpRequest();
xhr.open("get", imgUrl, true);
xhr.responseType = "blob";
xhr.onload = () => {
if (xhr.status == 200) {
//得到一个blob对象
const blob = xhr.response;
const oFileReader = new FileReader();
oFileReader.readAsDataURL(blob);
oFileReader.onloadend = e => {
this.code = e.target.result;//base64编码
};
}
};
xhr.send();
},
add() {
this.action = 1
},
getPoetry() {
if (!this.message) {
this.$toast({
message: '请输入藏头词'
})
} else {
Toast.loading({
message: '生成中...',
forbidClick: true,
});
this.$axios.get('/stage-api/system/management/getMessages?messages=' + this.message).then(res => {
console.log(res.msg)
if (!res.msg) {
Toast.clear();
Dialog.alert({
title: '温馨提示',
message: '未获取到相关藏头,请更换提示语重新生成',
}).then(() => {
// on close
});
} else {
this.message = ''
this.arr.push({
text: res.msg,
color: '#FFFFFF',
size: 24,
opacity: 100,
family: 'font-3',
bold: 400,
isEdit: false,
show: true,
top: 200,
left: 70,
})
this.index = (this.arr.length - 1) + ''
this.action = 2
Toast.clear();
}
})
}
},
add1() {
this.arr.push({
text: '新年快乐',
color: '#FFFFFF',
size: 28,
opacity: 100,
family: 'font-12',
bold: 400,
isEdit: false,
show: true,
top: 200,
left: 70,
})
this.index = (this.arr.length - 1) + ''
this.action = 5
},
changeImg() {
this.$refs.changeImgRef.init()
},
getImg(query) {
this.url = '/stage-api' + query.url
this.id = query.id
this.getBase64(this.url)
},
finish() {
this.onDeactivated()
},
del() {
this.$set(this.arr[this.index], 'show', false)
this.onDeactivated()
},
selectColor(color) {
this.$set(this.arr[this.index], 'color', color)
},
selectFont(i) {
this.$set(this.arr[this.index], 'family', 'font-' + (i + 1))
},
selectText(item) {
this.$set(this.arr[this.index], 'text', item)
},
changeBold(flag) {
this.$set(this.arr[this.index], 'bold', flag == 700 ? 400 : 700)
},
// 拖拽时可以确定元素位置
resize(newRect) {
this.w = newRect.width;
this.h = newRect.height;
this.$set(this.arr[this.index], 'top', newRect.top)
this.$set(this.arr[this.index], 'left', newRect.left)
},
onActivated(i) {
console.log('点击了' + i,)
this.arr.forEach((el, index) => {
if (index == i) {
this.index = i + ''
this.$set(this.arr[index], 'isEdit', true)
this.action = 2
} else {
this.$set(this.arr[index], 'isEdit', false)
}
});
},
onDeactivated() {
this.index = null
this.action = null
this.arr.forEach((el, index) => {
this.$set(this.arr[index], 'isEdit', false)
});
},
preview() {
this.onDeactivated()
Toast.loading({
message: '生成中...',
forbidClick: true,
loadingType: 'spinner',
});
setTimeout(() => {
html2canvas(document.querySelector('.imgBox'), {
backgroudColor: null,
scale: 3, // 1125
}).then(canvas => {
let imgUrl = canvas.toDataURL('image/png');
// console.log(imgUrl);
this.imgURL = imgUrl; //base64格式
// 构建FormData对象,通过该对象存储要上传的文件
const formData = new FormData();
// 遍历当前临时文件List,将上传文件添加到FormData对象中
formData.append('baseName', this.imgURL);
this.$axios.post('/stage-api/system/management/upload', formData)
.then(res => {
console.log(88877, res.fileName)
let path1 = res.fileName
let path = `/page_subject/detail/share?imgURL=${path1}&width=${this.width}&height=${this.height}&id=${this.id}`
wx.miniProgram.navigateTo({
url: path,
success() {
Toast.clear();
},
fail() {
Toast('跳转失败');
}, //小程序地址
});
}).catch(err => {
console.log(999, err)
})
})
}, 100);
},
}
}
</script>
<style scoped lang="scss">
.imgBox {
// margin-left: 30px;
background: #000 url('') no-repeat center center;
background-size: 100% 100%;
&.top {
left: 50%;
top: 0%;
transform: translateX(-50%);
}
&.middle {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.color-option {
width: 60px;
height: 60px;
margin: 8px;
border-radius: 50%;
}
.color-option.active {
border: 2px solid #FFFFFF;
}
::v-deep .m-colorPicker .colorBtn {
width: 50px;
height: 50px;
}
::v-deep .box .vdr-stick {
width: 35px !important;
height: 35px !important;
// background: #E94467;
border: 1px solid #fff;
border-radius: 50%;
background: linear-gradient(221.12deg, #FB3568 0%, #FF8B6B 100%);
&.vdr-stick-br {
bottom: -16px !important;
right: -15px !important;
}
&.vdr-stick-mr {
right: -15px !important;
}
&.vdr-stick-bm {
bottom: -16px !important;
}
&.vdr-stick-bl {
bottom: -16px !important;
}
}
img.code {
width: 100px;
height: 100px;
bottom: 20px;
&.right {
width: 100px;
height: 100px;
right: 20px;
}
&.center {
left: 50%;
transform: translateX(-50%);
}
}
.van-cell {
border: 1px solid #ccc;
}
::v-deep.m-colorPicker {
border: 1px solid #ccc;
}
.gushi {
animation: test 2s;
left: 0;
top: 0;
}
@keyframes test {
0% {
left: 0px;
top: 1000px;
}
50% {
transform: scale(1.5);
left: 0px;
bottom: 300px;
}
// 100% {
// left: 0;
// top: 0;
// }
}
::v-deep .solo.van-button--info {
color: #fff;
background-color: #E94467;
border: 1px solid #E94467;
}
</style>