Skip to content

Latest commit

 

History

History
483 lines (457 loc) · 25.6 KB

File metadata and controls

483 lines (457 loc) · 25.6 KB

使用方法

  • 插件包说明

    名称 大小 使用
    Parser 39.7KB 微信小程序插件包
    Parser.min 28.3KB 微信小程序插件包压缩版(功能相同)
    Parser.bd 36.9KB 百度小程序插件包
    Parser.bd.min 26.7KB 百度小程序插件包压缩版(功能相同)
    Parser.uni 48.4KB uni-app 插件包(可以编译到所有平台)
    • 关于百度版与微信版的差别,可见百度版与微信版的差别
    • uni-app版因为各平台rich-text和自定义组件表现有所不同,有较多条件编译的内容,编译后大小会缩小,关于各平台间的差别和与原生包的差别,可见uni-app包说明
    • 可根据需要选用,使用时建议统一更名为Parser,以下统称Parser
       
  • 在原生框架中使用

    1. 下载Parser文件夹至小程序目录
    2. 在需要引用的页面的json文件中添加(百度小程序中组件名一定要小写
      {
        "usingComponents": {
          "parser":"/Parser/index"
        }
      }
    3. 在需要引用的页面的wxml文件中添加
      <parser html="{{html}}" />
    4. 在需要引用的页面的js文件中添加
      data: {
        html:"<div>Hello World!</div>"
      }
    • demo文件夹下的是微信小程序 富文本插件 示例程序的源码,可供参考
       
  • uni-app中使用

    • 使用uni-app包(可以编译到所有小程序平台)
      1. 下载Parser.uni包到component目录下(更名为Parser
      2. 在需要使用页面的vue文件中添加
        <template>
          <view>
            <parser :html="html"></parser>
          </view>
        </template>
        <script>
        import parser from "@/components/Parser/index"
        export default{
          components: {
            parser
          },
          data() {
            return {
              html: '<div>Hello World!</div>'
            }
          }
        </script>
    • 使用原生包
      参考官网-小程序组件支持
       
  • mpVue中使用

    1. 下载Parser文件夹至static目录下
    2. src目录下需要使用本插件的页面文件夹下添加json文件
      {
          "usingComponents": {
              "parser": "../../static/Parser/index"
          }
      }
    3. 在需要使用的页面的vue文件中添加
      <template>
        <div class="container">
          <parser :html="html"></parser>
        </div>
      </template>
      <script>
      export default {
        data: {
          html: '<div>Hello World!</div>'
        }
      }
      </script>
    • 注意:mpvueuni-app中使用时组件名必须小写
       
  • wepy中使用
    测试版本:V1.7.3

    • 方法一
      1. 通过wepy build --no-cache --watch命令编译(一定要有--no-cache,否则可能出现Components not found的错误)

      2. Parser文件夹复制到/src/components目录下

      3. 如果没有使用document补丁包,删除Parser/index.js中第25到30行;如果没有使用emoji补丁包,删除Parser/Parser.js中148到151行(这两个地方都是通过try来引入文件,但在wepy中还是会出文件不存在的错误)

        // Parser/index.js
        created() {
          try {
            const Document = require("./document.js");
            this.document = new Document();
          } catch (e) {}
        },
        // Parser/Parser.js
        try {
          var emoji = require("./emoji.js");
          data = emoji.parseEmoji(data);
        } catch (err) {}
      4. 在需要使用的页面的wpy文件中添加

        <template>
          <view class="container">
            <Parser html="{{html}}"></Parser>
          </view>
        </template>
        <script>
        import wepy from 'wepy'
        export default class Index extends wepy.page {
          config = {
            usingComponents: {
              'Parser': '/components/Parser/index'
            }
          }
          data = {
            html: '<div>Hello World!</div>',
          }
        }
        </script>
    • 方法2
      1. Parser文件夹复制到/dist/components文件夹下(注意是dist不是src
      2. 同方法一的第4步
      • 这种方法wepy不会对插件包进行编译和压缩
         
  • 组件属性:

    属性 类型 默认值 必填 说明
    html String/Object/Array 要显示的富文本数据,具体格式见下方说明
    tag-style Object 设置标签的默认样式
    autocopy Boolean true 是否允许链接受到点击时自动复制链接(仅限http开头的网络链接)
    autopause Boolean true 是否允许播放视频时自动暂停其他视频
    autopreview Boolean true 是否允许点击图片时自动预览
    autosetTitle Boolean true 是否自动将title标签的内容设置到页面标题上
    img-mode String default 图片显示模式
    lazy-load Boolean false 是否开启图片懒加载
    selectable Boolean false 是否允许长按复制内容
    show-with-animation Boolean false 是否使用渐显动画
    animation-duration Number 400 动画持续时间
    • html格式:
      1. string类型:一个html字符串,例如:<div>Hello World!</div>
      2. object类型:一个形如{nodes: [Array], imgList: [Array], title: "String"}的结构体,其中nodes数组的格式基本同rich-text,对于该节点下有imgvideoa标签的,需要将continue属性设置为true,否则将直接使用rich-text组件渲染,可能导致图片无法预览,链接无法点击等问题,imgList为其中所有图片地址的数组,title是页面的标题(不必要,传入将会设置到页面的标题上),回调函数bindparser的返回值就是这样的结构体
      3. array类型:格式要求同上(用此格式传入预览图片时,将不能通过左右滑动查看所有图片)
      4. 使用b, c方法可以节省解析的时间,提高性能
    • 关于img-mode 默认default,在没有设置宽高时,按图片原大小显示;设置了宽或高时,按比例进行缩放;同时设置了宽高时,按设置的宽高进行缩放。在同时设置了宽高的情况下,宽度可能因为max-width:100%的限制而缩短导致图片变形,此时可将模式设置为widthFix,即保持宽度不变,高度自动变化(会导致设置的高度无效)
    • 关于tag-style
      可以设置标签的默认样式,如{ body:"margin:5px" };仅传入的htmlString类型时有效(在解析过程中设置)
       
  • 回调函数

    名称 功能 说明
    bindparser 在解析完成时调用(仅当传入的html为字符串时会调用) 返回一个object,其中 nodes为解析后的节点数组,imgList为图片列表,title是页面标题,该object可以在下次调用直接作为html属性的值,节省解析的时间
    bindready 渲染完成时调用 返回整个组件的NodesRef结构体,包含宽度、高度、位置等信息(每次html修改后都会触发)
    binderror 出错时调用 返回一个object,其中source是错误来源(ad广告出错、video视频加载出错、audio音频加载出错、parse解析过程中出错),errMsg为错误信息,errCode是错误代码(仅ad),target包含出错标签的具体信息
    bindimgtap 在图片受到点击时调用 返回一个形如{src:...}的结构体(src是图片链接),可用于阻挡onShow的调用
    bindlinkpress 在链接受到点击时调用 返回一个形如{href:...}的结构体(href是链接地址),开发者可以在该回调中进行进一步操作,如下载文档和打开等
    • 所有回调函数的返回值从e.detail中获取
       
  • 使用外部样式
    如果需要使用一些固定的样式,可以通过wxss / css文件引入
    /Parser/trees/trees.wxss(css)中通过@import引入自定义的样式文件即可

    /*
    * Parser/trees/trees.wxss(css)
    * 在这里引入您的自定义样式
    */
    @import "external.wxss(css)";

    注意事项:

    1. 由于只有自定义组件内的样式在组件内能生效且rich-text在组件内使用时也只能匹配组件内的样式,所以必须在trees组件的wxss/css文件中引入需要的样式,在页面中写的样式无效
    2. 组件内只能使用class选择器(支持后代选择器),不支持id选择器、属性选择器、标签名选择器等(更多可见官网说明
    3. 通过这种方式引入的样式会对所有parser标签生效,如果是对单个parser使用的样式,请使用style标签
       
  • 关于基础库
    微信小程序:

    版本 功能 覆盖率
    >=2.2.5 全部正常 99.19%
    1.9.3-2.2.4 部分html实体无法显示 0.68%
    1.6.3-1.9.2 部分html实体无法显示
    不支持lazy-load属性
    0.05%
    <1.6.6 无法使用 0.05%

    百度小程序:

    版本 功能 覆盖率
    >=1.10.13 全部正常 100%
  • Api

    • html2nodes
      功能:解析html字符串
      参数:html(要解析的字符串), tagStyle(默认的标签样式)
      返回值:同bindparse,可作为html属性的参数
      const Api=require("path/Parser/api.js");
      Api.html2nodes("<div>Hello World!</div>").then(res=>{
        console.log(res);
      })
    • css2object
      功能:解析css字符串
      参数:style(要解析的字符串), tagStyle(已有的样式)
      返回值:一个形如{key: value}的结构体,可作为tag-style属性的值
      const Api=require("path/Parser/api.js");
      console.log(Api.css2object(".demo{text-align:center;}"));
      //{.demo:"text-align:center;"}
    • versionHigherThan
      功能:判断当前设备的基础库版本是否高于或等于输入的版本
      参数:version(要比较的基础库版本号)
      返回值:若当前设备的基础库版本高于或等于输入的版本,返回true,否则返回false
      const Api=require("path/Parser/api.js");
      console.log(Api.versionHigherThan("2.7.1"));
    • String.splice
      功能:对字符串的指定位置进行删改(类似于数组的splice方法)
      参数:start(开始修改的位置,为负数时表示倒数第几个), deleteCount(要删除的字符个数), addStr(要添加的字符串)
      返回值:修改后的字符串(该方法不改变原字符串,不需要引入文件)
      var Str="Hello world!";
      Str=Str.splice(6,1,'W');
      console.log(Str);
      //Hello World
  • Tips

    • 表格和列表由于较难通过模板循环的方式显示,将直接通过rich-text进行渲染,因此请尽量避免在列表和表格中加入图片或链接,否则将无法预览或点击(但可以正常显示)(列表引入list补丁包后可以解决这个问题)
    • 若需要自定义链接受到点击时的效果,可对Parser/trees文件夹下的trees.wxss中的navigator-hover进行修改(默认下划线+半透明)

补丁包

patches文件夹中准备了一些补丁包,可根据需要选用,可以实现更加丰富的功能

emoji

  • 功能
    将形如[笑脸]的文本解析为emoji小表情
  • 大小
    4.70KBmin版本3.61KB
  • 使用方法
    emoji.js复制到Parser文件夹下即可(若使用min版本也要改名为emoji.js
    默认配置中支持177个常用的emoji小表情
    支持两种形式的emoji,一是emoji字符(不同设备上显示的样子可能不同),或者是网络图片(将按照16px × 16px的大小显示,且不可放大预览),默认配置中都是emoji字符,可使用以下api获取或修改:
    const parserEmoji = require("path/Parser/emoji.js");
    console.log(parserEmoji.getEmoji("笑脸")); //笑脸的emoji字符
    parserEmoji.removeEmoji("笑脸"); //移除笑脸emoji
    parserEmoji.setEmoji("哈哈","https://example.png"); //设置emoji,支持emoji字符或网络图片
    emoji演示

document

  • 功能
    实现类似于web中的document对象,可以动态操作DOM

  • 大小
    4.66KBmin版本3.61KB

  • 使用方法
    document.js复制到Parser文件夹下即可(若使用min版本也要改名为document.js

    • document
      获取方式:可通过 this.selectComponent("#id").document 获取
      Api列表:

      名称 输入值 返回值 功能
      getElementById id element 按照id查找element
      getChildren i element 获取根节点的第i个子节点的element实例
    • element
      属性名:

      名称 功能
      id 该节点的id值
      nodes 该节点的结构体,可以直接对这个结构体进行修改(修改后需要调用update方法同步到UI,修改时要注意格式,更建议使用下方的api方法进行修改)

      Api列表:

      名称 输入值 返回值 功能
      getText text 获取文本内容(仅直接包含文本的标签可用)
      setText text 修改文本内容(仅直接包含文本的标签可用)
      addChildren nodes, i 在第i个位置添加子节点,nodes为一个结构体,格式同rich-text
      removeChildren i 移除第i个子节点
      getChildren i 获取第i个子节点的element示例
      getAttr key attr 获取某个属性值
      setAttr key, value 设置某个属性值
      getElementById id element 在子节点中按照id查找element
      update 若修改了element.nodes需要调用此方法同步到UI
    • 返回格式
      若执行成功,返回{ok:true, data:...};若不成功,返回{ok:false, errCode:..., errMsg:...}
      错误码

      错误码 含义
      1 对没有直接包含text的标签执行getTextsetText
      2 输入值类型不正确
      3 输入值超出范围
      4 无法找到对应id的节点
  • 注意事项
    所有方法必须在htmlsetData完成后才能调用
    每次执行除了get以外的方法都需要进行一次局部的setData更新,请不要过于频繁的调用,否则可能影响性能。

  • 综合示例

    <Parser id="article" html="{{html}}" binderror="error" />
    data:{
      html:'...<div id="adContainer"><ad unit-id="..."></ad></div>...'
    }
    error(e){
      // 广告组件加载出错
      if(e.detail.source == "ad"){
        // 获取document
        var document = this.selectComponent("#article").document;
        // 查找广告框容器
        var res = document.getElementById("adContainer");
        if (res.ok)
          res.data.setAttr("style","display:none"); // 隐藏广告容器
        else
          console.error(res.errMsg); // 查找失败
      }
    }

list

  • 背景
    在原插件中,由于列表较难通过模拟实现,是直接使用rich-text来显示列表,这导致列表中的图片无法预览,链接无法点击,此补丁包可以解决这个问题
  • 功能
    模拟olulli标签
    ol标签支持starttype属性;ul标签会自动根据层级显示不同的样式
  • 大小
    4.50KB
  • 此补丁包仅能在微信小程序中使用
  • 使用方法
    1. list文件夹复制到Parser文件夹下
    2. trees.li.wxml中的内容复制到Parser/trees/trees.wxmlnameelementtemplate中的任意位置
    3. Parser/trees/handler.wxs中的isContinue函数中进行如下修改
      // else if(item.name=='a')
      else if(item.name=='a'||item.name=='li'||item.name=='ol'||item.name=='ul')
    4. Parser/trees/trees.json中添加
      "usingComponents": {
        "trees": "./trees",
        "ol": "../list/ol",
        "ul": "../list/ul",
        "li": "../list/li"
      }
    5. Parser/DomHandler.jstrustTag结构体的olulli属性值改为1
    • 可参考demo文件夹中的Parser(已装载此补丁包)
  • 在其他页面中使用
    该包将列表封装成自定义组件,可以直接在其他页面上使用
    1. 在需要使用的页面的json文件中添加
      {
        "usingComponents": {
          "ol": "/Parser/list/ol",
          "ul": "/Parser/list/ul",
          "li": "/Parser/list/li"
        }
      }
    2. 可以直接使用olulli标签来显示列表
      <ol>
        <li>类型1-1</li>
        <li>类型1-2</li>
      </ol>
      <ol type="A" start="3" style="margin-top:5px;">
        <li>类型2-3</li>
        <li>类型2-4</li>
      </ol>
      <ol type="I" start="5" style="margin-top:5px;">
        <li>类型3-5</li>
        <li>类型3-6</li>
      </ol>
      <ul style="margin-top:10px">
        <li>层级1
          <ul>
            <li>层级2
              <ul><li>层级3</li></ul>
            </li>
          </ul>
        </li>
      </ul>
      列表演示

CssHandler

  • 功能:支持更多的css选择器
    原插件包支持的选择器:

    模式 举例 匹配
    按class名匹配 .demo <element class="demo">
    按id名匹配 #demo <element id="demo">
    按标签名匹配 body <body>...</body>
    单层多个class .demo1.demo2 <element class="demo1 demo2">
    多个并列 .demo1,.demo2 <element class="demo1">或<element class="demo2">

    使用本补丁包后增加支持的选择器:

    模式 匹配的标签 说明
    * 所有 通配符
    .demo1 .demo2 <element class="demo1">
    ...
        <element class="demo2">
    后代选择器
    .demo1>.demo2 <element class="demo1">
        <element class="demo2">
    子选择器
  • 大小(与原大小相比增加)
    3.04KBmin版本:1.71KB

  • 使用方法
    CssHandler文件夹下的CssHandler.js(若使用min版本也要改名为CssHandler.js)替换原插件包下的CssHandler.js即可

  • 注意事项
    使用该补丁包后会一定程度上减慢解析速度,如非必要不建议使用

百度版与微信版的差别

百度小程序版插件与微信小程序版基本相同,组件属性、回调函数等基本完全一致,仅一些实现方式上的差别:

  1. 解析实体
    在微信小程序中,rich-text从基础库2.2.5开始就基本支持了所有实体;但百度小程序的rich-text组件仅支持很少的实体,且不支持的实体会被显示为undefined
    解决方案: 在百度小程序版的插件包中增加了对&nbsp; &ensp; &emsp; &mdash; &middot; &lsquo; &rsquo; &ldquo; &rdquo; &hellip;23个常用实体的支持
  2. 一些html5新标签
    在微信小程序中,rich-text从基础库2.7.1开始增加支持了很多html5新标签,但百度小程序的rich-text仍不支持
    解决方案: 微信小程序版本中就准备了低版本的兼容方案,在百度小程序中直接使用兼容方案,使得其也能够使用sectionfont等标签
  3. audioautoplay属性
    微信小程序和百度小程序的audio都没有autoplay属性,但微信小程序可以通过createAudioContextapi来获取audio标签的context并进行自动播放;但百度小程序没有这个api,因此不支持audioautoplay属性
  4. List补丁包
    List补丁包中使用了Component中的relations字段来控制olul标签与li标签的关系,但百度小程序中不支持relations字段,所有暂不支持在百度小程序中使用这个补丁包
  5. wxsfilter
    在插件中,由于使用rich-text组件作为整个富文本的一部分,有时需要给rich-text本身添加一些顶层组件的样式以达到正确的效果(如displayfloat等,但又不能将顶层模块的style全部加在rich-text上,否则如margin等样式会被重复缩进),在微信小程序版本中,是通过wxs脚本筛选出一些样式并给rich-text组件设置;但在百度小程序中,filter在属性的设置中无效(好像只能设置标签中的文本)
    解决方案: 将这部分设置改在解析过程中处理,给需要的标签增加一个containStyle的属性,在显示时用这个属性的值设置为rich-text的样式
    带来的问题:
    1. 稍慢的速度(wxsios中的执行速度远快于js,且在解析过程中处理需要先找出哪些标签需要这样处理,算法更复杂,耗时稍长)
    2. 稍大的解析结果(由于部分标签多了一个containStyle属性,会稍微增加解析结果的大小)
    3. imgMode属性仅为传入的htmlString类型时有效(因为imgMode的处理也被移到解析过程中,arrayobject类型传入不进行解析)
    4. 百度版暂不支持lazy-load属性
  6. rich-text组件的display:inline
    在微信小程序中,给rich-text设置display:inline是无效的,这导致很多文本标签(如spanstronglabel等)直接用rich-text容易出现问题,因此需要对所有文本标签都继续递归,用一个display:inlineview来模拟(除supsub等一些难模拟的标签外);但百度小程序的rich-text是支持inline的,这使得百度小程序版本中不需要这样的处理,在一些情况下还能取得更好的效果
  7. 组件间通信
    本插件的基本显示方式是通过自定义组件trees递归调用来显示dom树,在微信小程序中,事件通过设置options中的composed属性即可让该事件穿过自定义组件边界继续冒泡,使得各层trees组件中的图片受到点击、链接受到点击等情况发生时,顶层组件都能收到并处理;但在百度小程序中无论是triggerEventdispatch还是selectComponent均无法穿透组件边界,这将导致顶层组件无法知晓子孙组件的事件
    解决方案: 通过getApp()设置了一个全局变量_Parser,当顶层模块被创建的时候,将这个变量设置为顶层模块的this;子孙组件建立时,通过这个变量获取顶层组件示例,并直接操作顶层模块的各类方法以实现等价效果,最终效果基本无明显差异

uni-app包说明

  1. 本插件需要使用 HBuilderX 2.2.5-alpha 及以上版本进行编译
  2. 本插件通过组件递归的方式显示节点树,因此必须使用自定义组件模式编译
  3. 编译过程中出现 Module not foundWarning请忽略(是因为没有引入对应的补丁包
  4. 本插件支持小程序、H5APP(不支持nvue)端使用(除ios端外都已经过基本测试)
  5. a 标签 autocopy 属性的表现效果:H5 中将直接跳转对应网页;小程序和 APP 中将复制链接APP 中建议在 @linkpress 回调中跳转web-view 页面(可参考示例项目)
  6. 微信小程序、QQ小程序、APP 支持 lazy-load 属性
  7. 微信小程序、QQ小程序、百度小程序支持 ad 组件
  8. 支付宝小程序、H5APP没有 versionHigherThanapi
  9. 支付宝小程序不支持 autopause 属性
  10. 微信小程序支持rubybdibdo 标签及 audio 标签的 autoplay 属性
  • 与原生包编译结果的区别(已知问题)
    1. 微信小程序中要求基础库 2.3.0 及以上
    2. vue框架要求template下只能有一个直接子节点,因此每个trees组件都需要用一个view套着,一定程度上增加了节点树深度
    3. 编译中会使用大量的block,一定程度上增大了编译结果大小
      <!--原生包-->
      <view wx:elif="{{item.name=='div'}}">...</view>
      <!--uni-app编译结果-->
      <block wx:else>
        <block wx:if="{{item.name=='div'}}">
          <view>...</view>
        </block>
      </block>