欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

微信小程序:使用render函數(shù)在canvas中布局生成海報圖 - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏壧峁┍憬莸闹С郑?

您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >

微信小程序:使用render函數(shù)在canvas中布局生成海報圖

發(fā)表時間:2021-1-5

發(fā)布人:葵宇科技

瀏覽次數(shù):454

背景

一個常見的需求,在開發(fā)微信小程序時,前端需要生成海報圖分享,目前常見解決方案如下:

  1. 使用htmlCanvas庫,利用dom來生成圖片
  2. 前端使用ctx的api一個一個的畫出來,或者借助一些繪圖工具
  3. 利用puppeteer后端服務(wù),打開相應(yīng)界面截圖
痛點(diǎn):
  1. 這個庫本身并不能在小程序使用,因?yàn)樯婕暗絛om,在web端也有各種兼容性問題比如某個屬性不支持
  2. 這個方案,額。。??赡苓@就是程序員頭發(fā)少的原因吧。費(fèi)盡千辛萬苦畫好,萬一視覺調(diào)整一下。。這個方案開發(fā)費(fèi)時費(fèi)力,不好維護(hù)。雖然web端有react-canvas,小程序也有一些工具,但目前都只是封裝了繪制矩形、文字等方法,對于布局來說還是需要手動計算寬高以及位置,沒有完全解決痛點(diǎn)。
  3. 這種方案對前端來說是最完美的,也推薦大家有條件用這個方案,前端寫好頁面放到服務(wù)上,然后再掛一個服務(wù)訪問這個頁面來截圖,因?yàn)殚_發(fā)和截圖的都是chromium,基本不存在兼容性問題。但是這種方案會非常耗費(fèi)服務(wù)器資源,每次截圖都要打開一個新的瀏覽器tab,并且截圖耗時比較長,對于一些公司來說可能無法接受。
簡介

easy-canvas實(shí)現(xiàn)了在canvas中創(chuàng)建文檔流,api極易上手基本沒有學(xué)習(xí)成本,可以很輕松的支持組件化開發(fā),并且沒有第三方依賴,只要支持標(biāo)準(zhǔn)的canvas就可以使用,在實(shí)現(xiàn)基本功能的基礎(chǔ)上添加了事件、scroll-view等支持?;A(chǔ)版支持小程序、web。

如果使用過render函數(shù)的肯定很熟悉使用方式了,相關(guān)屬性在項(xiàng)目里以及示例里都有介紹,本篇文章就不過多介紹,基本使用如下:

npm install easy-canvas-layout --save
復(fù)制代碼
    import easyCanvas from 'easy-canvas-layout'

    // 首先綁定圖層
    const layer = easyCanvas.createLayer(ctx, {
      dpr: 2,
      width: 300,
      height: 600,
      canvas   // 小程序環(huán)境必傳
    })

    // 創(chuàng)建node 
    // c(tag,options,children)
    const node = easyCanvas.createElement((c) => {
      return c('view', { 
        styles: { backgroundColor:'#000' }, // 樣式
        attrs:{},                           // 屬性 比如src
        on:{}                               // 事件 如click load 
      }, 
      [
        c('text',{color:'#fff'},'Hello World')
      ])
    })

    // mount
    node.mount(layer)

復(fù)制代碼
vue中使用

另外在基礎(chǔ)版本上,封裝了相應(yīng)的vue組件,相比render函數(shù),要簡潔易懂很多,基本使用如下:

npm install vue-easy-canvas --save
復(fù)制代碼
import easyCanvas from 'vue-easy-canvas'
Vue.use(easyCanvas)
復(fù)制代碼
<ec-canvas :width="300" :height="600">
    <ec-scroll-view :styles="{height:600}">

    <ec-view :styles="styles.imageWrapper">
        <ec-image 
            src="https://tse1-mm.cn.bing.net/th/id/OIP.Dkj8fnK1SsPHIBmAN9XnUAHaNK?pid=Api&rs=1" 
            :styles="styles.image" 
            mode="aspectFill"></ec-image>
        <ec-view :styles="styles.homeTitleWrapper">
        <ec-text>easyCanvas</ec-text>
        </ec-view>
    </ec-view>

    <ec-view :styles="styles.itemWrapper" 
        v-for="(item,index) in examples" 
        :key="index"
        :on="{
        click(e){
            window.location.href = http://www.wxapp-union.com/host + item.url
        }
        }">
        <ec-view :styles="styles.title">
        <ec-text>{{item.title}}</ec-text>
        </ec-view>
        <ec-view :styles="styles.desc">
        <ec-text>{{item.desc}}</ec-text>
        </ec-view>
    </ec-view>

    </ec-scroll-view>
