一级片大奶子_色又黄又爽18禁免费视频_热久久久久久久_久久久精品一区二区_日韩av不卡在线播放_精品国内自产拍在线观看视频

注冊登錄

在微信小程序中渲染HTML內容

2018-09-18
導讀:大部分Web應用的富文本內容都是以HTML字符串的形式存儲的,通過HTML文檔去展示HTML內容自然沒有問題。但是,在微信小程序(下文簡稱為「小程序」)中,應當如何渲染這部分內容呢?...

大部分Web應用的富文本內容都是以HTML字符串的形式存儲的,通過HTML文檔去展示HTML內容自然沒有問題。但是,在微信小程序(下文簡稱為「小程序」)中,應當如何渲染這部分內容呢?

解決方案wxParse

小程序剛上線那會兒,是無法直接渲染HTML內容的,于是就誕生了一個叫做「 wxParse 」的庫。它的原理就是把HTML代碼解析成樹結構的數據,再通過小程序的模板把該數據渲染出來。

rich-text

后來,小程序增加了「rich-text」組件用于展示富文本內容。然而,這個組件存在一個極大的限制: 組件內屏蔽了所有節點的事件 。也就是說,在該組件內,連「預覽圖片」這樣一個簡單的功能都無法實現。

web-view

再后來,小程序允許通過「web-view」組件嵌套網頁,通過網頁展示HTML內容是兼容性最好的解決方案了。然而,因為要多加載一個頁面,性能是較差的。

當「WePY」遇上「wxParse」

基于用戶體驗和功能交互上的考慮,我們拋棄了「rich-text」和「web-view」這兩個原生組件,選擇了「wxParse」。然而,用著用著卻發現,「wxParse」也不能很好地滿足需要:

  • 我們的小程序是基于「WePY」框架開發的,而「wxParse」是基于原生的小程序編寫的。要想讓兩者兼容,必須修改「wxParse」的源代碼。
  • 「wxParse」只是簡單地通過image組件對原img元素的圖片進行顯示和預覽。而在實際使用中,可能會用到云存儲的接口對圖片進行縮小,達到「 用小圖顯示,用原圖預覽 」的目的。
  • 「wxParse」直接使用小程序的video組件展示視頻,但是video組件的 層級問題 經常導致UI異常(例如把某個固定定位的元素給擋了)。

此外,圍觀一下「wxParse」的代碼倉庫可以發現,它已經兩年沒有迭代了。所以就萌生了基于「WePY」的組件模式重新寫一個富文本組件的想法,其成果就是「WePY HTML」項目。

實現過程解析HTML

首先仍然是要把HTML字符串解析為樹結構的數據,我采用的是「特殊字符分隔法」。HTML中的特殊字符是「<」和「>」,前者為開始符,后者為結束符。

  • 如果待解析內容以開始符開頭,則截取 開始符到結束符之間 的內容作為節點進行解析。
  • 如果待解析內容不以開始符開頭,則截取 開頭到開始符之前 (如果開始符不存在,則為末尾)的內容作為純文本解析。
  • 剩余內容進入下一輪解析,直到無剩余內容為止。

為了形成樹結構,解析過程中要維護一個上下文節點(默認為根節點):

  • 如果截取出來的內容是開始標簽,則根據匹配出的標簽名和屬性,在當前上下文節點下創建一個子節點。如果該標簽不是自結束標簽(br、img等),就把上下文節點設為新節點。
  • 如果截取出來的內容是結束標簽,則根據標簽名關閉當前上下文節點(把上下文節點設為其父節點)。
  • 如果是純文本,則在當前上下文節點下創建一個文本節點,上下文節點不變。

經過上述流程,HTML字符串就被解析為節點樹了。

對比

把上述算法與其他類似的解析算法進行對比(性能以「解析10000長度的HTML代碼」進行測定):

可見,在不考慮容錯性(產生錯誤的結果,而非拋出異常)的情況下,本組件的算法與其余兩者相比有壓倒性的優勢,符合小程序「 小而快 」的需要。而一般情況下,富文本編輯器所生成的代碼也不會出現語法錯誤。因此,即使容錯性較差,問題也不大(但這是需要改進的)。

