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