在微信小程序中渲染HTML内容的方法示例(2)

以下为需要重复嵌套的模板(精简过),在其代码的开始前和结束后分别插入特殊注释进行标识,并在需要嵌入下一层模板的地方以另一段特殊注释(「」)标识:

<!-- wepyhtml-repeat start --> <template> <block wx:if="{{ content }}" wx:for="{{ content }}"> <block wx:if="{{ item.type === 'node' }}"> <view> <!-- 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」在生成组件代码时,为了避免组件数据与页面数据的变量名冲突,会 根据一定的规则给组件的变量名增加前缀 (如上面代码中的「

wepyHtml$」)。所以在生成嵌套模板时,也必须使用带前缀的变量名。

先在组件代码中增加一个变量「thisIsMe」用于识别前缀:

<!-- wepyhtml-repeat start --> <template> {{ thisIsMe }} <block wx:if="{{ content }}" wx:for="{{ content }}"> <block wx:if="{{ item.type === 'node' }}"> <view> <!-- 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> <image 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> <view @tap="videoTap" data-nodeid="{{ elem.nodeId }}"> <!-- 视频封面 --> <image mode="widthFix" src="{{ elem.attrs.poster }}"></image> <!-- 播放图标 --> <image src="https://www.jb51.net/article/imgs/icon-play.png"></image> <!-- 视频组件 --> <video src="{{ elem.attrs.src }}" @fullscreenchange="videoFullscreenChange" @play="videoPlay"></video> </view> </template></pre> <pre>{ // 点击封面图,播放视频 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(); } } }

开源

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/efb1e4f0e83a05811234eb616089391c.html