微信小程序canvas type=2d生成海报保存到相册、文字换行溢出显示...、文字删除线、分享面板
一、简介
做个简单的生成二维码海报分享,我做的时候也找简单的方法看能不能实现页面直接截图那种生成图片,原生小程序不支持,不多介绍下面有全部代码有注释、参数自行替换运行看看,还有需要优化的地方,有问题可以咨询我,我写的已经上线
如图:




二、 js:
// 产品详情
import {getProductDetails,getDataList,getShareData,getUnlimitedQRCode
} from "../../../../../api/dsxapi";
const ui = require("../../../../../utils/ui");Page({data: {id: null, //跳转传过来的产品iddatas: null, //详情数据images: null, //轮播图current: 0,proTags: null, //产品标签images2: null, //详情图片routeId: null, //哪里打开的show: false, //遮罩层showShare: false, //分享面板shareImg: false, //控制分享图标options: [{name: '微信',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_wechat.png',openType: 'share'},{name: '生成分享图',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_fxt.png'},],posterDatas: {width: 281, //画布宽度height: 460, //画布高度// 缓冲区,无需手动设定pic: null,buttonType: 1,show: false, // 显示隐藏跳转设置success: false, // 是否成功生成过海报canvas: null, // 画布的节点ctx: null, // 画布的上下文dpr: 1, // 设备的像素比},QRcodeImg: null, //小程序二维码photoWidth: null //产品图片宽度},onLoad(options) {this.getlength()this.setData({id: options.id})if (options.routeId) {this.setData({routeId: options.routeId})}if (options.scene) { //扫二维码进来的this.setData({id: decodeURIComponent(options.scene).split('id=')[1].split('&')[0],routeId: decodeURIComponent(options.scene).split('routeId=')[1]})}let that = this;//生成海报初始化let posterDatas = that.data.posterDatasconst query = wx.createSelectorQuery()query.select('#firstCanvas').fields({node: true,size: true},function (res) {const canvas = res.nodeconst ctx = canvas.getContext('2d')const dpr = wx.getSystemInfoSync().pixelRatiocanvas.width = posterDatas.width * dprcanvas.height = posterDatas.height * dprctx.scale(dpr, dpr)posterDatas.canvas = canvasposterDatas.ctx = ctxposterDatas.dpr = dpr//存储that.setData({posterDatas})}).exec()this._getProductDetails(this.data.id)},onShow() {// 判断分享打开并且没登录的跳转登录if (this.data.routeId) {if (wx.getStorageSync("appuser") == undefined || wx.getStorageSync("appuser") == '') {wx.navigateTo({url: "/subPackag/pages/me_jump/login/login",});}}this.getlength()this._getProductDetails(this.data.id)this.setData({show: false})},//自定义导航栏计算getlength() {let windowWidth = wx.getSystemInfoSync().windowWidth;const statusBarHeight = wx.getSystemInfoSync().statusBarHeight;const menuButton = wx.getMenuButtonBoundingClientRect();let navHeight = (menuButton.height + (menuButton.top - statusBarHeight) * 2) * (750 / windowWidth);let statusBarTop = statusBarHeight * (750 / windowWidth);this.setData({navHeight: navHeight + statusBarTop,statusBarTop: menuButton.top,})},//自定义返回按钮onBack() {if (this.data.routeId && this.data.routeId == 5 || this.data.routeId == 797 || this.data.routeId == 6) { //5好友里打开797朋友圈打开1未登录点击登录后大师兄页面返回// wx.navigateTo({// url: `/subPackag/pages/consult_jump/EnterprisePiece/market/market`,// });// 判断从分享和扫码打开点击为关闭小程序wx.exitMiniProgram({success: function () {},fail: function () {}})} else {wx.navigateBack();}},//跳转企业/园区详情goEnterprise(event) {if (this.data.datas.type == 2) {//园区wx.navigateTo({url: `/subPackag/pages/consult_jump/EnterprisePiece/park/park?id=${event.currentTarget.dataset.id}`,});} else {//企业wx.navigateTo({url: `/subPackag/pages/consult_jump/EnterprisePiece/enterprise/enterprise?id=${event.currentTarget.dataset.id}`,});}},//跳转案例详情goCase(event) {let params = {type: 4,id: event.currentTarget.dataset.id,};getShareData(params).then((res) => {wx.navigateTo({url: `/sDsxPackag/pages/webview/webview?url=${res.data.shareUrl}&title=${res.data.shareTitle}`})})},//跳转大师兄详情goDSXdetails(event) {getDataList({brotherName: event.currentTarget.dataset.item.realName,current: 1,size: 10}).then((res) => {console.log(1111111111111, res);const nowdata = {item: res.data.records[0],};console.log(111, nowdata);var queryBean = JSON.stringify(nowdata);if (wx.getStorageSync('queryBean') !== undefined) {let qb = wx.getStorageSync("queryBean");qb = queryBean;wx.setStorageSync("queryBean", qb);} else {wx.setStorageSync("queryBean", queryBean);}wx.navigateTo({url: `/sDsxPackag/pages/dsx/dsxcard/dsxcard?queryBean=${encodeURIComponent(queryBean)}`,});});},//产品详情_getProductDetails(id) {let params = {id: id};getProductDetails(params).then((res) => {this.setData({datas: res.data,images: res.data.proImgs.split(","),proTags: res.data.proTags.split(","),images2: res.data.proDetailsImgs.split(","),shareImg: true});}).catch(function (imError) {console.log(imError);})},//客服电话servicePhone() {if (this.data.datas.phone) {wx.makePhoneCall({phoneNumber: this.data.datas.phone})} else {wx.makePhoneCall({phoneNumber: '4001512051'})}},//轮播图预览tapAvatar(event) {console.log(event);wx.previewImage({current: event.currentTarget.dataset.item,urls: this.data.images,})console.log(event);},//轮播数字指示swiperChange(e) {var that = this;if (e.detail.source == 'touch') {that.setData({current: e.detail.current})}},//获取二维码//产品详情_getUnlimitedQRCode() {let params = {id: this.data.id,type: 1,envVersion: 'release' //正式版为 "release",体验版为 "trial",开发版为 "develop};getUnlimitedQRCode(params).then((res) => {const base64 = res.data.qrcode;const time = new Date().getTime();//USER_DATA_PATH:文件系统中的用户目录路径 (本地路径)const imgPath = wx.env.USER_DATA_PATH + "/poster" + time + "" + ".png";const imageData = base64.replace(/^data:image\/\w+;base64,/, "");const file = wx.getFileSystemManager();file.writeFileSync(imgPath, imageData, "base64");console.log(imgPath);this.setData({QRcodeImg: imgPath,});}).catch(function (imError) {console.log(imError);})},//引导打开相册权限取消按钮onClickHide1() {let posterDatas = this.data.posterDatas;posterDatas["buttonType"] = 1;this.setData({show: false,showShare: false,posterDatas,options: [{name: '微信',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_wechat.png',openType: 'share'},{name: '生成分享图',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_fxt.png'},],});},//分享按钮onClick(event) {if (!this.data.QRcodeImg) {//获取二维码this._getUnlimitedQRCode()}//获取产品图片宽度wx.getImageInfo({src: this.data.datas.proCover,success: res => {this.setData({photoWidth: res.width})}})this.setData({showShare: true,options2: [{name: '微信',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_wechat.png',openType: 'share'},{name: '生成分享图',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_fxt.png'},],});},//隐藏分享面板onClose() {this.onIsCanvas()this.data.posterDatas["buttonType"] = 1;this.setData({showShare: false,options: [{name: '微信',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_wechat.png',openType: 'share'},{name: '生成分享图',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_fxt.png'},],});},//分享面板里面的点击事件onSelect(event) {console.log(event);if (event.detail.index == 0) {this.setData({showShare: false})this.onIsCanvas()} else if (event.detail.index == 1) {if (this.data.posterDatas.buttonType == 1) {if (this.data.QRcodeImg) {this.data.posterDatas["buttonType"] = 2;this.onBuildPosterSaveAlbum()this.setData({options: [{name: '微信',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_wechat.png',openType: 'share'},{name: '保存到相册',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_down.png'},]})}} else if (this.data.posterDatas.buttonType == 2) {this.onDownloadImges()this.setData({options: [{name: '微信',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_wechat.png',openType: 'share'},{name: '保存到相册',icon: 'https://wx.applet.style.51dsx.cn/img/share_button_down.png'},]});} else if (this.data.posterDatas.buttonType == 3) {let posterDatas = this.data.posterDatas;posterDatas["show"] = false;this.setData({posterDatas,show: true})}}},//海报生成onBuildPosterSaveAlbum() {let that = this;let posterDatas = that.data.posterDataslet canvas = posterDatas.canvaslet ctx = posterDatas.ctx//已生成过海报的直接显示弹窗if (posterDatas.success) {posterDatas["show"] = true;that.setData({posterDatas})return;}posterDatas.show = true;that.setData({posterDatas})wx.showLoading({title: '海报生成中',mask: true});//二维码let promise1 = new Promise(function (resolve, reject) {const photo = canvas.createImage();photo.src = that.data.QRcodeImg;photo.onload = (e) => {resolve(photo);}});// 背景图let promise2 = new Promise(function (resolve, reject) {const photo = canvas.createImage();photo.src = "https://wx.applet.style.51dsx.cn/img/share_ig_bg.png";photo.onload = (e) => {resolve(photo);}});// 产品图let promise3 = new Promise(function (resolve, reject) {const photo = canvas.createImage();photo.src = that.data.datas.proCover;photo.onload = (e) => {resolve(photo);}});//获取图片信息Promise.all([promise1, promise2, promise3]).then(res => {//背景图ctx.drawImage(res[1], 0, 0, posterDatas.width, posterDatas.height);// 产品图// ctx.drawImage(res[2], 18, 18, posterDatas.width-36, 245);ctx.drawImage(res[2], 0, 0, that.data.photoWidth, that.data.photoWidth, 18, 18, posterDatas.width - 36, posterDatas.width - 36);//二维码ctx.drawImage(res[0], posterDatas.width - 82, posterDatas.height - 82, 64, 64);if (that.data.datas.payType == 2) {//面议ctx.font = "bold 20px sans-serif";ctx.fillStyle = "#EF3822";ctx.fillText('面议', 18, 290);ctx.fill();} else {//现价ctx.font = "14px"; //字体大小ctx.fillStyle = "#EF3822"; //字体颜色ctx.fillText('¥', 18, 290);ctx.font = "bold 20px sans-serif";ctx.fillStyle = "#EF3822";const proPrice = ctx.measureText(that.data.datas.proPrice)ctx.fillText(that.data.datas.proPrice, 26, 290);ctx.fill();// 原价let text = '¥' + that.data.datas.proOriginalPricectx.font = "10px sans-serif";ctx.fillStyle = "#9A9A9A";ctx.fillText(text, proPrice.width + 32, 290);ctx.fillStyle = '#9A9A9A';ctx.beginPath();const textWidth = ctx.measureText(text).width;ctx.rect(proPrice.width + 32, 286, textWidth, 1);ctx.fill();}//地区ctx.font = "10px sans-serif";ctx.fillStyle = "#9A9A9A";//画布宽度减去文字长度ctx.fillText(that.data.datas.serviceAreaText, posterDatas.width - ctx.measureText(that.data.datas.serviceAreaText).width - 18, 290);ctx.fill();//标题ctx.fillStyle = "#333333";ctx.font = "bold 14px sans-serif";// ctx.fillText('专精特新企业股权融资方案设计', 18, 310);that.toFormateStr(ctx, that.data.datas.proName, 245, 1, 18, 312, 16, 1) // 绘制文字并换行ctx.fill();//板块ctx.font = "11px sans-serif";ctx.fillStyle = "#646464";ctx.fillText(that.data.datas.proDesc, 18, 332);ctx.fill();//机构信息ctx.font = "11px";ctx.fillStyle = "#9D9D9D";ctx.fillText('机构信息:' + that.data.datas.institutionName, 18, 352);ctx.fill();//线条ctx.save();ctx.rect(18, 390, 140, 0.5);ctx.strokeStyle = "#9A9A9A"ctx.fill();ctx.font = "10px";ctx.fillStyle = "#9D9D9D";ctx.fillText('实际价格以扫码页面展示为准', 18, 410);ctx.fill();ctx.font = "10px";ctx.fillStyle = "#9D9D9D";ctx.fillText('长按识别查看、联系', 18, 426);ctx.fill();// 关闭loadingwx.hideLoading();//显示海报posterDatas.success = true;that.setData({posterDatas})}).catch(err => {console.log(err)wx.hideLoading();wx.showToast({icon: 'none',title: '海报生成失败,请稍后再试.',})})},// 文字换行toFormateStr(ctx, str, draw_width, lineNum, startX, startY, steps, number) {//ctx:canvas的 2d 对象,str:绘制的文字,startX,startY:文字坐标,draw_width:文字最大宽度,lineNum:需要的行数,steps:行高,number:减少最后几个字变成...let strWidth = ctx.measureText(str).width; // 测量文本源尺寸信息(宽度)let startpoint = startY,keyStr = '',sreLN = strWidth / draw_width; // 文本长度除以换行的宽 得到一共生成多少行let liner = Math.ceil(sreLN); // 计算文本源一共能生成多少行let strlen = parseInt(str.length / sreLN); // 等比缩放测量一行文本显示多少个字符// 若文本不足一行,则直接绘制,反之大于传入的最多行数(lineNum)以省略号(...)代替if (strWidth < draw_width) {ctx.fillText(str, startX, startpoint);} else {for (let i = 1; i < liner + 1; i++) {let startPoint = strlen * (i - 1);if (i < lineNum || lineNum == -1) {keyStr = str.substr(startPoint, strlen);ctx.fillText(keyStr, startX, startpoint);} else {keyStr = str.substr(startPoint, strlen - number) + '...';ctx.fillText(keyStr, startX, startpoint);break;}startpoint = startpoint + steps;}}},//画布转图片onCanvasBuildImges() {let that = this;let posterDatas = that.data.posterDatas;wx.canvasToTempFilePath({canvas: posterDatas.canvas,width: posterDatas.width,height: posterDatas.height,// destWidth: posterDatas.width * 3,// destHeight: posterDatas.height * 3,quality: 1,success: function success(res) {posterDatas["pic"] = res.tempFilePath;that.setData({posterDatas})that.onDownloadImges();},fail: function complete(e) {wx.hideLoading();wx.showToast({icon: 'none',title: 'sorry 保存失败,请稍后再试.',})return;}});},//下载图片onDownloadImges() {wx.showLoading({title: '保存中',mask: true});let that = this;let posterDatas = that.data.posterDatas;if (!posterDatas.pic) {that.onCanvasBuildImges();return;}wx.saveImageToPhotosAlbum({filePath: posterDatas.pic,success(res) {wx.hideLoading();wx.showToast({icon: 'none',title: '已保存到相册',})that.onIsCanvas()posterDatas["buttonType"] = 1;that.setData({showShare: false,posterDatas})},fail: function (res) {wx.hideLoading();wx.showToast({icon: 'none',title: '已取消',})posterDatas["buttonType"] = 3;that.setData({posterDatas})return;}})},//在打开授权设置页后回调onBindOpenSetting() {let that = this;let posterDatas = that.data.posterDatas;posterDatas["buttonType"] = 1;that.setData({posterDatas})},//隐藏海报onIsCanvas() {let that = this;let posterDatas = that.data.posterDatas;posterDatas["buttonType"] = 1;posterDatas["show"] = false;that.setData({posterDatas})},onShareAppMessage: function (res) { //分享给好友var that = thisreturn {title: that.data.datas.proName + '—产品详情',path: 'subPackag/pages/consult_jump/EnterprisePiece/product/product?id=' + that.data.datas.id + '&routeId=' + 5,imageUrl: '',success: function (res) {console.log(res);wx.showToast({title: '分享成功',icon: "none"});},fail: function (res) {wx.showToast({title: '分享失败',icon: "none"})}}},onShareTimeline: function () { //分享朋友圈var tha = thisreturn {title: tha.data.datas.proName + '—产品详情',query: 'id=' + tha.data.datas.id + '&routeId=' + 797,imageUrl: tha.data.datas.proCover,success: function (res) {wx.showToast({title: '分享成功',icon: "none"});},fail: function (res) {wx.showToast({title: '分享失败',icon: "none"})}}},
})
三、 wxml:
<!-- 自定义导航 -->
<view class="nav-back" style="height: {{navHeight}}rpx;"><image class="imgbackw" style="margin-top: {{statusBarTop}}px" src="https://wx.applet.style.51dsx.cn/img/icon_navigation_return.png" catchtap="onBack" /><view class="nav-name" style="margin-top: {{statusBarTop}}px">产品详情</view>
</view><view class="product" wx:if="{{datas}}" style="margin-top: {{navHeight}}rpx;"><!-- 轮播 --><view wx:if="{{images[0]!==''}}" class="swiper1" style="overflow: hidden;"><swiper bindchange="swiperChange" class="swiper" indicator-active-color="white" current="0" indicator-color="#fff6" display-multiple-items circular="{{true}}"><swiper-item wx:for="{{images}}" wx:key="index"><image data-item="{{item}}" bindtap="tapAvatar" src="{{item}}" mode="aspectFill" /></swiper-item></swiper><view class="imageCount" wx:if="{{images.length>1}}">{{current+1}}/{{images.length}}</view></view><view class="middle"><view class="price"><view class="price-div"><!-- 价钱、地区 --><view style="display: inline-block;">{{ datas.payType == 2 ? "" : "¥"}}<span class="item1">{{datas.payType == 2 ? "面议" : datas.proPrice}}</span><span class="item3">{{datas.payType == 2 || datas.proOriginalPrice == 0? "": "¥" + datas.proOriginalPrice}}</span></view><view class="area">{{datas.serviceAreaText}}</view></view><view class="info"><!-- 标题、板块、标签 --><view class="item1">{{ datas.proName }}</view><view class="item2" wx:if="{{datas.proDesc}}">{{ datas.proDesc }}</view><view wx:if="{{proTags[0]!==''}}"><view class="item3" wx:for="{{proTags}}" wx:key="index">{{item}}</view></view></view></view><view class="institution"><view class="title">机构信息</view><!-- 机构信息 --><view class="info2" data-id="{{datas.companyId}}" bindtap="goEnterprise"><image src="{{datas.institutionLogo}}" class="img1" mode="aspectFit" /><view class="right"><view class="item1">{{ datas.institutionName }}</view><view class="item2">{{ datas.institutionAddress }}</view></view></view><view wx:if="{{datas.userNames.length > 0}}"><!-- 大师兄左右滑动列表 --><van-divider customStyle="margin:0;" /><view class="BigMasterBox"><view class="BigMasterItem" data-item="{{item}}" bindtap="goDSXdetails" wx:for="{{datas.userNames}}" wx:key="index"><image src="{{item.photo}}" class="img" mode="aspectFill"/><view class="right"><view class="item1">{{ item.realName }}</view><view class="{{item.online == 1 ? 'item2' : 'red'}}">{{item.online == 1? "可咨询": "可预约"}}</view><view class="item3">{{ item.roleName }} |{{ item.unitStartTimeText }}</view></view></view></view><view class="prompt">以上大师兄由产品方所列,由用户自主选择</view></view></view><view class="case" wx:if="{{datas.serviceNames.length > 0}}"><view class="title">服务案例</view><view class="caseBox"><view class="caseItem" data-id="{{item.id}}" bindtap="goCase" wx:for="{{datas.serviceNames}}" wx:key="index"><!-- 案例左右滑动列表 --><image src="https://wx.applet.style.51dsx.cn/img/store_icon_fwal.png" class="img" mode='widthFix' /><view class="right"><view class="item1">{{ item.customerName }}</view><view class="item2">{{ item.sectionText }}</view><view class="item2">{{ item.serviceTime }}年</view></view></view></view></view><view class="details"><view class="median"></view><span> 产品详情 </span><view class="median"></view></view></view><!-- 产品介绍长图列 --><view class="introduce">{{ datas.proDetails }}</view><image wx:if="{{images2[0]!==''}}" class="img3" wx:for="{{images2}}" wx:key="index" src="{{item}}" mode='widthFix' /><view class="bottomBox"><view class="FixedBottom"><view><!-- <view class="item1" bindtap="servicePhone"><image class="img" src="https://image-cos.51dsx.cn/images/2023-05-08/store_button_service.png" /><view class="text">客服</view></view> --><view class="item2" data-id="{{datas.companyId}}" bindtap="goEnterprise"><image class="img" src="https://image-cos.51dsx.cn/images/2023-05-08/store_button_store.png" /><view class="text">店铺</view></view></view><view class="item3" bindtap="servicePhone">联系机构</view></view></view>
</view>
<!-- 海报 -->
<view class="canvasMain" hidden="{{!posterDatas.show}}"><canvas type="2d" id="firstCanvas" class="firstCanvas" style="width:{{posterDatas.width}}px;height:{{posterDatas.height}}px;"></canvas>
</view>
<!-- 分享图标 -->
<image wx:if="{{shareImg}}" class="shareImg" bindtap="onClick" src="https://wx.applet.style.51dsx.cn/img/xiangqing_button_share.png" mode="aspectFill" />
<!-- 弹窗去打开相册权限 -->
<van-overlay z-index="999999" show="{{ show }}"><view class="wrapper"><view class="block" catch:tap="noop"><view class="popup-box"><view class="telephone">进入设置页,开启“保存到相册”</view><van-divider customStyle="margin:0;" /><view class="ncontent"><button class='button' bindtap='onClickHide1'>取消</button><button class='button' open-type='openSetting' bindopensetting='onBindOpenSetting'>确定</button></view></view></view></view>
</van-overlay>
<!-- 分享面板 -->
<van-share-sheet show="{{ showShare }}" title="" options="{{ options }}" bind:select="onSelect" bind:close="onClose" />
四、wxss:
.nav-back {position: fixed;top: 0;left: 0;width: 100vw;text-align: center;background: #fff;z-index: 9999999;
}.nav-back .nav-name {font-size: 32rpx;font-family: PingFang SC-Semibold, PingFang SC;font-weight: 600;color: #000000;line-height: 40rpx;width: 100%;color: #000;height: 60rpx;line-height: 60rpx;
}.imgbackw {width: 60rpx;height: 60rpx;position: absolute;left: 0rpx;z-index: 100;
}.imageCount {padding: 4rpx 20rpx;font-size: 24rpx;border-radius: 40rpx;background-color: rgba(0, 0, 0, 0.6);color:#fff;position:absolute;right:16rpx;bottom:16rpx;
}
.swiper1 {width: 100vw;height: 100vw;transform: translateY(0);
}/* 广告轮播图 */
.swiper {/*再设置个transform的属性*/transform: translateY(0);}.swiper image,
.swiper {width: 100vw;height: 100vw;
}.swiper swiper-item {position: relative;
}
.product {padding-bottom: 164rpx;width: 100%;height: auto;
}.product .FixedBottom .item3 {/* width: 2.47rpx; *//* width: 70%; */width: 88%;height: 88rpx;background: linear-gradient(138deg, #5092f7 0%, #3171e8 100%);border-radius: 80rpx;line-height: 88rpx;font-size: 32rpx;font-weight: 500;color: #ffffff;
}.product .FixedBottom .img {width: 48rpx;height: 48rpx;
}.product .FixedBottom .text {font-size: 24rpx;font-weight: 400;color: #000000;line-height: 36rpx;
}.product .FixedBottom .item1,
.product .FixedBottom .item2 {font-size: 24rpx;color: #000000;line-height: 36rpx;
}.product .FixedBottom .item1,
.product .FixedBottom .item2,
.product .FixedBottom .item3 {display: inline-block;text-align: center;
}.product .bottomBox {width: 100%;background: #fff;position: fixed;left: 50%;transform: translate(-50%, 0);bottom: 0;padding: 20rpx 0rpx 52rpx 0rpx;border-top: 1px solid rgb(247, 246, 246);
}.product .FixedBottom {display: flex;justify-content: space-between;align-items: center;padding: 0 24rpx 0rpx 40rpx;/* margin: 0 auto; */
}.product .img3 {width: 100vw;
}.product .introduce {padding: 20rpx;font-size: 28rpx;color: #444444;line-height: 42rpx;
}/* 内容 价钱信息、机构、案例 */
.middle .details span {margin: 0 20rpx;
}.middle .details .median {display: inline-block;width: 96rpx;border-bottom: #d8d8d8 2rpx solid;
}.middle .details {width: 100%;display: flex;justify-content: center;align-items: center;margin-top: 40rpx;
}.middle .case .caseBox .caseItem .right .item2 {font-size: 24rpx;color: #6f6f6f;line-height: 36rpx;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;
}.middle .case .caseBox .caseItem .right .item1 {font-size: 28rpx;font-weight: 600;color: #000000;line-height: 40rpx;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;
}.middle .case .caseBox .caseItem .right {margin-left: 20rpx;
}.middle .case .caseBox .caseItem .img {width: 112rpx;min-width: 112rpx;height: 112rpx;border-radius: 12rpx;
}.middle .case .caseBox .caseItem {display: flex;align-items: center;margin-right: 16rpx;flex-shrink: 0;background: #f6f6f6;border-radius: 8rpx;height: 160rpx;padding: 0rpx 20rpx;min-width: 400rpx;max-width: 400rpx;
}.middle .case .caseBox .caseItem:last-child {margin-right: 0 !important;
}.middle .case .caseBox {border-radius: 12rpx;/* padding: 0.12rpx 0.1rpx; *//* 设置超出滚动 */overflow-x: auto;display: flex;justify-content: space-between;margin-top: 20rpx;
}.product .middle .case {margin-top: 16rpx;padding: 28rpx 20rpx 20rpx 20rpx;background: #fff;border-radius: 20rpx;border: 2rpx solid #ffffff;
}::-webkit-scrollbar {/* 隐藏滚动条 */display: none;
}.BigMasterItem .right {display: inline-block;font-size: 24rpx;color: #000000;line-height: 32rpx;margin-left: 8rpx;}.product .middle .institution .BigMasterBox .BigMasterItem .img {width: 60rpx;height: 60rpx;border-radius: 30rpx;object-fit: cover;
}.product .middle .institution .prompt {margin-top: 16rpx;font-size: 24rpx;color: #9a9a9a;line-height: 36rpx;
}.product .middle .institution .BigMasterBox .BigMasterItem:last-child {margin-right: 0 !important;
}.product .middle .institution .BigMasterBox .BigMasterItem .item1 {display: inline-block;font-size: 28rpx;font-weight: 600;color: #444444;line-height: 36rpx;
}.product .middle .institution .BigMasterBox .BigMasterItem .red {margin-left: 8rpx;display: inline-block;padding: 0 8rpx;height: 32rpx;background: #3a89ff;color: #fff;font-size: 24rpx;line-height: 32rpx;border-radius: 8rpx;
}.product .middle .institution .BigMasterBox .BigMasterItem .item2 {margin-left: 8rpx;display: inline-block;padding: 0 8rpx;height: 32rpx;background: #4dc741;color: #fff;font-size: 24rpx;line-height: 32rpx;border-radius: 8rpx;
}.product .middle .institution .BigMasterBox .BigMasterItem .item3 {margin-top: 4rpx;font-size: 24rpx;color: #9a9a9a;line-height: 28rpx;
}.BigMasterItem {display: flex;align-items: center;margin-right: 16rpx;flex-shrink: 0;background: #f3f8ff;border-radius: 16rpx;padding: 28rpx 24rpx;
}.BigMasterBox {/* 设置超出滚动 */overflow-x: auto;display: flex;justify-content: space-between;margin-top: 20rpx;
}::v-deep .el-divider--horizontal {margin: 0;background-color: #e5e5e5 !important;
}.product .middle .institution .info2 {margin-top: 24rpx;margin-bottom: 24rpx;display: flex;align-items: center;
}.product .middle .institution .img1 {display: inline-block;width: 88rpx;min-width: 88rpx;max-height: 88rpx;border-radius: 12rpx;border: 1rpx solid #ededed;
}.product .middle .institution .info2 .right {margin-left: 16rpx;display: inline-block;
}.product .middle .institution .info2 .right .item1 {font-size: 32rpx;font-weight: 600;color: #000000;line-height: 40rpx;
}.product .middle .institution .info2 .right .item2 {margin-top: 6rpx;font-size: 26rpx;color: #9a9a9a;line-height: 36rpx;min-height: 36rpx;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;
}.product .middle .institution {margin-top: 16rpx;padding: 28rpx 20rpx 20rpx 20rpx;background: linear-gradient(180deg, #e0edff 0%, #ffffff 23%, #ffffff 100%);border-radius: 20rpx;border: 2rpx solid #ffffff;
}.product .middle .institution .title,
.product .middle .case .title {font-size: 30rpx;font-weight: 600;color: #000000;line-height: 40rpx;
}.product .middle .info .item1 {width: 100%;font-size: 32rpx;font-weight: 600;color: #333333;line-height: 48rpx;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;
}.product .middle .info .item2 {width: 100%;font-size: 26rpx;color: #868686;line-height: 40rpx;margin-top: 8rpx;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;margin-bottom: 8rpx;
}.product .middle .info .item3 {display: inline-block;height: 32rpx;font-size: 24rpx;color: #9a9a9a;line-height: 32rpx;background: #f7f7f7;border-radius: 4rpx;padding: 0 12rpx;margin-right: 20rpx;
}.product .middle .info .item3:last-child {margin-right: 0 !important;
}.custom-indicator {position: absolute;right: 16rpx;bottom: 16rpx;padding: 4rpx 20rpx;font-size: 24rpx;border-radius: 40rpx;color: #fff;background: rgba(0, 0, 0, 0.6);
}.swipeItem {height: 100vw;width: 100%;
}.itemImg {height: 100%;width: 100%;object-fit: cover;background-color: #f2f2f2;
}.product .middle {padding: 16rpx 12rpx 24rpx;background: #f7f7f7;
}.product .middle .price {background: #fff1f1;border-radius: 20rpx;padding: 16rpx 0 0;
}.product .middle .info {padding: 28rpx 20rpx 32rpx 20rpx;border-radius: 20rpx;background: #fff;
}.middle .price .price-div {margin-bottom: 12rpx;margin-left: 20rpx;color: #ef3822;font-size: 28rpx;position: relative;
}.middle .price .price-div .area {font-size: 26rpx;color: #808080;display: inline-block;position: absolute;right: 20rpx;top:50%;transform:translate(0,-50%);line-height: 80rpx;
}.middle .price .price-div .item1 {color: #ef3822;font-size: 44rpx;font-weight: 600;
}.middle .price .price-div .item2 {color: #ef3822;font-size: 24rpx;
}.middle .price .price-div .item3 {text-decoration: line-through;margin-left: 20rpx;color: #9a9a9a;font-size: 24rpx;
}/* 生成海报 */
.shareImg{width: 100rpx;height: 100rpx;position: fixed;right: 14rpx;top: 80%;z-index: 99;
}
.popup-box {position: fixed;top: 50vh;left: 50vw;transform:translate(-50%,-50%);width: 62vw;background:#fff;border-radius: 16rpx;opacity: 1;margin: auto;text-align: center;padding: 34rpx 32rpx 36rpx;
}
.telephone{margin-bottom: 20rpx;
}
.canvasMain{position: fixed;top: 8vh;width: 100vw;z-index: 999999 !important;
}
.firstCanvas{margin: 5vh auto 0;z-index: 9999 !important;
}
.ncontent{margin-top: 20rpx;display: flex;justify-content: space-between;
}.van-share-sheet__cancel {font-size: 32rpx !important;
}.van-share-sheet__name{font-size: 26rpx !important;color: #333333 !important;
}
.van-share-sheet__header, .van-share-sheet__options{background: #F5F5F5;
}
.van-share-sheet__icon {width: 128rpx !important;height: 128rpx !important;
}
.van-share-sheet__cancel:before{background-color: #F5F5F5 !important;
}相关文章:
微信小程序canvas type=2d生成海报保存到相册、文字换行溢出显示...、文字删除线、分享面板
一、简介 做个简单的生成二维码海报分享,我做的时候也找简单的方法看能不能实现页面直接截图那种生成图片,原生小程序不支持,不多介绍下面有全部代码有注释、参数自行替换运行看看,还有需要优化的地方,有问题可以咨询…...
C++卷积神经网络
C卷积神经网络 #include"TP_NNW.h" #include<iostream> #pragma warning(disable:4996) using namespace std; using namespace mnist;float* SGD(Weight* W1, Weight& W5, Weight& Wo, float** X) {Vector2 ve(28, 28);float* temp new float[10];V…...
go 读取yaml映射到struct
安装 go get gopkg.in/yaml.v3创建yaml Mysql:Host: 192.168.214.134Port: 3306UserName: wwPassword: wwDatabase: go_dbCharset: utf8mb4ParseTime: trueLoc: LocalListValue:- haha- test- vv JWTSecret: nidaye定义结构体 type Mysql struct {Host string yaml:&…...
Redis 10 大数据类型
1. which 10 1. redis字符串 2. redis 列表 3. redis哈希表 4. redis集合 5. redis有序集合 6. redis地理空间 7. redis基数统计 8. redis位图 9. redis位域 10. redis流 2. 获取redis常见操作指令 官网英文:https://redis.io/commands 官网中文:https:/…...
优化生产流程:数字化工厂中的OPC UA分布式IO模块应用
背景 近年来,为了提升在全球范围内的竞争力,制造企业希望自己工厂的机器之间协同性更强,自动化设备采集到的数据能够发挥更大的价值,越来越多的传统型工业制造企业开始加入数字化工厂建设的行列,实现智能制造。 数字化…...
Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索
一、前言 不同于之前的term。terms等结构化查询,全文搜索首先对查询词进行分析,然后根据查询词的分词结果构建查询。这里所说的全文指的是文本类型数据(text类型),默认的数据形式是人类的自然语言,如对话内容、图书名…...
已解决Gradle错误:“Unable to load class ‘org.gradle.api.plugins.MavenPlugin‘”
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
windows中安装sqlite
1. 下载文件 官网下载地址:https://www.sqlite.org/download.html 下载sqlite-dll-win64-x64-3430000.zip和sqlite-tools-win32-x86-3430000.zip文件(32位系统下载sqlite-dll-win32-x86-3430000.zip)。 2. 安装过程 解压文件 解压上一步…...
前端面试:【系统设计与架构】前端架构模式的演进
前端架构模式在现代Web开发中扮演着关键角色,它们帮助我们组织和管理前端应用的复杂性。本文将介绍一些常见的前端架构模式,包括MVC、MVVM、Flux和Redux,以及它们的演进和应用。 1. MVC(Model-View-Controller)&#x…...
【CSS】em单位的理解
1、em单位的定义 MDN的解释:它是相对于父元素的字体大小的一个单位。 例如:父元素font-size:16px;子元素的font-size:2em(也就是32px) 注:有一个误区,虽然他是一个相对…...
无涯教程-Python机器学习 - Based on human supervision函数
Python机器学习 中的 Based on human s - 无涯教程网无涯教程网提供https://www.learnfk.com/python-machine-learning/machine-learning-with-python-based-on-human-supervision.html...
【滑动窗口】leetcode209:长度最小的子数组
一.题目描述 长度最小的子数组 二.思路分析 题目要求:找出长度最小的符合要求的连续子数组,这个要求就是子数组的元素之和大于等于target。 如何确定一个连续的子数组?确定它的左右边界即可。如此一来,我们最先想到的就是暴力枚…...
C++ STL unordered_map
map hashmap 文章目录 Map、HashMap概念map、hashmap 的区别引用头文件初始化赋值unordered_map 自定义键值类型unordered_map 的 value 自定义数据类型遍历常用方法插入查找 key修改 value删除元素清空元素 unordered_map 中每一个元素都是一个 key-value 对,数据…...
全流程R语言Meta分析核心技术应用
Meta分析是针对某一科研问题,根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法,对来源不同的研究成果进行收集、合并及定量统计分析的方法,最早出现于“循证医学”,现已广泛应用于农林生态,资源环境等方面。…...
Go并发可视化解释 - Select语句
昨天,我发布了一篇文章,用可视化的方式解释了Golang中通道(Channel)的工作原理。如果你对通道的理解仍然存在困难,最好呢请在阅读本文之前先查看那篇文章。作为一个快速的复习:Partier、Candier 和 Stringe…...
在线SM4(国密)加密解密工具
在线SM4(国密)加密解密工具...
golang的类型断言语法
例子1 在 Go 中,err.(interface{ Timeout() bool }) 是一个类型断言语法。它用于检查一个接口类型的变量 err 是否实现了一个带有 Timeout() bool 方法的接口。 具体而言,该类型断言的语法如下: if v, ok : err.(interface{ Timeout() boo…...
提速换挡 | 至真科技用技术打破业务壁垒,助力出海破局增长
各个行业都在谈出海,但真正成功的又有多少? 李宁出海十年海外业务收入占比仅有1.3%,走出去战略基本失败。 京东出海业务磕磕绊绊,九年过去国际化业务至今在财报上都不配拥有姓名。 几百万砸出去买量,一点水花都没有…...
第3篇:vscode搭建esp32 arduino开发环境
第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 1.下载vscode并安装 https://code.visualstudio.com/ 运行VSCodeUserSetup-x64-1.80.1.exe 2.点击扩展,搜索arduino,并点击安装 3.点击扩展设置,配置arduino…...
Apache Shiro是什么
特点 Apache Shiro是一个强大且易用的Java安全框架,用于身份验证、授权、会话管理和加密。它的设计目标是简化应用程序的安全性实现,使开发人员能够更轻松地处理各种安全性问题,从而提高应用程序的安全性和可维护性。下面是一些Apache Shiro的关键特点和概念: 特点和概念…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
