知識
不管是網(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ā)微信小程序時,前端需要生成海報圖分享,目前常見解決方案如下:
- 使用
htmlCanvas
庫,利用dom來生成圖片 - 前端使用ctx的api一個一個的畫出來,或者借助一些繪圖工具
- 利用
puppeteer
后端服務(wù),打開相應(yīng)界面截圖
- 這個庫本身并不能在小程序使用,因?yàn)樯婕暗絛om,在web端也有各種兼容性問題比如某個屬性不支持
- 這個方案,額。。??赡苓@就是程序員頭發(fā)少的原因吧。費(fèi)盡千辛萬苦畫好,萬一視覺調(diào)整一下。。這個方案開發(fā)費(fèi)時費(fèi)力,不好維護(hù)。雖然web端有react-canvas,小程序也有一些工具,但目前都只是封裝了繪制矩形、文字等方法,對于布局來說還是需要手動計算寬高以及位置,沒有完全解決痛點(diǎn)。
- 這種方案對前端來說是最完美的,也推薦大家有條件用這個方案,前端寫好頁面放到服務(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)案例查看更多
相關(guān)閱讀
- 跳轉(zhuǎn)小程序
- 云南網(wǎng)站建設(shè)列表網(wǎng)
- 云南網(wǎng)站建設(shè)公司排名
- 云南網(wǎng)站建設(shè)首選
- uniapp開發(fā)小程序
- 大理網(wǎng)站建設(shè)公司
- 云南建站公司
- 網(wǎng)站開發(fā)公司哪家好
- 小程序開發(fā)課程
- 微信分銷
- 云南網(wǎng)站建設(shè)專業(yè)品牌
- 模版消息
- 迪慶小程序開發(fā)
- 云南企業(yè)網(wǎng)站
- 搜索排名
- 保險網(wǎng)站建設(shè)公司
- 國內(nèi)知名網(wǎng)站建設(shè)公司排名
- 網(wǎng)站建設(shè)選
- 模版信息
- 云南軟件開發(fā)
- 云南網(wǎng)絡(luò)營銷
- 南通小程序制作公司
- 網(wǎng)站小程序
- 云南網(wǎng)站建設(shè)哪家強(qiáng)
- web服務(wù)
- 小程序
- 網(wǎng)站建設(shè)列表網(wǎng)
- 云南網(wǎng)站建設(shè)靠譜公司
- 昆明網(wǎng)站設(shè)計
- 云南小程序制作