欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

uniapp封裝canvas組件無腦繪制保存小程序分享海報

 更新時間:2022年08月07日 11:57:31   作者:Jerry丶Hu  
這篇文章主要為大家介紹了uniapp封裝canvas組件和方法無腦繪制并保存小程序分享海報實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

小程序分享海報想必大家都做過,受微信的限制,無法直接分享小程序到朋友圈(雖然微信開發(fā)者工具基礎庫從2.11.3開始支持分享小程序到朋友圈,但目前仍處于Beta中),所以生成海報仍然還是主流方式,通常是將設計稿通過canvas繪制成圖片,然后保存到用戶相冊,用戶通過圖片分享小程序

但是,如果不是對canvas很熟悉的話,每次都要去學習canvas的Api,挺麻煩的。我只想“無腦”的完成海報的繪制,就像是把每一個元素固定定位一樣,告訴它你要插入的是圖片、還是文字,然后再傳入坐標、寬高就能把在canvas繪制出內容。

怎么做呢?接著往下看(注:本文是基于uniapp Vue3搭建的小程序實現(xiàn)的海報功能)

配置項

屬性說明可選值
type元素類型image、text、border、block(一般用于設置背景色塊)
left元素距離canvas左側的距離數字或者center,center表示水平居中,比如10、'center'
right元素距離canvas右側的距離數字,比如10
top元素距離canvas頂部的距離數字,比如10
bottom元素距離canvas底部的距離數字,比如10
width元素寬度數字,比如20
height元素高度數字,比如20
urltype為image時的圖片地址字符串
colortype為text、border、block時的顏色字符串,比如#333333
contenttype為text時的文本內容字符串
fontSizetype為text時的字體大小數字,比如16
radiustype為image、block時圓角,200表示圓形數字,比如10
maxLinetype為text時限制最大行數,超出以…結尾數字,比如2
lineHeighttype為text時的行高,倍數數字,比如1.5,默認1.3

一、使用

<template>
  <m-canvas ref="myCanvasRef" :width="470" :height="690" />
  <button @click="createPoster">生成海報</button>
</template>
<script setup>
  import { ref } from 'vue'
  const myCanvasRef = ref()
  function createPoster() {
    // 配置項
    const options = [
      // 背景圖
      {
        type: 'image',
        url: '自行替換',
        left: 0,
        top: 0,
        width: 470,
        height: 690
      },
      // 長按掃碼 > 瀏覽臻品 > 獲取權益
      {
        type: 'text',
        content: '長按掃碼 > 瀏覽臻品 > 獲取權益',
        color: '#333',
        fontSize: 20,
        left: 'center',
        top: 240
      },
      // 小程序碼白色背景
      {
        type: 'block',
        color: '#fff',
        radius: 30,
        left: 'center',
        top: 275,
        width: 245,
        height: 245
      },
      // 小程序碼
      {
        type: 'image',
        url: '自行替換',
        left: 'center',
        top: 310,
        width: 180,
        height: 180
      },
      // 頭像
      {
        type: 'image',
        url: '自行替換',
        radius: '50%',
        left: 'center',
        top: 545,
        width: 50,
        height: 50
      },
      // 昵稱
      {
        type: 'text',
        content: 'Jerry',
        color: '#333',
        fontSize: 20,
        left: 'center',
        top: 625
      }
    ]
    // 調用myCanvas的onDraw方法,繪制并保存
    myCanvasRef.value.onDraw(options, url => {
      console.log(url)
    })
  }
</script>
<style lang="scss" scoped></style>

二、封裝m-canvas組件

<template>
  <canvas class="myCanvas" canvas-id="myCanvas" />
</template>
<script setup>
  import { getCurrentInstance } from 'vue'
  // 引入canvas方法
  import { createPoster } from './canvas'
  const { proxy } = getCurrentInstance()
  // 寬高需要傳哦~
  const props = defineProps({
    width: {
      type: Number,
      required: true
    },
    height: {
      type: Number,
      required: true
    }
  })
  // 導出方法給父組件用
  defineExpose({
    onDraw(options, callback) {
      createPoster.call(
        // 當前上下文
        proxy,
        // canvas相關信息
        {
          id: 'myCanvas',
          width: props.width,
          height: props.height
        },
        // 元素集合
        options,
        // 回調函數
        callback
      )
    }
  })
</script>
<style lang="scss" scoped>
  // 隱藏canvas
  .myCanvas {
    left: -9999px;
    bottom: -9999px;
    position: fixed;
    // canvas寬度
    width: calc(1px * v-bind(width));
    // canvas高度
    height: calc(1px * v-bind(height));
  }
</style>

三、聲明canvas.js,封裝方法

