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传过来的是解析好的数据, 这里重新组件了一下, 代码有些简陋, 可以自行修改.