canvas(uniapp + wx小程序)
1 <template> 2 <view> 3 <rich-text :nodes="string"></rich-text> 4 <!-- canvas --> 5 <canvas class="canvas" canvas-id="myCanvas" style="border: 1px solid; 750rpx;height: 2050rpx;"></canvas> 6 <!-- <image src="" mode=""></image> --> 7 <button type="default" @click="baocun()">保存</button> 8 </view> 9 </template> 10 11 <script> 12 export default { 13 data() { 14 return { 15 string: '<div style="color:#ff0000;"><img src="../../static/003.jpg" style=""></img></div>' 16 } 17 }, 18 onShow: function() { 19 // this.string=this.string.replace("<html>","") 20 21 //控制小程序中图片大小,正则表达式匹配style,改变其宽度 22 let newContent = this.string.replace(/<img[^>]*>/gi, function(match, capture) { 23 // console.log(match.search(/style=/gi)); 24 25 if (match.search(/style=/gi) == -1) { 26 match = match.replace(/<img/gi, '<img style=""'); 27 } 28 return match; 29 }); 30 newContent = newContent.replace(/style="/gi, '$& max-100% !important; '); 31 newContent = newContent.replace(/<br[^>]*/>/gi, ''); 32 33 this.string = newContent; 34 35 36 37 38 // canvas 39 const ctx = uni.createCanvasContext('myCanvas', this); 40 // 笔触的颜色 41 ctx.strokeStyle = "#0000ff"; 42 43 // 保存设置 44 ctx.save(); 45 46 47 // 第一张图片 48 ctx.drawImage('../../static/003.jpg', 0, 0, 300, 150); 49 50 // 第二张图片 51 ctx.drawImage('../../static/004.png', 0, 0, 100, 100); 52 53 // 文字 54 ctx.setFillStyle('#000000') //文字颜色:默认黑色 55 // ctx.setFontSize(48) //设置字体大小,默认10 56 // ctx.textAlign = 'center' // 设置文字位置 居中 57 ctx.font = 'bold 36px sans-serif'; // 字体样式 58 ctx.fillText('这是文字的位置', 20, 180); //文字的具体内容以及位置 59 ctx.strokeText("实例", 20, 230) 60 61 // 设置两个图像的样式(样式很多,参考globalCompositeOperation的属性) 62 ctx.globalCompositeOperation = 'destination-out'; 63 ctx.globalCompositeOperation = "source-over"; 64 ctx.restore(); //返回上次保存的属性 65 66 67 // 绘制圆形 68 ctx.beginPath(); //开始绘图 69 // ctx.arc(80,300,80,0,Math.PI*2) //圆形(x轴,y轴,半径,开始的点,结束的点),x轴与y轴的位置以 中心点 为准 70 ctx.stroke(); //结束绘图,与开始绘图相对应,必须有 71 72 // 绘制圆角矩形 73 ctx.beginPath(); 74 75 // 左上角 76 ctx.arc(100, 300, 10, Math.PI * 1, Math.PI * 1.5) 77 // 上线 78 ctx.moveTo(100, 290) 79 ctx.lineTo(160, 290) 80 81 // 右上角 82 ctx.arc(160, 300, 10, Math.PI * 1.5, Math.PI * 2) 83 // 右线 84 ctx.moveTo(170, 300) 85 ctx.lineTo(170, 350) 86 87 // 右下角 88 ctx.arc(160, 350, 10, Math.PI * 0, Math.PI * 0.5) 89 // 下线 90 ctx.moveTo(160, 360) 91 ctx.lineTo(100, 360) 92 93 // 左下角 94 ctx.arc(100, 350, 10, Math.PI * 0.5, Math.PI * 1) 95 ctx.moveTo(90, 350) 96 ctx.lineTo(90, 300) 97 ctx.closePath() 98 // ctx.clip() //剪切, 99 // ctx.setFillStyle("#007AFF") 100 // ctx.fillRect(80,280,100,100) 101 ctx.drawImage('../../static/003.jpg', 80, 280, 100, 80); 102 // ctx.globalCompositeOperation='destination-out'; 103 104 105 ctx.stroke(); 106 107 108 109 110 // 圆角矩形 111 ctx.restore(); //返回上次保存的属性 112 ctx.beginPath(); 113 ctx.moveTo(190, 380); 114 ctx.lineTo(260, 380); 115 ctx.arcTo(280, 380, 280, 400, 20); 116 ctx.lineTo(280, 460); 117 ctx.arcTo(280, 480, 260, 480, 20); 118 ctx.lineTo(190, 480); 119 ctx.arcTo(170, 480, 170, 450, 20); 120 ctx.lineTo(170, 400); 121 ctx.arcTo(170, 380, 190, 380, 20); 122 ctx.clip() //剪切, 123 // ctx.fillRect(170,380,140,100) 124 ctx.drawImage('../../static/003.jpg', 170, 380, 140, 100); 125 ctx.stroke(); 126 127 128 129 ctx.draw() //绘制图像到canvas里面, 必须有 130 }, 131 132 methods: { 133 baocun() { 134 uni.canvasToTempFilePath({ // 把画布转化成临时文件 135 x: 0, 136 y: 0, 137 750, // 截取的画布的宽 138 height: 1500, // 截取的画布的高 139 destWidth: 750, // 保存成的画布宽度 140 destHeight: 1500, // 保存成的画布高度 141 fileType: 'png', // 保存成的文件类型 142 quality: 1, // 图片质量 143 canvasId: 'myCanvas', // 画布ID 144 success(res) { 145 // 2-保存图片至相册 146 uni.saveImageToPhotosAlbum({ // 存成图片至手机 147 filePath: res.tempFilePath, 148 success(res2) { 149 wx.hideLoading(); 150 uni.showToast({ 151 title: '图片保存成功,可以去分享啦~', 152 duration: 2000 153 }) 154 // _this.canvasCancelEvn(); 155 }, 156 fail(res3) { 157 if (res3.errMsg === 'saveImageToPhotosAlbum:fail auth deny') { 158 // _this.$store.dispatch('SetPhoneShow',1) 159 uni.showToast({ 160 title: '保存失败,稍后再试', 161 duration: 2000, 162 icon: 'none' 163 }) 164 wx.hideLoading(); 165 } else { 166 uni.showToast({ 167 title: '保存失败,稍后再试', 168 duration: 2000, 169 icon: 'none' 170 }) 171 wx.hideLoading(); 172 } 173 } 174 }) 175 }, 176 fail() { 177 uni.showToast({ 178 title: '保存失败,稍后再试', 179 duration: 2000, 180 icon: 'none' 181 }) 182 wx.hideLoading(); 183 } 184 }) 185 } 186 } 187 } 188 </script> 189 190 <style> 191 192 </style>
购物车加减(uniapp)(参考方法就好)
1 <template style="height: 100%;"> 2 <view class="page"> 3 <toptars :nav='nav'></toptars> 4 <view class="CartK" v-if="flag"> 5 <view class="CartKBox"> 6 <image src="../../static/img/gwc.png" mode=""></image> 7 <text>购物车空空如也</text> 8 </view> 9 </view> 10 <view class="CartM" v-else="!flag"> 11 <view class="CartTop" @click="tabDelete"> 12 <text>{{Delete==false?'编辑商品':'完成'}}</text> 13 </view> 14 <view class="CartCon"> 15 <view class="CartConList" v-for="(item,index) in shangpin" :key="index"> 16 <view class="CartConListLeft"> 17 <checkbox-group @change="selected(item)"> 18 19 <checkbox style="transform:scale(0.7)" :checked="item.flag" /> 20 21 </checkbox-group> 22 </view> 23 <view class="CartConListRight"> 24 <view class="CartImg"> 25 <image src="../../static/image/banner3.png" mode=""></image> 26 </view> 27 <view class="CartTxt"> 28 <view class="CartTxtTop"> 29 <text>{{item.title}}</text> 30 <view class="shanchu" @click="shanchu(item,index)"> 31 删除 32 </view> 33 </view> 34 <view class="CartTxtBot"> 35 <view class="CartTxtBotPrice"> 36 <text>¥{{item.price}}</text> 37 </view> 38 <view class="CartTxtBotNum"> 39 <text class="NumReduce" @click="NumReduce(item)">-</text> 40 <text>{{item.nums}}</text> 41 <text class="NumAdd" @click="NumAdd(item)">+</text> 42 本 43 </view> 44 </view> 45 </view> 46 </view> 47 </view> 48 </view> 49 <view class="CartBot"> 50 <view class="CartBotLeft"> 51 <checkbox-group @change="selectedall()"> 52 <checkbox class="quanxuananniu" :checked="allchecked" style="transform:scale(0.7)" /> 53 </checkbox-group> 54 全选 55 </view> 56 <view class="CartBotRightDelete" v-if="Delete"> 57 <view class="CartBotRightDel" @click="DeleteChecked()"> 58 <text>删除</text> 59 </view> 60 </view> 61 <view class="CartBotRight" v-else="!Delete"> 62 <view class="CartBotRightSum"> 63 合计:<text>¥{{totalPrice}}</text> 64 </view> 65 <view class="CartBotRightJie"> 66 <text>结算</text> 67 </view> 68 </view> 69 70 </view> 71 </view> 72 </view> 73 </template> 74 75 <script> 76 import toptars from '@/components/toptars.vue' 77 export default { 78 data() { 79 return { 80 nav: { 81 //导航标题栏组件所显示的内容 82 'title': '购物车', 83 }, 84 85 //删除与结算切换 86 Delete: false, 87 88 89 90 //购物车内是否有商品 91 flag: false, 92 93 //全选 94 allchecked: false, 95 96 //商品的数组 97 shangpin: [{ 98 id: 1, 99 title: '商品1', 100 price: 326, 101 nums: 5, 102 flag: false, 103 }, 104 { 105 id: 2, 106 title: '商品2', 107 price: 656, 108 nums: 10, 109 flag: false, 110 }, 111 ] 112 113 }; 114 }, 115 computed: { 116 //监控数据变化 117 118 //当数量变化时,下面的价格总数也跟着变化 119 totalPrice() { 120 let totalPrice = 0; 121 this.shangpin.map(item => { 122 item.flag ? totalPrice += item.nums * item.price : totalPrice += 0; 123 }) 124 return totalPrice; 125 } 126 }, 127 onShow: function() { 128 //获取一下本地用户信息,然后请求购物车数据 129 try { 130 let userid = uni.getStorageSync("userid") //获取缓存中的用户id 131 let token = uni.getStorageSync("token") //获取缓存中的token值 132 133 if (userid && token) { //两个值都有的时候才可以访问购物车,不然就跳转到登录页面 134 uni.request({ 135 136 //发送请求,并且要有相对应的userid和token值,作为请求参数 137 url: 'xxxxx', 138 method: 'GET', 139 data: { 140 userid, 141 token 142 }, 143 // success:(res)=>{ 144 // console.log(res.data); 145 // this.shangpin=res.data; 146 // } 147 148 }).then(res => { 149 if (res.data.code === '10019') { //没有登录的情况下,进行页面跳转 150 uni.showToast({ 151 title: "请先登录" 152 }), 153 154 //跳转页面 155 uni.navigateTo({ 156 url: 'xxxxxx' 157 }) 158 } else if (res.data.code === '10012') { //符合登录条件后,但没有商品,改变购物车页面,显示内容 159 uni.showToast({ 160 title: "请选择商品" 161 }), 162 this.flag = true 163 } else { 164 uni.showToast({ 165 title: '获取列表成功' 166 }), 167 this.flag = true, 168 res.data.shuju.map(item => { 169 item.flag = true 170 }) 171 this.shangpin = res.data.shuju 172 } 173 }) 174 175 } else { 176 uni.showToast({ 177 title: '请先登录' 178 }) 179 uni.navigateTo({ 180 url: 'xxxxxx' 181 }) 182 } 183 } catch (err) { 184 185 } 186 }, 187 methods: { 188 //切换结算与删除 189 tabDelete: function() { 190 this.Delete = !this.Delete; 191 }, 192 193 //减号操作 194 NumReduce: function(item) { 195 let num = item.nums; 196 197 //判断是否到0 198 if (num > 1) { 199 num -= 1; 200 } else { 201 num = 1; 202 return num; 203 }; 204 205 //判断是否登录,然后传对应的接口进行后台数据修改 206 let token = uni.getStorageSync('token'); 207 uni.request({ 208 url: 'xxxxxx', 209 data::{ 210 token, 211 cartid: item.id, 212 num 213 } 214 }).then(res => { 215 if (res.data.code === '10019') { //没有登录的情况下,进行页面跳转 216 217 uni.showToast({ 218 title: "请先登录" 219 }), 220 221 //跳转页面 222 uni.navigateTo({ 223 url: 'xxxxxx/updata' 224 }) 225 } else { 226 uni.showToast({ 227 title: "修改成功" 228 }), 229 230 //数量加减 231 item.nums = num; 232 } 233 }) 234 235 //数量加减 236 // item.nums=num; 237 238 }, 239 240 //加号操作 241 NumAdd: function(item) { 242 let num = item.nums; 243 244 //判断是否登录 245 let token = uni.getStorageSync('token'); 246 uni.request({ 247 url: 'xxxxxx/updata', 248 data: { 249 token, 250 cartid: item.id, 251 num 252 } 253 }).then(res => { 254 if (res.data.code === '10019') { 255 uni.showToast({ 256 title: "请先登录" 257 }), 258 259 //跳转页面 260 uni.navigateTo({ 261 url: 'xxxxxx/xxxxx' 262 }) 263 } else { 264 uni.showToast({ 265 title: "修改成功" 266 }), 267 268 //数量加减 269 num += 1; 270 item.nums = num; 271 } 272 }) 273 274 //数量加减 275 // item.nums=num; 276 }, 277 278 279 //单个删除商品 280 shanchu: function(item, index) { 281 let token = uni.getStorageSync('token'); 282 uni.request({ 283 url: 'xxxxxx/delete', 284 data: { 285 token, 286 cartid: item.id 287 } 288 }).then(res => { 289 if (res.data.code === '10019') { 290 uni.showToast({ 291 title: "请先登录" 292 }); 293 294 //跳转页面 295 uni.navigateTo({ 296 url: 'xxxxxx/xxxxx' 297 }) 298 } else { 299 uni.showToast({ 300 title: "删除成功" 301 }), 302 this.shangpin.splice(index, 1), 303 if (this.shangpin.length === 0) { 304 this.flag = true; 305 } 306 307 } 308 }) 309 }, 310 311 312 //删除选中商品 313 DeleteChecked: function() { 314 this.shangpin.forEach(item => { 315 if (item.flag == true) { 316 console.log(item) 317 this.shangpin.splice(item.index, 1) 318 } 319 }) 320 321 322 }, 323 //单个商品勾选 324 selected: function(item) { 325 item.flag = !item.flag; 326 if (!item.flag) { 327 this.allchecked = false; 328 329 } else { 330 const test = this.shangpin.every(item => { 331 return item.flag === true; 332 }); 333 if (test) { 334 this.allchecked = true; 335 } else { 336 this.allchecked = false; 337 } 338 } 339 340 }, 341 342 //全选按钮 343 selectedall: function() { 344 this.allchecked = !this.allchecked; 345 if (this.allchecked) { 346 this.shangpin.map(item => { 347 item.flag = true; 348 }) 349 } else { 350 this.shangpin.map(item => { 351 item.flag = false; 352 }) 353 } 354 } 355 }, 356 components: { 357 toptars, 358 } 359 } 360 </script> 361 362 <style lang="scss"> 363 page { 364 height: 100%; 365 background-color: #F6F5F5; 366 367 .CartK { 368 width: 750rpx; 369 height: 100%; 370 371 .CartKBox { 372 width: 360rpx; 373 height: 300rpx; 374 margin: 160rpx auto; 375 @extend .FlexColumnMiddle; 376 377 image { 378 width: 328rpx; 379 height: 282rpx; 380 @extend .FlexMiddle; 381 } 382 383 text { 384 margin-top: 36rpx; 385 font-size: 28rpx; 386 color: #999999; 387 font-weight: bold; 388 } 389 } 390 391 } 392 393 .CartM { 394 @extend .WidthAll; 395 background-color: #F6F5F5; 396 height: 100%; 397 398 .CartTop { 399 @extend .WidthAll; 400 height: 36rpx; 401 padding: 20rpx 0; 402 display: flex; 403 justify-content: flex-end; 404 align-items: center; 405 background-color: #FFFFFF; 406 407 text { 408 width: 156rpx; 409 height: 36rpx; 410 margin-right: 20rpx; 411 font-size: 26rpx; 412 color: #666666; 413 font-weight: bold; 414 text-align: center; 415 } 416 417 } 418 419 .CartCon { 420 @extend .WidthAll; 421 height: 100%; 422 423 .CartConList { 424 margin-top: 20rpx; 425 width: 750rpx; 426 height: 276rpx; 427 background-color: #FFFFFF; 428 @extend .FlexMiddle; 429 430 .CartConListLeft { 431 @extend .FlexMiddle; 432 height: 100%; 433 } 434 435 .CartConListRight { 436 width: 630rpx; 437 height: 190rpx; 438 439 @extend .FlexMiddle; 440 441 .CartImg { 442 width: 241rpx; 443 height: 190rpx; 444 @extend .FlexMiddle; 445 446 image { 447 width: 241rpx; 448 height: 190rpx; 449 @extend .FlexMiddle; 450 } 451 } 452 453 .CartTxt { 454 width: 373rpx; 455 height: 190rpx; 456 margin-left: 16rpx; 457 458 .CartTxtTop { 459 width: 373rpx; 460 height: 84rpx; 461 font-size: 28rpx; 462 color: #333333; 463 line-height: 42rpx; 464 } 465 466 .CartTxtBot { 467 width: 373rpx; 468 height: 52rpx; 469 margin-top: 40rpx; 470 @extend .FlexMiddleB; 471 472 .CartTxtBotPrice { 473 width: 156rpx; 474 text-align: left; 475 font-size: 26rpx; 476 font-weight: bold; 477 color: #FF3C31; 478 } 479 480 .CartTxtBotNum { 481 width: 196rpx; 482 margin-right: 20rpx; 483 @extend .FlexMiddle; 484 font-size: 24rpx; 485 color: #999999; 486 font-weight: bold; 487 488 text { 489 border: 1rpx solid #E5E5E5; 490 border-right: none; 491 padding: 14rpx 24rpx; 492 493 } 494 495 .NumAdd { 496 border-right: 1rpx solid #E5E5E5; 497 margin-right: 10rpx; 498 } 499 } 500 } 501 502 } 503 504 } 505 506 } 507 508 509 } 510 511 .CartBot { 512 width: 750rpx; 513 height: 98rpx; 514 position: fixed; 515 bottom: 0; 516 left: 0; 517 background-color: #FFFFFF; 518 z-index: 99; 519 @extend .FlexMiddleB; 520 521 .CartBotLeft { 522 width: 132rpx; 523 font-size: 26rpx; 524 color: #666666; 525 font-weight: bold; 526 @extend .FlexMiddle; 527 528 } 529 530 .CartBotRight { 531 width: 330rpx; 532 @extend .FlexMiddleB; 533 534 .CartBotRightSum { 535 font-size: 26rpx; 536 color: #666666; 537 font-weight: bold; 538 @extend .FlexMiddle; 539 540 text { 541 margin-left: 14rpx; 542 color: #FF3C31; 543 } 544 } 545 546 .CartBotRightJie { 547 width: 160rpx; 548 height: 98rpx; 549 background-color: #FF0015; 550 color: #FFFFFF; 551 font-size: 30rpx; 552 @extend .FlexMiddle; 553 // letter-spacing: 10rpx; 554 } 555 } 556 557 .CartBotRightDelete { 558 display: flex; 559 align-items: center; 560 justify-content: flex-end; 561 562 .CartBotRightDel { 563 width: 160rpx; 564 height: 98rpx; 565 background-color: #FF0015; 566 color: #FFFFFF; 567 font-size: 30rpx; 568 @extend .FlexMiddle; 569 } 570 571 } 572 } 573 } 574 575 } 576 </style>