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

uni-app中使用towxml

步骤见:  https://www.cnblogs.com/chuan2021/p/17223663.html

 

在微信小程序中的效果:

展示的css可自行调整

 

支持代码复制:

towxml先用mardown.js把mardown转换成html, 然后再解析html,最后渲染到towxml/decode.wxml页面中, 代码会渲染到

item.tag == "view" 一段中, 这里先在parse/index.js中增加一个参数, 好判断是不是代码块,  增加第18-27行,  为代码块和行内代码块增加raw_tag, 行内代码块不支持复制, 修改结果:

 1 arr.forEach(item => {
 2     if (item.type === 'comment') {
 3         return;
 4     };
 5     let o = {
 6             type: item.type === 'text' ? 'text' : isRichTextContent ? 'node' : item.type
 7         },
 8         e = {},
 9         attrs = o.attrs = item.attribs || {};
10     if (item.type === 'text') {
11         o.text = e.text = item.data;
12     } else {
13         if (isRichTextContent) {
14             o.name = item.name;
15         } else {
16             o.tag = getWxmlTag(item.name); // 转换之后的标签
17             // o.tag = o.tag === 'text' ? 'view' : o.tag;
18             o.raw_tag = item.name
19             
20             // code block has parent element with class "h2w__pre"
21             // inline block has parent element with class "h2w__p" or "h2w__li"
22             // inline block no support copy
23             if (item.name == "code" && item.parent && item.parent.attribs && item.parent.attribs.class) {
24                 if (item.parent.attribs.class.indexOf('h2w__pre') === -1) {
25                     o.raw_tag = "inline_code"
26                 }
27             }
28 
29             e.tag = item.name; // 原始
30             o.attrs = item.attribs;
31             e.attrs = JSON.parse(JSON.stringify(attrs));
32         };
33         attrs.class = attrs.class ? `h2w__${item.name} ${attrs.class}` : `h2w__${item.name}`;
34 
35         // 处理资源相对路径
36         if (base && attrs.src) {
37             let src = attrs.src;
38             switch (src.indexOf('//')) {
39                 case 0:
40                     attrs.src = `https:${src}`;
41                     break;
42                 case -1:
43                     attrs.src = `${base}${src}`;
44                     break;
45             };
46         };
47     };
48 
49     o.rely = relyList.indexOf(e.tag) > -1; // 判断是否不能嵌套其它标签
50 
51     if (item.children) {
52         eachFn(item.children, o, e, isRichTextContent || item.name === 'rich-text');
53     };
54     child.push(o);
55     child_e.push(e);
56 });

然后在decode.wxml的h2w__viewParent一段下进行判断和增加复制按钮:

towxml/decode.wxml

 1 <block wx:if="{{item.tag==='view'}}">
 2     <block wx:if="{{item.rely}}">
 3         <view data-data="{{item}}" class="{{item.attrs.class}}" data="{{item.attrs.data}}" id="{{item.attrs.id}}" style="{{item.attrs.style}}" catch:tap="_tap">
 4             <decode wx:if="{{item.children}}" nodes="{{item}}"/>
 5         </view>
 6     </block>
 7     <block wx:else>
 8         <view class="h2w__viewParent">
 9             <view data-data="{{item}}" class="{{item.attrs.class}}" data="{{item.attrs.data}}" id="{{item.attrs.id}}" style="{{item.attrs.style}}" catch:tap="_tap">
10                 <block wx:if="{{item.raw_tag === 'code'}}">
11                     <view style="float: right" catch:tap="_copy" data-data="{{item}}" data="{{item.attrs.data}}">复制</view>
12                 </block>
13                 <decode wx:if="{{item.children}}" nodes="{{item}}"/>
14             </view>
15         </view>
16     </block>
17 </block>

可以看到这里我们新增了一个copy函数, 专门支持复制代码块, 为了支持新event. 还需要改towxml/config.js中的events字段:

1     events:[
2         // 'touchstart',
3         // 'touchmove',
4         // 'touchcancel',
5         // 'touchend',
6         'tap',                      // 用于元素的点击事件
7         'change',                   // 用于todoList的change事件
8         'copy',                     // 代码复制事件
9     ],

然后就可以在uni-app中处理该点击事件:

 1 let md = this.$towxml(src,
 2     'markdown', {
 3         // base: 'https://xxx.com', // 相对资源的base路径
 4         theme: 'light', // 主题,默认`light`
 5         events: { // 为元素绑定的事件方法
 6             tap: (e) => {
 7                 console.log('tap', e);
 8             },
 9             copy: (e) => {
10                 console.log(e.target.dataset.data)
11                 let copyed_code = ""
12                 
13                 const extract_code = (parsed_item) => {
14                     if (!parsed_item.children) {
15                         return
16                     }
17                     parsed_item.children.forEach(item => {
18                         if (item.raw_tag == "ul" || (item.attrs.class && item.attrs.class
19                                 .indexOf("h2w__lineNum") != -1)) {
20                             console.log('find number')
21                             return
22                         } else if (item.raw_tag == "p") {
23                             copyed_code = copyed_code + "\n\n"
24                         } else if (item.raw_tag == "br") {
25                             copyed_code = copyed_code + "\n"
26                         } else if (item.type == "text") {
27                             copyed_code = copyed_code + item.text
28                         } else {
29                             extract_code(item)
30                         }
31                     })
32                 }
33                 
34                 extract_code(e.target.dataset.data)
35                 
36                 uni.setClipboardData({
37                     data: copyed_code,
38                     showToast: true,
39                 });
40             },
41         }
42     });
43 this.article = md;

 

因为事件中的dataset传过来的是解析好的数据, 这里重新组件了一下, 代码有些简陋, 可以自行修改.

posted @ 2023-03-16 18:08  沉川  阅读(551)  评论(0编辑  收藏  举报