/** @生成海報 **/
export function createPoster(canvasInfo, options, callback) {
  uni.showLoading({
    title: '海報生成中…',
    mask: true
  })
  const myCanvas = uni.createCanvasContext(canvasInfo.id, this)
  var index = 0
  drawCanvas(myCanvas, canvasInfo, options, index, () => {
    myCanvas.draw(true, () => {
      // 延遲,等canvas畫完
      const timer = setTimeout(() => {
        savePoster.call(this, canvasInfo.id, callback)
        clearTimeout(timer)
      }, 1000)
    })
  })
}
// 繪制中
async function drawCanvas(myCanvas, canvasInfo, options, index, drawComplete) {
  let item = options[index]
  // 最大行數:maxLine  字體大?。篺ontSize  行高:lineHeight
  //    類型    顏色  left  right  top  bottom   寬      高     圓角    圖片  文本內容
  let { type, color, left, right, top, bottom, width, height, radius, url, content, fontSize } = item
  radius = radius || 0
  const { width: canvasWidth, height: canvasHeight } = canvasInfo
  switch (type) {
    /** @文本 **/
    case 'text':
      if (!content) break
      // 根據字體大小計算出寬度
      myCanvas.setFontSize(fontSize)
      // 內容寬度:傳了寬度就去寬度,否則取字體本身寬度
      item.width = width || myCanvas.measureText(content).width
      console.log(myCanvas.measureText(content))
      // left位置
      if (right !== undefined) {
        item.left = canvasWidth - right - item.width
      } else if (left === 'center') {
        item.left = canvasWidth / 2 - item.width / 2
      }
      // top位置
      if (bottom !== undefined) {
        item.top = canvasHeight - bottom - fontSize
      }
      drawText(myCanvas, item)
      break
    /** @圖片 **/
    case 'image':
      if (!url) break
      var imageTempPath = await getImageTempPath(url)
      // left位置
      if (right !== undefined) {
        left = canvasWidth - right - width
      } else if (left === 'center') {
        left = canvasWidth / 2 - width / 2
      }
      // top位置
      if (bottom !== undefined) {
        top = canvasHeight - bottom - height
      }
      // 帶圓角
      if (radius) {
        myCanvas.save()
        myCanvas.beginPath()
        // 圓形圖片
        if (radius === '50%') {
          myCanvas.arc(left + width / 2, top + height / 2, width / 2, 0, Math.PI * 2, false)
        } else {
          if (width < 2 * radius) radius = width / 2
          if (height < 2 * radius) radius = height / 2
          myCanvas.beginPath()
          myCanvas.moveTo(left + radius, top)
          myCanvas.arcTo(left + width, top, left + width, top + height, radius)
          myCanvas.arcTo(left + width, top + height, left, top + height, radius)
          myCanvas.arcTo(left, top + height, left, top, radius)
          myCanvas.arcTo(left, top, left + width, top, radius)
          myCanvas.closePath()
        }
        myCanvas.clip()
      }
      myCanvas.drawImage(imageTempPath, left, top, width, height)
      myCanvas.restore()
      break
    /** @盒子 **/
    case 'block':
      // left位置
      if (right !== undefined) {
        left = canvasWidth - right - width
      } else if (left === 'center') {
        left = canvasWidth / 2 - width / 2
      }
      // top位置
      if (bottom !== undefined) {
        top = canvasHeight - bottom - height
      }
      if (width < 2 * radius) {
        radius = width / 2
      }
      if (height < 2 * radius) {
        radius = height / 2
      }
      myCanvas.beginPath()
      myCanvas.fillStyle = color
      myCanvas.strokeStyle = color
      myCanvas.moveTo(left + radius, top)
      myCanvas.arcTo(left + width, top, left + width, top + height, radius)
      myCanvas.arcTo(left + width, top + height, left, top + height, radius)
      myCanvas.arcTo(left, top + height, left, top, radius)
      myCanvas.arcTo(left, top, left + width, top, radius)
      myCanvas.stroke()
      myCanvas.fill()
      myCanvas.closePath()
      break
    /** @邊框 **/
    case 'border':
      // left位置
      if (right !== undefined) {
        left = canvasWidth - right - width
      }
      // top位置
      if (bottom !== undefined) {
        top = canvasHeight - bottom - height
      }
      myCanvas.beginPath()
      myCanvas.moveTo(left, top)
      myCanvas.lineTo(left + width, top + height)
      myCanvas.strokeStyle = color
      myCanvas.lineWidth = width
      myCanvas.stroke()
      break
  }
  // 遞歸邊解析圖片邊畫
  if (index === options.length - 1) {
    drawComplete()
  } else {
    index++
    drawCanvas(myCanvas, canvasInfo, options, index, drawComplete)
  }
}
// 下載并保存
function savePoster(canvasId, callback) {
  uni.showLoading({
    title: '保存中…',
    mask: true
  })
  uni.canvasToTempFilePath(
    {
      canvasId,
      success(res) {
        callback && callback(res.tempFilePath)
        uni.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
          success() {
            uni.showToast({
              icon: 'success',
              title: '保存成功!'
            })
          },
          fail() {
            uni.showToast({
              icon: 'none',
              title: '保存失敗,請稍后再試~'
            })
          },
          complete() {
            uni.hideLoading()
          }
        })
      },
      fail(res) {
        console.log('圖片保存失敗:', res.errMsg)
        uni.showToast({
          icon: 'none',
          title: '保存失敗,請稍后再試~'
        })
      }
    },
    this
  )
}
// 繪制文字(帶換行超出省略…功能)
function drawText(ctx, item) {
  let { content, width, maxLine, left, top, lineHeight, color, fontSize } = item
  content = String(content)
  lineHeight = (lineHeight || 1.3) * fontSize
  // 字體
  ctx.setFontSize(fontSize)
  // 顏色
  ctx.setFillStyle(color)
  // 文本處理
  let strArr = content.split('')
  let row = []
  let temp = ''
  for (let i = 0; i < strArr.length; i++) {
    if (ctx.measureText(temp).width < width) {
      temp += strArr[i]
    } else {
      i-- //這里添加了i-- 是為了防止字符丟失,效果圖中有對比
      row.push(temp)
      temp = ''
    }
  }
  row.push(temp) // row有多少項則就有多少行
  //如果數組長度大于2,現(xiàn)在只需要顯示兩行則只截取前兩項,把第二行結尾設置成'...'
  if (row.length > maxLine) {
    let rowCut = row.slice(0, maxLine)
    let rowPart = rowCut[1]
    let text = ''
    let empty = []
    for (let i = 0; i < rowPart.length; i++) {
      if (ctx.measureText(text).width < width) {
        text += rowPart[i]
      } else {
        break
      }
    }
    empty.push(text)
    let group = empty[0] + '...' //這里只顯示兩行,超出的用...表示
    rowCut.splice(1, 1, group)
    row = rowCut
  }
  // 把文本繪制到畫布中
  for (let i = 0; i < row.length; i++) {
    // 一次渲染一行
    ctx.fillText(row[i], left, top + i * lineHeight, width)
  }
}
// 獲取圖片信息
function getImageTempPath(url) {
  return new Promise((resolve) => {
    if (url.includes('http')) {
      uni.downloadFile({
        url,
        success: (res) => {
          uni.getImageInfo({
            src: res.tempFilePath,
            success: (res) => {
              resolve(res.path)
            }
          })
        },
        fail: (res) => {
          console.log('圖片下載失?。?, res.errMsg)
        }
      })
    } else {
      resolve(url)
    }
  })
}

以上就是uniapp封裝canvas組件無腦繪制保存小程序分享海報的詳細內容,更多關于uniapp封裝canvas的資料請關注腳本之家其它相關文章!

相關文章

  • JS數據分析數據去重及參數序列化示例

    JS數據分析數據去重及參數序列化示例

    這篇文章主要為大家介紹了JS數據分析數據去重及參數序列化示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 微信小程序 共用變量值的實現(xiàn)

    微信小程序 共用變量值的實現(xiàn)

    這篇文章主要介紹了微信小程序 共用變量值的實現(xiàn)的相關資料,需要的朋友可以參考下
    2017-07-07
  • TypeScript中Module使用區(qū)別及模塊路徑解析規(guī)則

    TypeScript中Module使用區(qū)別及模塊路徑解析規(guī)則

    這篇文章主要為大家介紹了TypeScript中Module使用區(qū)別及模塊路徑解析規(guī)則,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • 前端JavaScript徹底弄懂函數柯里化curry

    前端JavaScript徹底弄懂函數柯里化curry

    隨著主流JavaScript中函數式編程的迅速發(fā)展, 函數柯里化在許多應用程序中已經變得很普遍。 了解它們是什么,它們如何工作以及如何充分利用它們非常重要。本篇文章小編九向大家詳細介紹JavaScript函數柯里化,需要的小伙伴可以參考下面文字內容
    2021-09-09
  • 微前端之?js隔離?樣式隔離?元素隔離問題詳解

    微前端之?js隔離?樣式隔離?元素隔離問題詳解

    這篇文章主要為大家介紹了微前端之?js隔離?樣式隔離?元素隔離問題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 羊了個羊的中強大的Grid布局

    羊了個羊的中強大的Grid布局

    這篇文章主要為大家介紹了羊了個羊的中強大的Grid布局詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • quickjs 封裝 JavaScript 沙箱詳情

    quickjs 封裝 JavaScript 沙箱詳情

    這篇文章主要介紹了 quickjs 封裝 JavaScript 沙箱,在前文 JavaScript 沙箱探索 中聲明了沙箱的接口,并且給出了一些簡單的執(zhí)行任意第三方 js 腳本的代碼,但并未實現(xiàn)完整的 IJavaScriptShadowbox,下面便講一下如何基于 quickjs 實現(xiàn),需要的朋友可以參考一下
    2021-10-10
  • THREE.js添加多個castShadow光源報錯解決及原因分析

    THREE.js添加多個castShadow光源報錯解決及原因分析

    這篇文章主要介紹了THREE.js添加多個castShadow的光源報錯解決及原因分析
    2023-06-06
  • 微信小程序 頁面滑動事件的實例詳解

    微信小程序 頁面滑動事件的實例詳解

    這篇文章主要介紹了微信小程序 頁面滑動事件的實例詳解的相關資料,希望通過本文能幫助到大家,讓大家實現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • Server-sent?events實時獲取服務端數據技術詳解

    Server-sent?events實時獲取服務端數據技術詳解

    這篇文章主要為大家介紹了Server-sent?events實時獲取服務端數據技術詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02

最新評論