</ec-canvas>
復(fù)制代碼
支持元素
  • view 基本元素,類似div
  • text 文本 支持自動換行以及超過省略等功能,目前text實(shí)現(xiàn)為inline-block
  • image 圖片 src mode支持aspectFit以及aspectFill,其他css特性同web 支持load事件監(jiān)聽圖片加載并且繪制完成
  • scroll-view 滾動容器,需要在樣式里設(shè)置direction 支持x、y、xy,并且設(shè)置具體尺寸 設(shè)置renderOnDemand只繪制可見部分
支持屬性

屬性使用像素的地方統(tǒng)一使用數(shù)字

  • display block | inline-block | flex, text默認(rèn)是inline-block的
  • width auto 100% Number 這里盒模型使用border-box,不可修改
  • height
  • flex flex不支持auto,固定寬度直接使用width
  • minWidth maxWidth minHeight maxHeight 如果設(shè)置了具體寬度高度不生效
  • margin marginLeft,marginRight,marginTop,marginBottom margin支持?jǐn)?shù)組縮寫例如 [10,20][10,20,10,20]
  • paddingLeft,paddingRight,paddingTop,paddingBottom 同上
  • backgroundColor
  • borderRadius
  • borderWidth borderTopWidth ... 細(xì)邊框直接設(shè)置0.5
  • borderColor
  • lineHeight 字體相關(guān)的只在text內(nèi)有效
  • color
  • fontSize
  • textAlign left right center
  • textIndent Number
  • verticalAlign top middle bottom
  • justifyContent flex-start center flex-end flex布局 水平方向?qū)ζ?/li>
  • alignItems flex-start center flex-end flex布局 垂直方向?qū)ζ?/li>
  • maxLine 最大行數(shù),超出自動省略號,只支持在text中使用
  • whiteSpace normal nowrap 控制換行,不能控制字體,只能控制inline-block
  • overflow hidden 如果添加了圓角,會自動加上 hidden
  • flexDirection
  • borderStyle dash Array 詳見ctx.setLineDash()
  • shadowBlur 設(shè)置了陰影會自動加上 overflow:hidden;
  • shadowColor
  • shadowOffsetX
  • shadowOffsetY
  • position static absolute
  • opacity Number

例如這個組件庫里的button組件

正常來說我們寫一個按鈕

.button{
    display:inline-block;
    background:green;
    color:#fff;
    font-size:14px;
    padding:4px 12px;
    text-align:center;
    border-radius:4px;
}
復(fù)制代碼

在easyCanvas中的寫法

function Button(c){
    return c('view',{
        styles:{
            display:'inline-block',
            backgroundColor:'green',
            color:'#fff',
            fontSize:14,
            padding:[4,12],
            textAlign:'center',
            borderRadius:4
        }
    },[
        c('text',{},'按鈕')
    ])
}
復(fù)制代碼

是不是覺得很熟悉很簡單,讓我們來寫一個可以接受參數(shù)的按鈕

function Button(c, { attrs, styles, on }, content) {
  const size = attrs.size || 'medium'
  const nums = SIZE[size]
  let _styles = Object.assign({
    backgroundColor: THEME[attrs.type.toUpperCase() || 'info'],
    display: 'inline-block',
    borderRadius: 2,
    color: '#fff',
    lineHeight: nums.lineHeight,
    padding: nums.padding,
    fontSize: nums.fontSize
  }, styles || {})

  if (attrs.plain) {
    _styles.color = THEME[attrs.type.toUpperCase()]
    _styles.borderWidth = 0.5
    _styles.borderColor = THEME[attrs.type.toUpperCase()]
    _styles.backgroundColor = PLAIN_THEME[attrs.type.toUpperCase() || 'info']
  }

  if (attrs.round) {
    _styles.borderRadius = nums.borderRadius
  }

  return c('view', {
    attrs: Object.assign({

    }, attrs || {}),
    styles: _styles,
    on: on || {},
  }, typeof content === 'string' ? [c('text', {}, content)] : content)
}
復(fù)制代碼

這樣在使用的地方可以傳入?yún)?shù),像這樣,也就是大家在demo里看到的

Button(c, {
    attrs: { type: 'primary', plain: true },
}, '主要按鈕'),
Button(c, {
    attrs: { type: 'success', plain: true },
}, '成功按鈕'),
Button(c, {
    attrs: { type: 'info', plain: true },
}, '信息按鈕'),
Button(c, {
    attrs: { type: 'warning', plain: true },
}, '警告按鈕'),
Button(c, {
    attrs: { type: 'error', plain: true },
}, '危險按鈕'),
復(fù)制代碼