模板渲染

樹結構的渲染,必然會涉及到子節點的 遞歸 處理。然而,小程序的模板并不支持遞歸,這下仿佛掉入了一個大坑。

看了一下「wxParse」模板的實現,它采用簡單粗暴的方式解決這個問題:通過13個長得幾乎一模一樣的模板進行嵌套調用(1調用2,2調用3,……,12調用13),也就是說最多可以支持12次嵌套。一般來說,這個深度也足夠了。

由于「WePY」框架本身是有構建機制的,所以不必手寫十來個幾乎一模一樣的模板,通過一個構建的插件去生成即可。

以下為需要重復嵌套的模板(精簡過),在其代碼的開始前和結束后分別插入特殊注釋進行標識,并在需要嵌入下一層模板的地方以另一段特殊注釋(「<!-- next template -->」)標識:

<!-- wepyhtml-repeat start -->
<template name="wepyhtml-0">
	<block wx:if="{{ content }}" wx:for="{{ content }}">
		<block wx:if="{{ item.type === 'node' }}">
			<view class="wepyhtml-tag-{{ item.name }}">
				<!-- next template -->
			</view>
		</block>
		<block wx:else>{{ item.text }}</block>
	</block>
</template>
<!-- wepyhtml-repeat end -->

以下是對應的構建代碼(需要安裝「 wepy-plugin-replace 」):

// wepy.config.js
{
	plugins: {
		replace: {
			filter: /\.wxml$/,
			config: {
				find: /<\!-- wepyhtml-repeat start -->([\W\w]+?)<\!-- wepyhtml-repeat end -->/,
				replace(match, tpl) {
					let result = '';
					// 反正不要錢,直接寫個20層嵌套
					for (let i = 0; i <= 20; i++) {
						result += '\n' + tpl
							.replace('wepyhtml-0', 'wepyhtml-' + i)
							.replace(/<\!-- next template -->/g, () => {
								return i === 20 ?
									'' :
									`<template is="wepyhtml-${ i + 1 }" wx:if="{{ item.children }}" data="{{ content: item.children"></template>`;
							});
					}
					return result;
				}
			}
		}
	}
}

然而,運行起來后發現,第二層及更深層級的節點都沒有渲染出來,說明嵌套失敗了。再看一下dist目錄下生成的wxml文件可以發現,變量名與組件源代碼的并不相同:

<block wx:if="{{ $htmlContent$wepyHtml$content }}" wx:for="{{ $htmlContent$wepyHtml$content }}">

「WePY」在生成組件代碼時,為了避免組件數據與頁面數據的變量名沖突,會 根據一定的規則給組件的變量名增加前綴 (如上面代碼中的「$htmlContent$wepyHtml$」)。所以在生成嵌套模板時,也必須使用帶前綴的變量名。

先在組件代碼中增加一個變量「thisIsMe」用于識別前綴:

<!-- wepyhtml-repeat start -->
<template name="wepyhtml-0">
	{{ thisIsMe }}
	<block wx:if="{{ content }}" wx:for="{{ content }}">
		<block wx:if="{{ item.type === 'node' }}">
			<view class="wepyhtml-tag-{{ item.name }}">
				<!-- next template -->
			</view>
		</block>
		<block wx:else>{{ item.text }}</block>
	</block>
</template>
<!-- wepyhtml-repeat end -->

然后修改構建代碼:

replace(match, tpl) {
	let result = '';
	let prefix = '';

    // 匹配 thisIsMe 的前綴
	tpl = tpl.replace(/\{\{\s*(\$.*?\$)thisIsMe\s*\}\}/, (match, p) => {
		prefix = p;
		return '';
	});

	for (let i = 0; i <= 20; i++) {
		result += '\n' + tpl
			.replace('wepyhtml-0', 'wepyhtml-' + i)
			.replace(/<\!-- next template -->/g, () => {
				return i === 20 ?
					'' :
					`<template is="wepyhtml-${ i + 1 }" wx:if="{{ item.children }}" data="{{ ${ prefix }content: item.children }}"></template>`;
			});
	}

	return result;
}

