微信小程序开发之wxParse组件化

背景

6月的时候,公司有个小程序项目是展示一些微信公众号文章。因为获取的文章内容都是HTML DOM的结构。在小程序里面如果简单地通过RichText展示,可能会出现一些样式和原文不一致的问题。还有一个需求是要在文章内进行一些选择、标注的操作。这时候就不可避免地要将HTML String转成HTML DOM进行处理、显示。而wxParse就是这样做的。

功能1.gif

思路

既然wxParse能够显示富文本而且它的思路是将整个HTML String转换成一个Node数组,数组按照传入的HTML String生成HTML DOM结构。所以既然它能够处理每一个DOM,那么我们也可以在其中的一环上做一些事情,例如标注。然而实际开发的时候是在显示的时候进行处理的。

分析wxParse

wxParse的使用文档里写的很清楚。

WxParse.wxParse('article', 'html', article, that, 5);

在对应的Component或者page组件中调用其这句话,其实就是将article处理成node数组,存在that的‘article’字段里,而that就是一个component组件。
接下来

// 引入模板
<import src="你的路径/wxParse/wxParse.wxml"/>
//这里data中article为bindName
<template is="wxParse" data="{{wxParseData:article.nodes}}"/>

通过这个template来进行展示,基本思路就是这样子。
这个wxParse.wxml目前是一个拥有11层的template嵌套,也就是最多支持11层的DOM树了。
然而这是无法满足我们的需求的,因为标注功能需要操作DOM,也就是通过点击,你要知道你点了哪一个DOM,而template在目前的版本是无法传递方法的。所以有了接下来的故事,也就是把wxParse组件化,将其变为组件不就可以传递方法到最内层,然后做任何事情了嘛。

组件化

组件化之后的结构长这样,其实就是把template中的每一层都抽出来写成组件,而转node数组的那部分,还是用之前的方法,这里只是负责显示的部分。


组件化后的结构.png

wxEmojiView、wxParseBr、wxParseImg、wxParseVideo等等都是简单的组件,负责显示传入的DOM就可以了,而wxParse比较复杂一些,根据node的类型,来指定渲染哪些组件。直接贴代码大家感受一下吧。
这里出现了组件自身又引用自身的情况(第5行),这个在微信小程序原生开发中是可行的。

<block wx:if="{{item.node == 'element'}}">
    <block wx:if="{{item.tag == 'button'}}">
      <button type="default" size="mini">
        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
          <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse>
        </block>
      </button>
    </block>
    <!--li类型-->
    <block wx:elif="{{item.tag == 'li'}}">
      <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
        <view class="{{item.classStr}} wxParse-li-inner">
          <view class="{{item.classStr}} wxParse-li-text">
            <view class="{{item.classStr}} wxParse-li-circle"></view>
          </view>
          <view class="{{item.classStr}} wxParse-li-text">
            <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
               <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse>
            </block>
          </view>
        </view>
      </view>
    </block>

    <!--video类型-->
    <block wx:elif="{{item.tag == 'video'}}">
      <custom-parse-video item="{{item}}"></custom-parse-video>
    </block>

    <!--img类型-->
    <block wx:elif="{{item.tag == 'img'}}">
      <custom-parse-img item="{{item}}"></custom-parse-img>
    </block>

    <!--a类型-->
    <block wx:elif="{{item.tag == 'a'}}">
      <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
           <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse>
        </block>
      </view>
    </block>
    <block wx:elif="{{item.tag == 'table'}}">
      <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
           <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse>
        </block>
      </view>
    </block>

    <block wx:elif="{{item.tag == 'br'}}">
      <custom-parse-br item="{{item}}"></custom-parse-br>
    </block>
    <!--其他块级标签-->
    <block wx:elif="{{item.tagType == 'block'}}">
      <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
        <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
           <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse>
        </block>
      </view>
    </block>

    <!--内联标签-->
    <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
      <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
         <custom-parse item="{{item}}" notes="{{notes}}"></custom-parse>
      </block>
    </view>

  </block>

  <!--判断是否是文本节点-->
  <block wx:elif="{{item.node == 'text'}}">
    <!--如果是,直接进行-->
    <custom-emoji-view item="{{item}}" bind:onMark="onMark" notes="{{notes}}"></custom-emoji-view>
  </block>

完成之后,只需要在你需要的地方调用这个组件就可以了。

<html-view id="htmlView" wxParseData="{{nodes}}"
          notes="{{notes}}"
          bind:onMark="onMark" 
          bind:unMark="unMark"
          bind:wxParseImgTap="wxParseImgTap" bind:wxParseImgLoad="wxParseImgLoad" ></html-view>

需要哪些方法,就可以像其他组件一样,往内部传递下去就行了。只需要在最内层设置一下冒泡和跨越组件边界就可以了

onMark: function (event) {
      var myEventOption = { bubbles: true, composed:true} // 触发事件的选项
      this.triggerEvent('onMark', event, myEventOption);
    }

在Taro(bate3)中使用

因为开发中遇到了全局状态管理的的问题,第二版采用Taro重构。在这个功能上又遇到了问题,我试图用同样的思路来组件化。然后Taro目前的版本还没有解决组件嵌套自身的问题,大家可以看我箭头,这是在CustomParse组件中,在第二个箭头的位置,又引用了它自身。这种写法,会导致编译的时候循环引用。我猜想是编译转成小程序原生结构的时候,导致了死循环。所以这个方法就行不通了。


CustomParse.png

然后,产品是不会管怎么实现的,明天上线!
所以为了顺利上线,我用了最土鳖的办法,直接把上一个版本的这部分代码直接复制到了Taro打包好的dist文件夹中,经过复杂的调试,因为还要相关用到的组件一起copy,最终搞定,留下的一个问题就是在copy进来的组件中没有享受到了Taro Redux的福利,所以这个组件相当于是一个没有状态的死组件,孤单地游离在外面...

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 这个月断断续续的看完了一本书,还看几篇短文以及一些专业相关的文章。但是,我自己在读书的过程总感觉到无聊与...
    lyxu阅读 368评论 0 1
  • 1.总有一个人教会你成长然后悄无声息的离开。 2.一个人对待身份卑微人的态度,往往能反映出他的真正修养。 3.时间...
    许小敬阅读 181评论 2 1
  • 天空永远留不下大雁飞过翅膀的痕迹,大地永远留不下人们刻在昨天的影子,噼里啪啦的鞭炮声在夜空里回响,能在春节文艺晚会...
    旋旋的读书随笔阅读 161评论 0 0
  • 告白嘛 ,就是一个人喜欢另一个人,因为喜欢而去表达自己的心意。 说实话,随年龄数字的慢慢变大,以一个看客的身份...
    汐貝丹丹阅读 385评论 0 1