<p>思路</p><p>既然wxParse能够显示富文本而且它的思路是将整个HTML String转换成一个Node数组,数组按照传入的HTML String生成HTML DOM结构。所以既然它能够处理每一个DOM,那么我们也可以在其中的一环上做一些事情,例如标注。然而实际开发的时候是在显示的时候进行处理的。</p><p>分析wxParse</p><p>wxParse的使用文档里写的很清楚。</p><p>WxParse.wxParse('article', 'html', article, that, 5);</p><p>在对应的Component或者page组件中调用其这句话,其实就是将article处理成node数组,存在that的‘article’字段里,而that就是一个component组件。</p><p>接下来</p><p>// 引入模板</p><p><import src="你的路径/wxParse/wxParse.wxml"/></p><p>//这里data中article为bindName</p><p><template is="wxParse" data="{{wxParseData:article.nodes}}"/></p><p>通过这个template来进行展示,基本思路就是这样子。</p><p>这个wxParse.wxml目前是一个拥有11层的template嵌套,也就是最多支持11层的DOM树了。</p><p>然而这是无法满足我们的需求的,因为标注功能需要操作DOM,也就是通过点击,你要知道你点了哪一个DOM,而template在目前的版本是无法传递方法的。所以有了接下来的故事,也就是把wxParse组件化,将其变为组件不就可以传递方法到最内层,然后做任何事情了嘛。</p><p>组件化</p><p>组件化之后的结构长这样,其实就是把template中的每一层都抽出来写成组件,而转node数组的那部分,还是用之前的方法,这里只是负责显示的部分。</p><p><img src="/up_pic/201907/061007345487.png" title="061007345487.png" alt="1.png"/></p><p>组件化后的结构.png</p><p>wxEmojiView、wxParseBr、wxParseImg、wxParseVideo等等都是简单的组件,负责显示传入的DOM就可以了,而wxParse比较复杂一些,根据node的类型,来指定渲染哪些组件。直接贴代码大家感受一下吧。</p><p>这里出现了组件自身又引用自身的情况(第5行),这个在微信小程序原生开发中是可行的。</p><p><block wx:if="{{item.node == 'element'}}"></p><p> <block wx:if="{{item.tag == 'button'}}"></p><p> <button type="default" size="mini"></p><p> <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""></p><p> <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse></p><p> </block></p><p> </button></p><p> </block></p><p> <!--li类型--></p><p> <block wx:elif="{{item.tag == 'li'}}"></p><p> <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"></p><p> <view class="{{item.classStr}} wxParse-li-inner"></p><p> <view class="{{item.classStr}} wxParse-li-text"></p><p> <view class="{{item.classStr}} wxParse-li-circle"></view></p><p> </view></p><p> <view class="{{item.classStr}} wxParse-li-text"></p><p> <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""></p><p> <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse></p><p> </block></p><p> </view></p><p> </view></p><p> </view></p><p> </block></p><p> <!--video类型--></p><p> <block wx:elif="{{item.tag == 'video'}}"></p><p> <custom-parse-video item="{{item}}"></custom-parse-video></p><p> </block></p><p> <!--img类型--></p><p> <block wx:elif="{{item.tag == 'img'}}"></p><p> <custom-parse-img item="{{item}}"></custom-parse-img></p><p> </block></p><p> <!--a类型--></p><p> <block wx:elif="{{item.tag == 'a'}}"></p><p> <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"></p><p> <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""></p><p> <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse></p><p> </block></p><p> </view></p><p> </block></p><p> <block wx:elif="{{item.tag == 'table'}}"></p><p> <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"></p><p> <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""></p><p> <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse></p><p> </block></p><p> </view></p><p> </block></p><p> <block wx:elif="{{item.tag == 'br'}}"></p><p> <custom-parse-br item="{{item}}"></custom-parse-br></p><p> </block></p><p> <!--其他块级标签--></p><p> <block wx:elif="{{item.tagType == 'block'}}"></p><p> <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"></p><p> <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""></p><p> <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse></p><p> </block></p><p> </view></p><p> </block></p><p> <!--内联标签--></p><p> <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"></p><p> <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""></p><p> <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse></p><p> </block></p><p> </view></p><p> </block></p><p> <!--判断是否是文本节点--></p><p> <block wx:elif="{{item.node == 'text'}}"></p><p> <!--如果是,直接进行--></p><p> <custom-emoji-view item="{{item}}" bind:onMark="onMark" notes="{{notes}}"></custom-emoji-view></p><p> </block></p><p>完成之后,只需要在你需要的地方调用这个组件就可以了。</p><p><html-view id="htmlView" wxParseData="{{nodes}}"</p><p> notes="{{notes}}"</p><p> bind:onMark="onMark"</p><p> bind:unMark="unMark"</p><p> bind:wxParseImgTap="wxParseImgTap" bind:wxParseImgLoad="wxParseImgLoad" ></html-view></p><p>需要哪些方法,就可以像其他组件一样,往内部传递下去就行了。只需要在最内层设置一下冒泡和跨越组件边界就可以了</p><p>onMark: function (event) {</p><p> var myEventOption = { bubbles: true, composed:true} // 触发事件的选项</p><p> this.triggerEvent('onMark', event, myEventOption);</p><p> }</p><p>在Taro(bate3)中使用</p><p>因为开发中遇到了全局状态管理的的问题,第二版采用Taro重构。在这个功能上又遇到了问题,我试图用同样的思路来组件化。然后Taro目前的版本还没有解决组件嵌套自身的问题,大家可以看我箭头,这是在CustomParse组件中,在第二个箭头的位置,又引用了它自身。这种写法,会导致编译的时候循环引用。我猜想是编译转成小程序原生结构的时候,导致了死循环。所以这个方法就行不通了。</p><p><img src="/up_pic/201907/061008103056.png" title="061008103056.png" alt="2.png"/></p>