<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「微信小程序」生成水印原理與插件編寫

          共 13689字,需瀏覽 28分鐘

           ·

          2021-07-12 03:40


          一 前言

          今天分享一個(gè)小程序生成水印的小技巧——canvas繪制背景圖,接下來(lái)我會(huì)詳細(xì)介紹繪制的細(xì)節(jié)。希望開(kāi)發(fā)過(guò)微信小程序的同學(xué)可以把文章收藏起來(lái),這樣如果以后遇到類似的需求,可以翻出來(lái)作為參考。

          本文的插件同樣適用于Taro,uniapp,原生等構(gòu)建的小程序項(xiàng)目,項(xiàng)目demo是采用Taro-Vue構(gòu)建的。

          我們先來(lái)看看demo效果。

          WechatIMG157.jpeg

          二 原理實(shí)現(xiàn)

          canvas繪制背景圖這個(gè)方案原理本質(zhì)上是非常簡(jiǎn)單的,就如把大象放冰箱一共分成三步那樣簡(jiǎn)單????。

          • 第一步冰箱門打開(kāi),因?yàn)檫@個(gè)功能是前端實(shí)現(xiàn)的,而且是canvas畫出來(lái)的,所以我們需要海報(bào)的基礎(chǔ)配置,比如canvas海報(bào)寬高,文字內(nèi)容,文字顏色,海報(bào)文字的旋轉(zhuǎn)角度等。

          • 第二步把大象??放進(jìn)去,canvas得到配置,繪制水印底圖。

          那么問(wèn)題來(lái)了,我們繪制的底圖是整張水印底圖嗎?

          答案是否定的。我們只需要畫一個(gè)模版圖片就可以了,如下圖所示:

          111.jpg

          但是為了讓水印填充整個(gè)手機(jī)屏幕,我們需要將水印圖片作為背景圖片,然后設(shè)置background-repeat:repeat;就可以了。

          222.jpg
          • 第三步把冰箱門關(guān)上,我們通過(guò)canvas生成的圖片,將圖片填充整個(gè)屏幕就可以了。

          三 細(xì)節(jié)實(shí)現(xiàn)

          demo樣板

          canvas模版接下來(lái)我們開(kāi)始實(shí)現(xiàn)具體的細(xì)節(jié),首先我們頁(yè)面放入一個(gè)<canvas>

          <view
              class="markBox"
              :style="{ backgroundImage: `url(${url})` }"
          >
            
              <canvas
                v-show="isShow"
                :id="settings.id"
                type="2d"
                :class="settings.id"
                :style="{ width:settings.width + 'px' , height : settings.height + 'px' }"
              />

          </view>
          • 這里有一點(diǎn)值得注意,就是我們?cè)O(shè)置的type = '2d'最好不要用canvasId方式來(lái)操作canvas,包括獲取canvas實(shí)例,調(diào)用canvasToTempFilePathapi等,不然可能會(huì)失效。這里采用的是通過(guò)id方式,來(lái)獲取canvas實(shí)例的。

          • 當(dāng)我們繪制完成后,隱藏canvas,將view容器設(shè)置背景圖片,背景圖片就是canvas繪制形成的圖片。

          • canvas寬度和高度是根據(jù)canvas的配置項(xiàng)添加的,所以我們要?jiǎng)討B(tài)用style屬性設(shè)置寬高。

          配置項(xiàng)

          export default {
             /* 前端生成水印 */
             name:"MakeWaterMark",
             data(){
                 return {
                     isShow:true,
                     url:'',
                     settings: {
                          'id''waterMark',                  /* canvas id */
                          'content''我不是外星人',            /* 水印內(nèi)容 */
                          'width'200,                       /* 圖片/canvas 寬度 */
                          'height'200,                      /* 圖片/canvas 高度 */ 
                          'rotate'-45,                      /* 水印文案旋轉(zhuǎn)角度*/ 
                          'left':60,                          /* 水印文案相對(duì)圖片水平偏移量 */
                          'top':80,                           /* 水印文案相對(duì)圖片垂直偏移量 */
                          'fontSize''15px',                 /* 水印文字大小 */
                          'fontFamily''Microsoft JhengHei'/* 水印文字樣式 */
                          'bg''#fff',                       /* 圖片背景顏色 */ 
                          'color''#ccc',                    /* 水印文字顏色 */
                          'fontWeight''normal',             /* 水印文字寬度 */
                      }
                 }
             },
          }

          樣式處理

          .markBox{
              position: fixed;
              left:0;
              right:0;
              bottom0;
              top:0;
              background-repeat:repeat ;
          }
          • 給外層容器設(shè)置樣式,能夠讓水印圖片平鋪整個(gè)頁(yè)面。

          插件核心代碼

          插件的核心功能就是生成水印圖片,除此之外還要滿足兩個(gè)要求:

          • 插件本身和頁(yè)面/組件低耦合。插件本身可以在任何組件中使用。
          • 插件不受構(gòu)建平臺(tái)的限制,就是既能在原生微信小程序中使用,也能在Taro,uniapp等構(gòu)建工具中使用。

          接下來(lái)我們看一下具體細(xì)節(jié):

          function createPromise(callback){
              return new Promise((resolve,reject)=>{
                  callback(resolve,reject)
              })
          }

          /**
           * 制作水印圖片
           */

          class MarkwaterMark{
              constructor(options){
                  /* 初始化配置 */
                 this.platform  = null 
                 this.pixelRatio = null
                 this.context = null
                 this.options = options 
                 this.ready = createPromise(this._init.bind(this))   
                 /* 生成組件方法 */
                 this.make = (cb) => { 
                    if(this.context){
                       this._markPicture(cb)
                    }else{
                        this.ready.then(()=>{
                           this.context && this._markPicture(cb)
                        })
                    }    
                 }
              }
              /* 初始化方法 */
              _init(next,fail){
                 const { platform , pixelRatio } = wx.getSystemInfoSync()
                 this.platform = platform
                 this.pixelRatio = pixelRatio
                 const query = wx.createSelectorQuery()
                 query.select('#' + this.options.id ).fields({
                  nodetrue,
                  sizetrue
                }).exec((res)=>{
                  let {
                      node,
                  } = res[0] || {} 
                  if (!node) return fail && fail()
                  this.context = node.getContext('2d')    
                  this.node = node
                  next()
                })
              }
              /* 制作水印圖片 */
              _markPicture(cb){
                 const { width , height , bg ,color ,fontSize, fontFamily,fontWeight ,content , left, top ,rotate } = this.options
                 this.node.width = (width || 200) * this.pixelRatio
                 this.node.height =( height || 200) * this.pixelRatio
                 this.context.scale(this.pixelRatio,this.pixelRatio)
                 this.context.fillStyle = bg || '#fff'
                 this.context.fillRect(00, width, height)
                 this.context.fillStyle = color || '#000'
                 this.context.save()
                 this.context.translate(left,top)
                 this.context.rotate(Math.PI * rotate / 180 )
                 this.context.font =  `${fontWeight} 400 ${fontSize} ${fontFamily}`
                 this.context.fillText(content, 00)
                 this.context.restore() 
                 this._savePicture(cb)
              }
              /* 生成圖片 */
              _savePicture(cb){
               const { width , height  } = this.options
                 wx.canvasToTempFilePath({
                    x:0,
                    y:0,
                    width,
                    height,
                    destWidth:width*1,
                    destHeight:height*1,
                    canvas:this.node,
                    success:function(res){
                       cb && cb(res.tempFilePath)
                    }
                 })
              }
          }
          /**
           * 
           * @param {*} options 配置項(xiàng)
           */

          function makeWatermark(options){
            if(!wx) return null
            return new MarkwaterMark(options) 
          }

          module.exports = makeWatermark

          核心功能流程分析:

          • 第一步:暴露makeWatermark接口,可以實(shí)例化一個(gè)MarkwaterMark對(duì)象,實(shí)例化過(guò)程中本身先進(jìn)行初始化配置,包裹一層Promise用于創(chuàng)建圖片。由于canvas操作中,很多方法都是異步的,所以用 createPromise 方法代理一層Promise。

          • 第二步:MarkwaterMark對(duì)象上,有make方法,會(huì)獲取canvas實(shí)例,然后設(shè)置canvas畫布的寬高和縮放比,繪制水印canvas。

          • 第三步:將canvas通過(guò)canvasToTempFilePath接口把canvas畫布轉(zhuǎn)化成臨時(shí)圖片,并把臨時(shí)圖片路徑通過(guò)callback形式,傳遞給業(yè)務(wù)組件或者頁(yè)面。

          插件使用

          在業(yè)務(wù)組件(上述demo)中,我們就可以使用上述插件了。具體參考如下:

           mounted(){ 
                 Taro.nextTick(()=>{
                     /* 創(chuàng)建一個(gè)  makeWatermark 對(duì)象 */
                     const marker = makeWatermark(this.settings)
                     /* 調(diào)用make,生成圖片 */
                     marker.make((url)=>{
                         /* url 為臨時(shí)路徑  */
                         const fileManage = Taro.getFileSystemManager()
                         let base64 = 'data:image/jpg;base64,' + fileManage.readFileSync(url,'base64');
                         this.url = base64
                         this.isShow  = false
                     })
                 })
             },

          重要細(xì)節(jié):

          這里還有一個(gè)比較重要細(xì)節(jié)就是,小程序中背景圖片一般都是網(wǎng)絡(luò)圖片或者base64圖片,對(duì)于臨時(shí)路徑的圖片在真機(jī)上是不顯示的。為了解決這個(gè)問(wèn)題,我們需要把臨時(shí)圖片轉(zhuǎn)換成base64格式圖片。

          • 通過(guò) getFileSystemManagerbase64方式訪問(wèn)剛生成的臨時(shí)圖片,然后返回base64格式,接下來(lái)就可以把 base64 圖片設(shè)置為背景圖片了。

          效果:

          WechatIMG157.jpeg

          大功告成!?。?/p>

          四 總結(jié)

          通過(guò)本文我們學(xué)習(xí)了微信小程序生成水印的方式和流程。還有一些開(kāi)發(fā)中的細(xì)節(jié)問(wèn)題。感興趣的同學(xué)可以收藏起來(lái),以備不時(shí)之需。


          如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:

          1. 點(diǎn)個(gè)「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點(diǎn)在看,都是耍流氓 -_-)
          2. 歡迎加我微信「Augenstern9728」一起交流學(xué)習(xí)...
          3. 關(guān)注公眾號(hào)「前端時(shí)光屋」,持續(xù)為你推送精選好文


          瀏覽 164
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  粉嫩99精品99久久久久久特污兔 | 久久er99热精品一区二区 | 思思热在线观看视频精品 | 大香蕉婷婷丁香五月 | 国产丝袜足交的视频链接 |