并且,easyCanvas支持注冊全局組件,方便調(diào)用,其他參數(shù)請看項(xiàng)目使用文檔

// 注冊全局組件
easyCanvas.component('button',Button)

// 使用全局組件
function Page(c){
    return c('button',{
        attrs: { type: 'warning', plain: true },
    }, '警告按鈕')
}
復(fù)制代碼

另外easyCanvas內(nèi)置了事件管理器,可以支持類似web中的事件,從父級向子級執(zhí)行捕獲,子級再向父級冒泡。

首先需要讓canvas元素接管事件


// canvas元素監(jiān)聽鼠標(biāo)事件
canvas.ontouchstart = ontouchstart
canvas.ontouchmove = ontouchmove
canvas.ontouchend = ontouchend
canvas.onmousedown = ontouchstart
canvas.onmousemove = ontouchmove
canvas.onmouseup = ontouchend
canvas.onmousewheel = onmousewheel


// 將事件交給事件管理器接管 需要注意的是,這里的坐標(biāo)是相對于canvas元素的坐標(biāo),而不是屏幕
function ontouchstart(e) {
  e.preventDefault()
  layer.eventManager.touchstart(e.pageX || e.touches[0].pageX || 0, e.pageY || e.touches[0].pageY || 0)
}
function ontouchmove(e) {
  e.preventDefault()
  layer.eventManager.touchmove(e.pageX || e.touches[0].pageX || 0, e.pageY || e.touches[0].pageY || 0)
}
function ontouchend(e) {
  e.preventDefault()
  layer.eventManager.touchend(
    e.pageX || e.changedTouches[0].pageX || 0,
    e.pageY || e.changedTouches[0].pageY || 0
  )
}
function onClick(e) {
  e.preventDefault()
  layer.eventManager.click(e.pageX, e.pageY)
}
function onmousewheel(e){
  e.preventDefault()
  layer.eventManager.mousewheel(e.pageX,e.pageY,-e.deltaX,-e.deltaY)
}
復(fù)制代碼

接管到事件后,我們就可以在元素內(nèi)監(jiān)聽事件了

c('button',{
    id:'測試按鈕',
    on:{
        click(e){
            // 阻止冒泡到父級
            e.stopPropagation()
            alert(e.currentTarget.id) // alert 測試按鈕
        }
    }
},'點(diǎn)我點(diǎn)我')
復(fù)制代碼

目前支持的鼠標(biāo)事件有: click、touchstart、touchmove、touchend、mousewheel。

圖片支持 load、error事件

另外,支持在layer中監(jiān)聽所有圖片請求完成,比如我們需要在圖片加載完成,reflow布局并且重新渲染后立即生成圖片:

easyCanvas.createLayer(ctx, {
    dpr,
    width,
    height,
    lifecycle: {
        onEffectSuccess(res) {
            // 所有圖片加載成功
        },
        onEffectFail(res) {
            // 有圖片加載失敗
        },
        onEffectComplete(){
            // 只要加載結(jié)束就會調(diào)用
            // 生成圖片...
        }
    }
})
復(fù)制代碼

easyCanvas還支持在初始渲染后對元素進(jìn)行操作

// 獲取元素 key為attrs中定義的
el.getElementBy(key,value)

// 增加元素
el.appendChild(element)
el.prependChild(element)
el.append(element) // 加在當(dāng)前元素后
el.prepend(element)

// 刪除元素
el.removeChild(element)
el.remove()

// 修改樣式 內(nèi)部會根據(jù)樣式判斷是否需要reflow還是僅僅repaint就足夠
el.setStyles(styles)
復(fù)制代碼

demo中點(diǎn)擊左側(cè)右側(cè)定位代碼

c('view', {
    on: {
        click(e) {
            const target = layer.getElementBy('id', item.en)[0]
            if (!target || e.currentTarget === lastSelect) return
            const scrollView = layer.getElementBy('id', 'main')[1]
            scrollView.scrollTo({ y: target.y })
            e.currentTarget.setStyles({ backgroundColor: '#f1f1f1', color: '#333' })
            if (lastSelect) lastSelect.setStyles({ backgroundColor: '' })
            lastSelect = e.currentTarget
        }
    },
    styles: {
        padding: 10,
        color: '#666',
        fontSize: 16
    }
}, [c('text', {}, item.en + ' ' + item.zh)]))
復(fù)制代碼
Ending

本篇文章主要介紹項(xiàng)目背景以及基本使用,也是為了給自己打個廣告吧:) 后面會寫實(shí)現(xiàn)原理以及一些坑,歡迎各位交流,感謝閱讀!


作者:FiyN
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

相關(guān)案例查看更多