摘要:介紹轉換意思是將小程序不支持的東西轉換成它支持的東西。我在開發的小程序的過程中遇到了兩種需要做轉換的場景轉換成轉換成我將在下文詳細介紹我是怎么處理這兩種情況的。總結以上,就是我在開發小程序中對與做的一些轉換的經歷。
介紹
“轉換” 意思是將"小程序"不支持的東西轉換成它支持的東西。我在開發的小程序的過程中遇到了兩種需要做“轉換”的場景:
html 轉換成 wxml
svg 轉換成 canvas
我將在下文詳細介紹我是怎么處理這兩種情況的。
html 轉換成 wxml我們的產品在某些場景下,后端接口會直接傳 html 字符串給前端。在 ReactJs 中,我們可以用 dangerouslySetInnerHTML 直接渲染 html 字符串(不一定安全),而 ”小程序“不支持 html ,因此必須對 html 進行處理。解決這個問題的步驟主要是:1. 將 html 轉換成 json ( 樹結構) ;2. 將 json 轉換成 wxml 。我在對問題做了調研后發現,現有一個庫 wxParse 滿足該轉換的目的,但是在我看來,這個庫做的事情太多,需要依賴文件過多,不滿足只需要簡單處理的需要,所以我決定自己寫。
html 轉換成 json在參考了 html2json 與 himalaya 兩個庫的處理思路的基礎上,我寫了一個簡單的解析庫 htmlParser 。htmlParser 處理 html字符串分兩步:
lexer: 生成標記(token)
function lex(html) { let string = html let tokens = [] while (string) { // 先處理以 "" 開始的結束標簽 if (string.indexOf("") === 0) { const match = string.match(REGEXP.endTag) if (!match) continue // 通過 substring 截斷這個標簽的字符串長度 string = string.substring(match[0].length) tokens.push({ tag: match[1], type: "tag-end", }) continue } // 處理以 "<" 開始的標簽 if (string.indexOf("<") === 0) { const match = string.match(REGEXP.startTag) if (!match) continue string = string.substring(match[0].length) const tag = match[1] const isEmpty = !!MAKER.empty[tag] const type = isEmpty ? "tag-empty" : "tag-start" const attributes = getAttributes(match[2]) tokens.push({ tag, type, attributes }) continue } // 每個處理過程的其他部分字符串被當做 "text" 文本處理(暫時不處理其他情況) const index = string.indexOf("<") const text = index < 0 ? string : string.substring(0, index) string = index < 0 ? "" : string.substring(index) tokens.push({ type: "text", text }) } return tokens }
parser: 根據標記生成樹
上面的 lexer 將 html 字符串分隔成了一個一個 token,然后,我們通過遍歷所有的標識來構建樹
function parse(tokens) { let root = { tag: "root", children: [] } let tagArray = [root] tagArray.last = () => tagArray[tagArray.length - 1] for (var i = 0; i < tokens.length; i++) { const token = tokens[i] if (token.type === "tag-start") { // 構建節點 const node = { type: "Element", tagName: token.tag, attributes: Object.assign({}, { class: token.tag }, token.attributes), children: [] } tagArray.push(node) continue } if (token.type === "tag-end") { let parent = tagArray[tagArray.length - 2] let node = tagArray.pop() // 將該節點加入父節點中 parent.children.push(node) continue } if (token.type === "text") { // 往該節點中加入子元素 tagArray.last().children.push({ type: "text", content: replaceMark(token.text) }) continue } if (token.type === "tag-empty") { // 往該節點中加入子元素 tagArray.last().children.push({ type: "Element", tagName: token.tag, attributes: Object.assign({}, { class: token.tag }, token.attributes), }) continue } } return root }
整個程序的運行結果舉例:
var html = "" htmlParser(html) # 轉換結果 { "tag": "root", "children": [{ "type": "Element", "tagName": "div", "attributes": { "style": "height:10rpx;width: 20rpx;" }, "children": [ { "type": "Element", "tagName": "img", "attributes": { src: "http://xxx.jpg", class: "image" } }] }] }
以上,我們完成了 html字符串的轉換,完整代碼請戳 htmlParser
json 轉換成 wxml在熟悉了“小程序”框架的基礎上,發現需要借助模板 template ,將 json 數據填充進 template,并根據元素類型渲染相應的 wxml 組件以達到轉換目的。比如:
# 定義一個名稱為 html-image 的模板/* 使用模板 其中 json 的結構為: { "type": "Element", "tagName": "img", "attributes": { src: "http://xxx.jpg", class: "image" } } */
這樣,我們就能轉化成功了。
而因為模板沒有引用自身的能力,只能使用笨辦法:使用多個同樣內容,但是模板名稱不一樣的模板來解決嵌套的層級關系,而嵌套的層級取決于使用的模板個數。
{{content}} // html 引用 html1 兩個模板一樣
如上處理過程中,有些需要注意的細節,比如:要對 html 實體字符轉換,讓模板的 image 組件支持 mode 等等。總之,經過如上的處理,html 字符串對 wxml 組件的轉換基本功能完成。
svg 轉換成 canvas在我們的產品 web 版本中,由于需要在頁面元素中使用 svg 作為 dom 元素,而“小程序” 沒有 svg 組件的支持,如此一來,我們也需要對后端接口傳來的 svg 字符串做轉換。“小程序”沒有svg 組件但是有 canvas 組件,于是我決定使用 canvas 來模擬 svg 繪制圖形,并將圖形做一定的修改以滿足基本需求。
做這個“轉換”的關鍵也有兩點:1. 提取 svg 字符串中的元素;2.canvas 模擬元素功能進行繪制
svg 元素的提取因為 svg 字符串是一個 xml, 用上面的 htmlParser 可以將其生成 json ,問題解決。
canvas 模擬繪制在 web 中 svg 的元素有很多,好在我們需要的只有一些基本的元素:image, rect, path。rect 用 canvas 模擬不算難事,canvas 繪制起來很簡單,代碼如下:
// draw rect ctx.save() ctx.setFillStyle(attr.fill) ctx.fillRect(attr.x, attr.y, attr.width, attr.height) ctx.restore()
然而,在開發過程中,遇到了一個難點:不知道對 path 的 d 屬性如何進行模擬。d 屬性涉及移動、貝塞爾曲線等等。比如:
/** * svg path ** d 屬性值 "M250 150 L150 350 L350 350 Z" * 我們提取屬性的的結構為: [ * { marker: "M", values: [250, 150]} * ] * https://gist.github.com/shamansir/0ba30dc262d54d04cd7f79e03b281505 * 以下代碼為 d 屬性的提取部分,已在源代碼基礎上修改, */ _pathDtoCommands(str) { let results = [], match; while ((match = markerRegEx.exec(str)) !== null) { results.push(match) } return results .map((match) => { return { marker: str[match.index], index: match.index } }) .reduceRight((all, cur) => { let chunk = str.substring(cur.index, all.length ? all[all.length - 1].index : str.length); return all.concat([{ marker: cur.marker, index: cur.index, chunk: (chunk.length > 0) ? chunk.substr(1, chunk.length - 1) : chunk }]) }, []) .reverse() .map((command) => { let values = command.chunk.match(digitRegEx); return { marker: command.marker, values: values ? values.map(parseFloat) : [] }; }) }
完成了如上的步驟后,圖形基本繪制出來了,但是在后期,出現了 svg image 位置的問題。svg 中的圖片除了會有 x, y 坐標關系,還會根據視窗大小,以短邊為準,保持寬高比,長邊做縮放,視窗中居中顯示。這是我之前不清楚的部分,為此多花了點時間和精力。此外,還有些細節需要注意,比如需要調整 canvas 的縮放比例,以讓圖形完全顯示。
總結以上,就是我在開發“小程序”中對 html 與 svg 做的一些“轉換”的經歷。總結起來就是,對字符串解析,轉換成“小程序”語言。在此延伸一下,如需在 wxml 中支持 wxml 字符串,借助 htmlParser 做解析,再寫一個 wxml 模板,我們也就能“轉換” wxml 了。
參考小程序官方文檔
wxParse
html2json
himalaya
svg path 屬性
svg d 屬性值解析
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/88221.html
在微信小程序開發中用新功能利用uni-app來開發,我們看看都有哪些優缺? 首選我們看看官網給出的解決思路方案 https://uniapp.dcloud.io/hybrid 方式1:把原生小程序轉換為uni-app源碼。有各種轉換工具,詳見 方式2:新建一個uni-app項目,把原生小程序的代碼變成小程序組件,進而整合到uni-app項目下。uni-app支持使用小程序wxml組件,...
摘要:我的目的是確保所有引用的使用都是絕對安全的,編譯器會自動進行檢查。它導致了數不清的錯誤漏洞和系統崩潰,可能在之后年中造成了十億美元的損失。這個函數將使用一個表示我們希望進行轉換的函數參數,并返回一個包含轉換結果的新參數。 翻譯原文出處:Building a Maybe in JavaScript 鄙人翻譯略差且略有出入,別見笑。 很多時候我們會碰到:Uncaught TypeError...
眾所周知,Python的一個使用場景還是比較多的,在工作當中,也會涉及到多方面的一些事情。那么,今天小編寫這篇文章的一個主要目的,給大家來介紹關于如何用Python完成百度與搞得地圖轉換,下面就給大家詳細介紹下。 一、地理編碼與逆編碼 地理編碼與逆編碼表示的是地名地址與地理坐標(經緯度)互相轉換的過程。其中,將地址信息映射為地理坐標的過程稱之為地理編碼;將地理坐標轉換為地址信息的過程稱之為...
閱讀 973·2021-11-25 09:43
閱讀 2298·2019-08-30 15:55
閱讀 3160·2019-08-30 15:44
閱讀 2059·2019-08-29 16:20
閱讀 1459·2019-08-29 12:12
閱讀 1614·2019-08-26 12:19
閱讀 2289·2019-08-26 11:49
閱讀 1718·2019-08-26 11:42