至此,渲染問題就解決了。

圖片

為了節省流量和提高加載速度,展示富文本內容時,一般都會按照所需尺寸對里面的圖片進行縮小,點擊小圖進行預覽時才展示原圖。這主要涉及節點屬性的修改:

  • 把圖片原路徑(src屬性值)存到自定義屬性(例如「data-src」)中,并將其添加到預覽圖數組。
  • 把圖片的src屬性值修改為縮小后的圖片URL(一般云服務商都有提供此類URL規則)。
  • 點擊圖片時,使用自定義屬性的值進行預覽。

為了實現這個需求,本組件在解析節點時提供了一個鉤子( onNodeCreate ):

onNodeCreate(name, attrs) {
	if (name === 'img') {
		attrs['data-src'] = attrs.src;
		// 預覽圖數組
		this.previewImgs.push(attrs.src);
		// 縮圖
		attrs.src = resizeImg(attrs.src, 640);
	}
}

對應的模板和事件處理邏輯如下:

<template name="wepyhtml-img">
	<image class="wepyhtml-tag-img" mode="widthFix" src="{{ elem.attrs.src }}" data-src="{{ elem.attrs['data-src'] || elem.attrs.src }}" @tap="imgTap"></image>
</template>
// 點擊小圖看大圖
imgTap(e) {
	wepy.previewImage({
		current: e.currentTarget.dataset.src,
		urls: this.previewImgs
	});
}
視頻

在小程序中,video組件的層級是較高的(且無法降低)。如果頁面設計上存在著可能擋住視頻的元素,處理起來就需要一些技巧了:

  • 隱藏video組件,用image組件(視頻封面)占位;
  • 點擊圖片時,讓視頻全屏播放;
  • 如果退出了全屏,則暫停播放。

相關代碼如下:

<template name="wepyhtml-video">
	<view class="wepyhtml-tag-video" @tap="videoTap" data-nodeid="{{ elem.nodeId }}">
		<!-- 視頻封面 -->
		<image class="wepyhtml-tag-img wepyhtml-tag-video__poster" mode="widthFix" src="{{ elem.attrs.poster }}"></image>
		<!-- 播放圖標 -->
		<image class="wepyhtml-tag-img wepyhtml-tag-video__play" src="./imgs/icon-play.png"></image>
		<!-- 視頻組件 -->
		<video style="display: none;" src="{{ elem.attrs.src }}" id="wepyhtml-video-{{ elem.nodeId }}" @fullscreenchange="videoFullscreenChange" @play="videoPlay"></video>
	</view>
</template>
{
	// 點擊封面圖,播放視頻
	videoTap(e) {
		const nodeId = e.currentTarget.dataset.nodeid;
		const context = wepy.createVideoContext('wepyhtml-video-' + nodeId);
		context.play();
		// 在安卓微信下,如果視頻不可見,則調用play()也無法播放
		// 需要再調用全屏方法
		if (wepy.getSystemInfoSync().platform === 'android') {
			context.requestFullScreen();
		}
	},
	// 視頻層級較高,為防止遮擋其他特殊定位元素,造成界面異常,
	// 強制全屏播放
	videoPlay(e) {
		wepy.createVideoContext(e.currentTarget.id).requestFullScreen();
	},
	// 退出全屏則暫停
	videoFullscreenChange(e) {
		if (!e.detail.fullScreen) {
			wepy.createVideoContext(e.currentTarget.id).pause();
		}
	}
}
開源

最后貼一下「WePY HTML」的項目倉庫: https://github.com/beiliao-web-frontend/wepy-html ,具體使用方法見項目內的 README 。如果你在使用過程中遇到了問題,或者是有好的建議和意見,都可以在 Issues 中提出。

重磅推薦:小程序開店目錄

第一部分:小商店是什么

第二部分:如何開通一個小商店

