今天,小程序正式支持 SVG


今天,小程序正式支持 SVG


寫在前面

今天你可以在小程序中使用 Cax 引擎高性能渲染 SVG!

SVG 是可縮放矢量圖形(Scalable Vector Graphics),基於可擴展標記語言,用於描述二維矢量圖形的一種圖形格式。它由萬維網聯盟制定,是一個開放標準。SVG 的優勢有很多:

  • SVG 使用 XML 格式定義圖形,可通過文本編輯器來創建和修改
  • SVG 圖像可被搜索、索引、腳本化或壓縮
  • SVG 是可伸縮的,且放大圖片質量不下降
  • SVG 圖像可在任何的分辨率下被高質量地打印
  • SVG 可被非常多的工具讀取和修改(比如記事本)
  • SVG 與 JPEG 和 GIF 圖像比起來,尺寸更小,且可壓縮性、可編程星更強
  • SVG 完全支持 DOM 編程,具有交互性和動態性

而支持上面這些優秀特性的前提是 -

需要支持 SVG 標籤。比如在小程序中直接寫:


<rect> bindtap="tapHandler" height="100" width="100"
style="stroke:#ff0000; fill: #0000ff">
/<rect>

上面定義了 SVG 的結構、樣式和點擊行為。但是小程序目前不支持 SVG 標籤,僅僅支持加載 SVG 之後 作為 background-image 進行展示,如 background-image: url("data:image/svg+xml.......),或者 base64 後作為 background-image 的 url。

那麼怎麼辦呢?有沒有辦法讓小程序支持 SVG? 答案是有的!需要下面這些東西(站在巨人的肩膀上):

  • JSX,史上最強 UI 表達式,支持書寫 XML-Hyperscript 互轉的 JS 語言
  • 小程序內置 Canvas 渲染器
  • Cax 最新渲染引擎
  • HTM,Hyperscript Tagged Markup,可能是 JSX 的替代品或者另一種選擇,使用ES標準的模板語法實現的 Hyperscript 運行時/編譯時生成,preact 作者(也是google工程師)打造

這裡稍微解釋下 Hyperscript:

比如 JSX 中的


Hello {this.props.name}

或者 js 中的 htm:

html`

Hello {this.props.name}
`

最後都會被編譯成:

h(
"div",
null,
"Hello ",
this.props.name
);

嵌套的 div 也會變編譯成 h 嵌套 h,比如


abc


編譯後:

h(
"div",
null,
h(
"div",
null,
"abc"
)
)

而 h 函數的定義也是相當簡潔:

function h(type, props, ...children) {
return { type, props, children }
}

通過 h 的執行可以 js 中拿到結構化的數據,也就是所謂的虛擬 dom。需要注意的是 htm 有輕微的運行時開銷,jsx 沒有。

一句話總結:

使用小程序內置的 Canvas 渲染器, 在 Cax 中實現 SVG 標準的子集,使用 JSX 或者 HTM 描述 SVG 結構行為表現

直接看在小程序種使用案例:

import { html, renderSVG } from '../../cax/cax'
Page({
onLoad: function () {
renderSVG(html`

<rect> height="110" width="110"
style="stroke:#ff0000; fill: #ccccff"
transform="translate(100 50) rotate(45 50 50)">
/<rect>
`, 'svg-a', this)
},
tapHandler: function () {
console.log('你點擊了 rect')
}
})

其中的 svg-a 對應著 wxml 裡 cax-element 的 id:

<view>
<cax-element>

/<view>
{
"usingComponents": {
"cax-element":"../../cax/index"
}
}

小程序中顯示效果:


今天,小程序正式支持 SVG

13

可以使用 width,height,bounds-x 和 bounds-y 設置綁定事件的範圍,比如:

<path>

需要注意的是,元素的事件觸發的包圍盒受自身或者父節點的 transform 影響,所以不是絕對座標的 rect 觸發區域。

再來一個複雜的例子,用 SVG 繪製 Omi 的 logo:

renderSVG(html`


<circle>
<polygon>
<circle>

`, 'svg-a', this)

小程序種顯示效果:


今天,小程序正式支持 SVG


在 omip 和 mps 當中使用 cax 渲染 svg,你可以不用使用 htm。比如在 omip 中實現上面兩個例子:

 renderSVG(

<rect> height="110" width="110"
style="stroke:#ff0000; fill: #ccccff"
transform="translate(100 50) rotate(45 50 50)">
/<rect>
, 'svg-a', this.$scope)
renderSVG(


<circle>
<polygon>
<circle>

, 'svg-a', this.$scope)
複製代碼
需要注意的是在 omip 中傳遞的最後一個參數不是 this,而是 this.$scope。

在 mps 中,更加徹底,你可以單獨創建 svg 文件,通過 import 導入。

//注意這裡不能寫 test.svg,因為 mps 會把 test.svg 編譯成 test.js
import testSVG from '../../svg/test'
import { renderSVG } from '../../cax/cax'
Page({
tapHandler: function(){
this.pause = !this.pause
},
onLoad: function () {

renderSVG(testSVG, 'svg-a', this)
}
})

比如 test.svg :


<rect> style="stroke:#ff0000; fill: #0000ff" />
/<rect>

會被 mps 編譯成:

const h = (type, props, ...children) => ({ type, props, children });
export default h(
"svg",
{ width: "300", height: "300" },
h("rect", {
bindtap: "tapHandler",
x: "0",
y: "0",
height: "110",
width: "110",
style: "stroke:#ff0000; fill: #0000ff"
})
);

所以總結一下:

  • 你可以在 mps 中直接使用 import 的 SVG 文件的方式使用 SVG
  • 你可以直接在 omip 中使用 JSX 的使用 SVG
  • 你可以直接在原生小程序當中使用 htm 的方式使用 SVG

這就完了?遠沒有,看 cax 在小程序中的這個例子:


今天,小程序正式支持 SVG


詳細代碼:

renderSVG(html`

<path>
<animate>
/<path>
`, 'svg-c', this)

再試試著名的 SVG 老虎:


今天,小程序正式支持 SVG


path 太長,就不貼代碼了

就這麼多?未完待續...,後續補充:

pasiton 標籤

import { html, renderSVG } from '../../cax/cax'
Page({
onLoad: function () {

const svg = renderSVG(html`

<pasition> to="M49.1 23.5H2.1C0.9 23.5 0 24.5 0 25.6s0.9 2.1 2.1 2.1h47c1.1 0 2.1-0.9 2.1-2.1C51.2 24.5 50.3 23.5 49.1 23.5zM49.1 7.8H2.1C0.9 7.8 0 8.8 0 9.9c0 1.1 0.9 2.1 2.1 2.1h47c1.1 0 2.1-0.9 2.1-2.1C51.2 8.8 50.3 7.8 49.1 7.8zM49.1 39.2H2.1C0.9 39.2 0 40.1 0 41.3s0.9 2.1 2.1 2.1h47c1.1 0 2.1-0.9 2.1-2.1S50.3 39.2 49.1 39.2z"
from-stroke="red" to-stroke="green" from-fill="blue" to-fill="red" stroke-width="2" />
/<pasition>`, 'svg-c', this)
this.pasitionElement = svg.children[0]
},
changePath: function () {
this.pasitionElement.toggle()
}
})

pasiton 提供了兩個 path 和 顏色 相互切換的能力,最常見的場景比如 menu 按鈕和 close 按鈕點擊後 path 的變形。

舉個例子,看顏色和 path 同時變化:


今天,小程序正式支持 SVG



線性運動

這裡舉一個在 mps 中使用 SVG 的案例:

import { renderSVG, To } from '../../cax/cax'
Page({
tapHandler: function(){
this.pause = !this.pause
},
onLoad: function () {
const svg = renderSVG(html`

<rect> style="stroke:#ff0000; fill: #0000ff" />
/<rect>`
, 'svg-a', this)
const rect = svg.children[0]
rect.originX = rect.width/2
rect.originY = rect.height/2
rect.x = svg.stage.width/2
rect.y = svg.stage.height/2
this.pause = false
this.interval = setInterval(()=>{
if(!this.pause){
rect.rotation++
svg.stage.update()
}
},15)
})

效果如下:


今天,小程序正式支持 SVG



組合運動

import { renderSVG, To } from '../../cax/cax'
Page({
onLoad: function () {
const svg = renderSVG(html`

<rect> style="stroke:#ff0000; fill: #0000ff" />
/<rect>`
,'svg-a', this)
const rect = svg.children[0]

rect.originX = rect.width/2
rect.originY = rect.height
rect.x = svg.stage.width/2
rect.y = svg.stage.height/2
var sineInOut = To.easing.sinusoidalInOut
To.get(rect)
.to().scaleY(0.8, 450, sineInOut).skewX(20, 900, sineInOut)
.wait(900)
.cycle().start()
To.get(rect)
.wait(450)
.to().scaleY(1, 450, sineInOut)
.wait(900)
.cycle().start()
To.get(rect)
.wait(900)
.to().scaleY(0.8, 450, sineInOut).skewX(-20, 900, sineInOut)
.cycle()
.start()
To.get(rect)
.wait(1350)
.to().scaleY(1, 450, sineInOut)
.cycle()
.start()
setInterval(() => {
rect.stage.update()
}, 16)
}
})

效果如下:


今天,小程序正式支持 SVG



其他

  • vscode 安裝 lit-html 插件使 htm 的 html內容 高亮
  • 還希望小程序 SVG 提供什麼功能可以開 issues告訴我們,評估後通過,我們去實現!

想要學好web前端的小夥伴們,小編給大家整理了最新web前端資料大全!這些資料都是JD架構師Sonia老師熬夜錄製的,下面的所有錄製的每一個免費課程Sonia老師都要精心準備3-5小時,Sonia老師作為每天敲8小時以上代碼的一線程序員,所有課程都是她每天下班回家和早上4:30起來錄製的。所有視頻,一共花了3個月的時間,後續Sonia老師還會每天堅持給大家錄製免費視頻!請大家支持一下Sonia老師!

本著為廣大讀者服務的初心,下面所以Sonia老師錄製的視頻資料完全是免費贈送的,感興趣的只需要添加小編WX: 18672945276 ,備註"資料",就能立即獲取免費資料!

今天,小程序正式支持 SVG

今天,小程序正式支持 SVG


分享到:


相關文章: