淼宇心柔 發表於 2023-3-16 18:08:00

towxml支持代码复制功能(支持uni-app)

<h2>uni-app中使用towxml</h2>
<p>步骤见:&nbsp; https://www.cnblogs.com/chuan2021/p/17223663.html</p>
<p>&nbsp;</p>
<h1>在微信小程序中的效果:</h1>
<p>展示的css可自行调整</p>
<p><img src="https://img2023.cnblogs.com/blog/1820780/202303/1820780-20230320121553145-1441964432.png"></p>
<p>&nbsp;</p>
<h1>支持代码复制:</h1>
<p>towxml先用mardown.js把mardown转换成html, 然后再解析html,最后渲染到towxml/decode.wxml页面中, 代码会渲染到</p>
<p>item.tag == "view" 一段中, 这里先在parse/index.js中增加一个参数, 好判断是不是代码块,&nbsp; 增加第18-27行,&nbsp; 为代码块和行内代码块增加raw_tag, 行内代码块不支持复制, 修改结果:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> arr.forEach(item =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 0, 255, 1)">if</span> (item.type === 'comment'<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>         <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">    };
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   let o =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>             type: item.type === 'text' ? 'text' : isRichTextContent ? 'node'<span style="color: rgba(0, 0, 0, 1)"> : item.type
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">      },
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>         e =<span style="color: rgba(0, 0, 0, 1)"> {},
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>         attrs = o.attrs = item.attribs ||<span style="color: rgba(0, 0, 0, 1)"> {};
</span><span style="color: rgba(0, 128, 128, 1)">10</span>   <span style="color: rgba(0, 0, 255, 1)">if</span> (item.type === 'text'<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)">11</span>         o.text = e.text =<span style="color: rgba(0, 0, 0, 1)"> item.data;
</span><span style="color: rgba(0, 128, 128, 1)">12</span>   } <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">13</span>         <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isRichTextContent) {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>             o.name =<span style="color: rgba(0, 0, 0, 1)"> item.name;
</span><span style="color: rgba(0, 128, 128, 1)">15</span>         } <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">16</span>             o.tag = getWxmlTag(item.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 转换之后的标签</span>
<span style="color: rgba(0, 128, 128, 1)">17</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> o.tag = o.tag === 'text' ? 'view' : o.tag;</span>
<span style="color: rgba(0, 128, 128, 1)">18</span>             o.raw_tag =<span style="color: rgba(0, 0, 0, 1)"> item.name
</span><span style="color: rgba(0, 128, 128, 1)">19</span>            
<span style="color: rgba(0, 128, 128, 1)">20</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> code block has parent element with class "h2w__pre"</span>
<span style="color: rgba(0, 128, 128, 1)">21</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> inline block has parent element with class "h2w__p" or "h2w__li"</span>
<span style="color: rgba(0, 128, 128, 1)">22</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> inline block no support copy</span>
<span style="color: rgba(0, 128, 128, 1)">23</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (item.name == "code" &amp;&amp; item.parent &amp;&amp; item.parent.attribs &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> item.parent.attribs.class) {
</span><span style="color: rgba(0, 128, 128, 1)">24</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (item.parent.attribs.class.indexOf('h2w__pre') === -1<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)">25</span>                     o.raw_tag = "inline_code"
<span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">28</span>
<span style="color: rgba(0, 128, 128, 1)">29</span>             e.tag = item.name; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 原始</span>
<span style="color: rgba(0, 128, 128, 1)">30</span>             o.attrs =<span style="color: rgba(0, 0, 0, 1)"> item.attribs;
</span><span style="color: rgba(0, 128, 128, 1)">31</span>             e.attrs =<span style="color: rgba(0, 0, 0, 1)"> JSON.parse(JSON.stringify(attrs));
</span><span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(0, 0, 0, 1)">      };
</span><span style="color: rgba(0, 128, 128, 1)">33</span>         attrs.class = attrs.class ?<span style="color: rgba(0, 0, 0, 1)"> `h2w__${item.name} ${attrs.class}` : `h2w__${item.name}`;
</span><span style="color: rgba(0, 128, 128, 1)">34</span>
<span style="color: rgba(0, 128, 128, 1)">35</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 处理资源相对路径</span>
<span style="color: rgba(0, 128, 128, 1)">36</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> (base &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> attrs.src) {
</span><span style="color: rgba(0, 128, 128, 1)">37</span>             let src =<span style="color: rgba(0, 0, 0, 1)"> attrs.src;
</span><span style="color: rgba(0, 128, 128, 1)">38</span>             <span style="color: rgba(0, 0, 255, 1)">switch</span> (src.indexOf('//'<span style="color: rgba(0, 0, 0, 1)">)) {
</span><span style="color: rgba(0, 128, 128, 1)">39</span>               <span style="color: rgba(0, 0, 255, 1)">case</span> 0<span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)">40</span>                     attrs.src =<span style="color: rgba(0, 0, 0, 1)"> `https:${src}`;
</span><span style="color: rgba(0, 128, 128, 1)">41</span>                     <span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">42</span>               <span style="color: rgba(0, 0, 255, 1)">case</span> -1<span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 128, 1)">43</span>                     attrs.src =<span style="color: rgba(0, 0, 0, 1)"> `${base}${src}`;
</span><span style="color: rgba(0, 128, 128, 1)">44</span>                     <span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">45</span> <span style="color: rgba(0, 0, 0, 1)">            };
</span><span style="color: rgba(0, 128, 128, 1)">46</span> <span style="color: rgba(0, 0, 0, 1)">      };
</span><span style="color: rgba(0, 128, 128, 1)">47</span> <span style="color: rgba(0, 0, 0, 1)">    };
</span><span style="color: rgba(0, 128, 128, 1)">48</span>
<span style="color: rgba(0, 128, 128, 1)">49</span>   o.rely = relyList.indexOf(e.tag) &gt; -1; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断是否不能嵌套其它标签</span>
<span style="color: rgba(0, 128, 128, 1)">50</span>
<span style="color: rgba(0, 128, 128, 1)">51</span>   <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (item.children) {
</span><span style="color: rgba(0, 128, 128, 1)">52</span>         eachFn(item.children, o, e, isRichTextContent || item.name === 'rich-text'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">53</span> <span style="color: rgba(0, 0, 0, 1)">    };
</span><span style="color: rgba(0, 128, 128, 1)">54</span> <span style="color: rgba(0, 0, 0, 1)">    child.push(o);
</span><span style="color: rgba(0, 128, 128, 1)">55</span> <span style="color: rgba(0, 0, 0, 1)">    child_e.push(e);
</span><span style="color: rgba(0, 128, 128, 1)">56</span> });</pre>
</div>
<p>然后在decode.wxml的h2w__viewParent一段下进行判断和增加复制按钮:</p>
<p>towxml/decode.wxml</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> &lt;block wx:<span style="color: rgba(0, 0, 255, 1)">if</span>="{{item.tag==='view'}}"&gt;
<span style="color: rgba(0, 128, 128, 1)"> 2</span>   &lt;block wx:<span style="color: rgba(0, 0, 255, 1)">if</span>="{{item.rely}}"&gt;
<span style="color: rgba(0, 128, 128, 1)"> 3</span>         &lt;view data-data="{{item}}" class="{{item.attrs.class}}" data="{{item.attrs.data}}" id="{{item.attrs.id}}" style="{{item.attrs.style}}" <span style="color: rgba(0, 0, 255, 1)">catch</span>:tap="_tap"&gt;
<span style="color: rgba(0, 128, 128, 1)"> 4</span>             &lt;decode wx:<span style="color: rgba(0, 0, 255, 1)">if</span>="{{item.children}}" nodes="{{item}}"/&gt;
<span style="color: rgba(0, 128, 128, 1)"> 5</span>         &lt;/view&gt;
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   &lt;/block&gt;
<span style="color: rgba(0, 128, 128, 1)"> 7</span>   &lt;block wx:<span style="color: rgba(0, 0, 255, 1)">else</span>&gt;
<span style="color: rgba(0, 128, 128, 1)"> 8</span>         &lt;view class="h2w__viewParent"&gt;
<span style="color: rgba(0, 128, 128, 1)"> 9</span>             &lt;view data-data="{{item}}" class="{{item.attrs.class}}" data="{{item.attrs.data}}" id="{{item.attrs.id}}" style="{{item.attrs.style}}" <span style="color: rgba(0, 0, 255, 1)">catch</span>:tap="_tap"&gt;
<span style="color: rgba(0, 128, 128, 1)">10</span>               &lt;block wx:<span style="color: rgba(0, 0, 255, 1)">if</span>="{{item.raw_tag === 'code'}}"&gt;
<span style="color: rgba(0, 128, 128, 1)">11</span>                     &lt;view style="float: right" <span style="color: rgba(0, 0, 255, 1)">catch</span>:tap="_copy" data-data="{{item}}" data="{{item.attrs.data}}"&gt;复制&lt;/view&gt;
<span style="color: rgba(0, 128, 128, 1)">12</span>               &lt;/block&gt;
<span style="color: rgba(0, 128, 128, 1)">13</span>               &lt;decode wx:<span style="color: rgba(0, 0, 255, 1)">if</span>="{{item.children}}" nodes="{{item}}"/&gt;
<span style="color: rgba(0, 128, 128, 1)">14</span>             &lt;/view&gt;
<span style="color: rgba(0, 128, 128, 1)">15</span>         &lt;/view&gt;
<span style="color: rgba(0, 128, 128, 1)">16</span>   &lt;/block&gt;
<span style="color: rgba(0, 128, 128, 1)">17</span> &lt;/block&gt;</pre>
</div>
<p>可以看到这里我们新增了一个copy函数, 专门支持复制代码块, 为了支持新event. 还需要改towxml/config.js中的events字段:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">    events:[
</span><span style="color: rgba(0, 128, 128, 1)">2</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 'touchstart',</span>
<span style="color: rgba(0, 128, 128, 1)">3</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 'touchmove',</span>
<span style="color: rgba(0, 128, 128, 1)">4</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 'touchcancel',</span>
<span style="color: rgba(0, 128, 128, 1)">5</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 'touchend',</span>
<span style="color: rgba(0, 128, 128, 1)">6</span>         'tap',                      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用于元素的点击事件</span>
<span style="color: rgba(0, 128, 128, 1)">7</span>         'change',                   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用于todoList的change事件</span>
<span style="color: rgba(0, 128, 128, 1)">8</span>         'copy',                     <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 代码复制事件</span>
<span style="color: rgba(0, 128, 128, 1)">9</span>   ],</pre>
</div>
<p>然后就可以在uni-app中处理该点击事件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> let md = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$towxml(src,
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   'markdown'<span style="color: rgba(0, 0, 0, 1)">, {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> base: 'https://xxx.com', // 相对资源的base路径</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span>         theme: 'light', <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主题,默认`light`</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span>         events: { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 为元素绑定的事件方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>             tap: (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>               console.log('tap'<span style="color: rgba(0, 0, 0, 1)">, e);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">            },
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>             copy: (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">                console.log(e.target.dataset.data)
</span><span style="color: rgba(0, 128, 128, 1)">11</span>               let copyed_code = ""
<span style="color: rgba(0, 128, 128, 1)">12</span>               
<span style="color: rgba(0, 128, 128, 1)">13</span>               const extract_code = (parsed_item) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>                     <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">parsed_item.children) {
</span><span style="color: rgba(0, 128, 128, 1)">15</span>                         <span style="color: rgba(0, 0, 255, 1)">return</span>
<span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">                  }
</span><span style="color: rgba(0, 128, 128, 1)">17</span>                     parsed_item.children.forEach(item =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">18</span>                         <span style="color: rgba(0, 0, 255, 1)">if</span> (item.raw_tag == "ul" || (item.attrs.class &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> item.attrs.class
</span><span style="color: rgba(0, 128, 128, 1)">19</span>                                 .indexOf("h2w__lineNum") != -1<span style="color: rgba(0, 0, 0, 1)">)) {
</span><span style="color: rgba(0, 128, 128, 1)">20</span>                           console.log('find number'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">21</span>                           <span style="color: rgba(0, 0, 255, 1)">return</span>
<span style="color: rgba(0, 128, 128, 1)">22</span>                         } <span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (item.raw_tag == "p"<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)">23</span>                           copyed_code = copyed_code + "\n\n"
<span style="color: rgba(0, 128, 128, 1)">24</span>                         } <span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (item.raw_tag == "br"<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)">25</span>                           copyed_code = copyed_code + "\n"
<span style="color: rgba(0, 128, 128, 1)">26</span>                         } <span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (item.type == "text"<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)">27</span>                           copyed_code = copyed_code +<span style="color: rgba(0, 0, 0, 1)"> item.text
</span><span style="color: rgba(0, 128, 128, 1)">28</span>                         } <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)">                            extract_code(item)
</span><span style="color: rgba(0, 128, 128, 1)">30</span> <span style="color: rgba(0, 0, 0, 1)">                        }
</span><span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 0, 0, 1)">                  })
</span><span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)">33</span>               
<span style="color: rgba(0, 128, 128, 1)">34</span> <span style="color: rgba(0, 0, 0, 1)">                extract_code(e.target.dataset.data)
</span><span style="color: rgba(0, 128, 128, 1)">35</span>               
<span style="color: rgba(0, 128, 128, 1)">36</span> <span style="color: rgba(0, 0, 0, 1)">                uni.setClipboardData({
</span><span style="color: rgba(0, 128, 128, 1)">37</span> <span style="color: rgba(0, 0, 0, 1)">                  data: copyed_code,
</span><span style="color: rgba(0, 128, 128, 1)">38</span>                     showToast: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 0, 0, 1)">                });
</span><span style="color: rgba(0, 128, 128, 1)">40</span> <span style="color: rgba(0, 0, 0, 1)">            },
</span><span style="color: rgba(0, 128, 128, 1)">41</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">42</span> <span style="color: rgba(0, 0, 0, 1)">    });
</span><span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.article = md;</pre>
</div>
<p>&nbsp;</p>
<p>因为事件中的dataset传过来的是解析好的数据, 这里重新组件了一下, 代码有些简陋, 可以自行修改.</p><br><br>
来源:https://www.cnblogs.com/chuan2021/p/17223727.html
頁: [1]
查看完整版本: towxml支持代码复制功能(支持uni-app)