第三部分:如何登錄小商店

第四部分:開店任務常見問題

第五部分:小商店可以賣什么

第六部分:HiShop小程序特色功能

第七部分:小程序直播

第八部分:小程序收貨/物流

第九部分:小程序怎么結算

第十部分:小程序客服

第十一部分:電商創業

第十二部分:小程序游戲開發

電話咨詢 微信咨詢 預約演示 0元開店
主站蜘蛛池模板: 国产精品丝袜在线观看|日本女人xx|中美性猛交xxxx乱大交3|99久久久久久久久久|#NAME?|国产精品绯色蜜臀99久久 | 7777欧美成是人在线观看|无码=aV中文一区二区三区桃花岛|日本精品久久久久久久久久|一级做=a爰片|成人综合一区二区|99热热精品 | 澳门成免费crm大全|日韩在线精品成人=aV|精品国产一区二区三区成人影院|日韩=av中文无码影院|久久最新金品视频免费播放|国产精品1卡2卡3卡4卡 | 丰满人妻熟妇乱又伦精品|黑白配高清国语免费观看|#NAME?|亚洲视频高清不卡在线观看|99ri=av国产在线观看|丝袜美腿视频一区二区三区 | 国产高清精品亚洲а∨|一本久道久久综合狠狠爱亚洲精品|久久国产福利|久久久久www|无码人妻精品一区二区三区99不卡|亚V=a芒果乱码一二三四区别 | 吃奶摸下的激烈视频|亚洲人成网站18禁止中文字幕|无码=aV天堂一区二区三区|男人猛躁进女人视频免费播放|精品一区在线观看视频|欧美午夜=a级限制福利片 | 49vv亚洲|成人一级网站|九月婷婷人人澡人人添人人爽|国产精品69毛片高清亚洲|五月婷婷天堂|特黄=a级毛片免费视频 | 中文字幕无码免费久久91|wwwwww在线观看|白天操夜夜操|92福利视频1000免费|69精品丰满人妻无码视频=a片|97在线中文字幕免费公开视频 | 亚洲精品萌白酱一区|日本二三区不卡|国产精品一二三区夜夜躁|欧美激情日韩|91啦中文在线|99精品国产丝袜在线拍国语 | 亚洲线精品一区二区三区|亚洲综合中文|特级一级片|在线观看国产视频一区|国产乱码卡1卡二卡3卡四卡|国产v亚洲v天堂无码网站 | 青娱乐极品视觉盛宴=av|国产成人=av无码片在线观看|国产网站入口|国产一区二区=av|星空天美mv视频大全免费观看|曰韩一级片 | 天天干天天插伊人网|久久久久久一级片|粉嫩久久久久久久极品|人人插人人搞|五月丁香六月综合缴清无码|国产精华=aV午夜在线 | 成人免费=av在线播放|国产CHINESEHDXXXX宾馆TUBE|夜夜夜夜夜夜爽噜噜噜噜噜噜|午夜理论在线观看无码|亚洲人ⅴs=aⅴ国产精品|91免费影视 | 黄视频日本|超碰=av免费|婷婷色综合视频在线观看|午夜免费视频|久色网站|成人网在线 | 青草国产精品久久久久久|公和我做好爽添厨房中文字幕|99re6这里有精品热视频|六月婷婷精品视频在线观看|女教师办公室被强在线播放|日韩一区二区三区不卡视频 | 2019久久久|91女同|#NAME?|亚洲福利在线视频|国产猛烈高潮尖叫视频免费|久久精品国产72国产精 | 一本到亚洲网|99久久精品国产欧美主题曲|973理论片235影院|国产一区二区高清在线|亚州国产视频|国产精品一卡二卡三卡 | 国产www成人|干干操操|国产久一一精品|日韩综合在线播放|二区视频|九九国产视频 | 久久99国产一区二区三区|99热这里只有精|护士做xxxxx免费看国产|色情一区二区三区免费看|亚洲天堂精品在线|欧美极品kenn=aj=ames喷水 | 久久国产福利一区二区|一本色道久久88精品综合|亚洲学生妹高清=av|WWW亚洲色大成网络|免费在线观看成人=av|亚洲天堂资源在线 | 国产草莓精品国产=av片国产|91影视在线|76少妇国内精品视频|中文字幕人妻丝袜美腿乱|国产日韩欧美视频免费看|国产精品久久无码一区 | 精品视频在线一区二区在线|码亚洲中文无码=av在线|九九九国产精品成人免费视频|国产露脸对白88=av|天天艹日日干|中文字幕久久精品一二三区 | 国产精品nxnn|精品欧美一区二区三区在线观看|色88久久久久高潮综合影院|最好看的2018中文在线观看|#NAME?|91国偷自产中文字幕久久 | 少妇被躁爽到高潮无码文|人人看人人摸|99国产欧美久久久精品|亚洲精品无码一区二区三区久久久|国产91导航|毛片在线网址 | 婷婷久久综合九色综合97最多收藏|国产一级毛片久久|91精品二区|思思99精品视频在线观看|国产福利第一视频在线播放|人人澡超碰碰 | 大东北CHINESEXXXX露脸|中文字幕人妻偷伦在线视频|精品一区二区三区毛片|亚洲熟妇丰满xxxxx小品|毛片=av网站|#NAME? | 激情婷婷开心五月综合|国产区免费视频|欧美精品一区二区三区免费播放|亚洲一级片免费看|国产精品边做奶水狂喷无码|久久8精品 | 久久国产精品精品|#NAME?|色免费观看|日韩乱码人妻无码中文视频|亚洲天堂777|天堂成人 | 秋霞福利视频|亚洲精品1234区|国产一级久久久久|在线91|国产做=a爱片久久毛片=a片|天天爱天天做天天做天天吃中文 | 久久精品九九热无码免贵|日本=aⅴ精品一区二区三区|亚洲国产精品一区二区成人片|国产精品91久久|久草=av在线播放|亚洲在线www | 少妇精品|欧美大逼视频|一级做=a爱片特黄在线观看|日本乱码伦视频免费播放|亚洲精品在线观看=av|久久久久久久久久久久久久=av | 女同互慰高潮呻吟免费播放|精品视频在线99|国产美女视频免费的|国产另类ts人妖高潮|欧美黄色片免费观看|一起操视频在线观看 | 免费无码成人=aV在线播放不卡|美女一区二区三区四区|男女激情麻豆|4虎四虎永久在线精品免费|黄色录像www|顶级丰满少妇自慰到喷水 | 6996网站免费观看|麻豆传媒免费在线观看|欧美多p视频|老司机午夜在线|亚洲国产高清理论片|国产在线高清观看 | 国产婷婷综合在线视频中文|人人超人人超碰超国产97超碰|一区二区动漫|中国农村毛片免费播放|久久综合久久久久88|男女猛烈啪啪无遮挡免费观看 | 久久精品国产91|精品不卡高清视频在线观看|毛片网子|操操操日日日|国产福利一|中文字幕色欲=aV亚洲二区 | 女明星一级毛片|国产精品成人v=a|久久天天躁狠狠躁夜夜躁2012|久热这里只有精|国产黄大片在线观看|国产成人在线播放视频 | 亚洲视频在线观看一区二区|涩涩资源中文字幕久久婷婷爱|少妇精品无码一区二区三区|69激情网|影音先锋每日=aV色资源站|chin=a中国人妻video | 国产最新在线观看|久久黄页|在线不卡日本v二区707|成人免费一区二区三区在线观看|欧美又粗又大色情hd堕落街传奇|免费观看全黄做爰的视频 | 爱情到此为止在线观看|精品热99|老熟女多次高潮露脸视频|91国偷自产一区二区三区老熟女|美女久久久久久久久|高潮VPSWINDOWS国产乱 | 国产亚洲精品一区二区三区|狠狠插综合网|把女人弄爽特黄=a大片3人|国产精品99久久久久久人免费|永夜星河免费在线观看|日日做=a爰片久久毛片=a片英语 |