Rorschach 6 years ago
parent
commit
e3d5a9efe9
49 changed files with 1831 additions and 1 deletions
  1. 1 1
      component/dialog/dialog.wxml
  2. BIN
      static/image/reader_logo.jpg
  3. 10 0
      towxml/entry.wxml
  4. 172 0
      towxml/lib/Audio.js
  5. 5 0
      towxml/lib/markdown-it.js
  6. 2 0
      towxml/lib/parse5.js
  7. 64 0
      towxml/lib/tagsAndAttrs.js
  8. 296 0
      towxml/lib/toJson.js
  9. 137 0
      towxml/main.js
  10. 177 0
      towxml/outTemplate.js
  11. 1 0
      towxml/plugins/hljs/highlight.js
  12. 29 0
      towxml/plugins/hljs/index.js
  13. 1 0
      towxml/plugins/hljs/languages/bash.js
  14. 1 0
      towxml/plugins/hljs/languages/coffeescript.js
  15. 1 0
      towxml/plugins/hljs/languages/css.js
  16. 1 0
      towxml/plugins/hljs/languages/dns.js
  17. 1 0
      towxml/plugins/hljs/languages/dos.js
  18. 1 0
      towxml/plugins/hljs/languages/erlang.js
  19. 1 0
      towxml/plugins/hljs/languages/go.js
  20. 1 0
      towxml/plugins/hljs/languages/htmlbars.js
  21. 1 0
      towxml/plugins/hljs/languages/http.js
  22. 1 0
      towxml/plugins/hljs/languages/java.js
  23. 1 0
      towxml/plugins/hljs/languages/javascript.js
  24. 1 0
      towxml/plugins/hljs/languages/json.js
  25. 1 0
      towxml/plugins/hljs/languages/less.js
  26. 1 0
      towxml/plugins/hljs/languages/makefile.js
  27. 1 0
      towxml/plugins/hljs/languages/markdown.js
  28. 1 0
      towxml/plugins/hljs/languages/nginx.js
  29. 1 0
      towxml/plugins/hljs/languages/php.js
  30. 1 0
      towxml/plugins/hljs/languages/powershell.js
  31. 1 0
      towxml/plugins/hljs/languages/python.js
  32. 1 0
      towxml/plugins/hljs/languages/ruby.js
  33. 1 0
      towxml/plugins/hljs/languages/scss.js
  34. 1 0
      towxml/plugins/hljs/languages/shell.js
  35. 1 0
      towxml/plugins/hljs/languages/sql.js
  36. 1 0
      towxml/plugins/hljs/languages/swift.js
  37. 1 0
      towxml/plugins/hljs/languages/typescript.js
  38. 99 0
      towxml/plugins/hljs/style/github.wxss
  39. 70 0
      towxml/plugins/hljs/style/monokai.wxss
  40. 3 0
      towxml/plugins/markdown-it-emoji.js
  41. 2 0
      towxml/plugins/markdown-it-ins.js
  42. 2 0
      towxml/plugins/markdown-it-mark.js
  43. 2 0
      towxml/plugins/markdown-it-sub.js
  44. 2 0
      towxml/plugins/markdown-it-sup.js
  45. 148 0
      towxml/plugins/markdown-it-todoList.js
  46. 1 0
      towxml/renderTemplate.wxml
  47. 421 0
      towxml/style/main.wxss
  48. 87 0
      towxml/style/theme/dark.wxss
  49. 75 0
      towxml/style/theme/light.wxss

+ 1 - 1
component/dialog/dialog.wxml

@@ -2,7 +2,7 @@
 <view class="dialog">
     <view class="dialog-contain">
         <view class="title">微信授权</view>
-        <image class="head-bg" src="" style="background: red;"></image>
+        <image class="head-bg" src="../../static/image/reader_logo.jpg" style="background: red;"></image>
         <view class="text">小学语文朗读配音 申请获得以下权限</view>
         <view class="shuoming">获得你的公开信(昵称、头像等)</view>
         <button class="btn"  open-type="getUserInfo" bindgetuserinfo="impower">允许</button>

BIN
static/image/reader_logo.jpg


+ 10 - 0
towxml/entry.wxml

@@ -0,0 +1,10 @@
+<template name="entry">
+  <view class="h2w h2w-{{theme}}">
+    <view class="h2w__main">
+      <import src="/towxml/renderTemplate.wxml"/>
+      <block wx:for="{{child}}" wx:key="{{index}}">
+        <template is="m0" data="{{item}}"/>
+      </block>
+    </view>
+  </view>
+</template>

+ 172 - 0
towxml/lib/Audio.js

@@ -0,0 +1,172 @@
+module.exports = (option) => {
+    option = option || {};
+    const app = option.app;
+
+    class Audio {
+        constructor(option) {
+            const _ts = this;
+
+            _ts.option = option.option;
+            _ts.playerId = option.playerId;
+            _ts.dataId = option.dataId;
+
+            this.player = this.createPlayer();
+            this.status = 'init';
+        }
+
+        // 播放
+        play() {
+            const _ts = this;
+            _ts.player.play();
+        }
+
+        // 暂停
+        pause() {
+            const _ts = this;
+            _ts.player.pause();
+        }
+
+        // 获取需要更新的数据键名
+        getAppDataKey(id){
+            for(let key in app.data){
+                let item = app.data[key];
+
+                if(item.id === id){
+                    return key;
+                };
+            };
+        }
+
+        updateView(data){
+            data = data || {};
+            const _ts = this,
+                option = _ts.option;
+
+            _ts.updateKey = _ts.updateKey || _ts.getAppDataKey(_ts.dataId)
+
+            let articleData = global.__towxmldata__[_ts.dataId].article,
+                playerData = global.__towxmldata__[_ts.dataId].audio[_ts.playerId];
+            
+            // 检查如果数据没有被应用到页面上则中止操作
+            if(!_ts.updateKey){
+                return;
+            };
+
+            // 将选项和新传入的数据组合到viewData,后续更新使用
+            for(let key in data){
+                option[key] = data[key];
+            };
+
+            // 设置默认进的播放进度
+            option.duration = _ts.duration || 0.001;
+            option.currentTime = _ts.currentTime || 0;
+            option.class = option.class || 'audioForH2w';
+
+            // 设置播放器样式
+            playerData.attr.class = option.class;
+
+            // 设置封面图片
+            playerData.child[1].child[0].attr.src = option.poster;
+            
+            // 设置进度条
+            playerData.child[2].child[0].attr.style = `width:${option.currentTime / option.duration * 100}%`;
+
+            // 设置title、歌手、播放时间
+            playerData.child[2].child[1].child[0].text = option.name;
+            playerData.child[2].child[2].child[0].text = option.author;
+            playerData.child[2].child[3].child[0].text = `${_ts.formatTime(option.duration)} / ${_ts.formatTime(option.currentTime)}`;
+
+            // 更新数据
+            let updateData = {};
+            updateData[_ts.updateKey] = articleData;
+
+            app.setData(updateData);
+        }
+
+        // 创建播放器
+        createPlayer() {
+            const _ts = this;
+
+            let option = _ts.option,
+
+                autoplay = option.autoplay === 'true' ? true :
+                            option.autoplay === 'false' ? false :
+                            !!option.autoplay,
+                loop = option.loop === 'true' ? true :
+                        option.loop === 'false' ? false :
+                        !!option.loop,
+                src = option.src,
+                audio = wx.createInnerAudioContext();
+
+            audio.autoplay = autoplay;
+            audio.loop = loop;
+            audio.src = src;
+
+            // 进入可播放状态时更新视图
+            audio.onCanplay(() =>{
+                _ts.updateView({
+                    class:'audioForH2w'
+                });
+            });
+
+            // 播放
+            audio.onPlay(() => {
+              _ts.status = 'start';
+
+              _ts.updateView({
+                  class:'audioForH2w audioForH2w--play'
+              });
+            });
+
+            // 播放过程中
+            let temp = 0;
+            audio.onTimeUpdate(function (obj) {
+                _ts.status = 'update';
+                _ts.duration = audio.duration;
+                _ts.currentTime = audio.currentTime;
+
+                // 每5秒更新一次(否则内容过多会导致性能低下)
+                if(_ts.currentTime - temp > 5){
+                    temp = _ts.currentTime;
+                    _ts.updateView({
+                        class:'audioForH2w audioForH2w--play'
+                    });
+                };
+            });
+
+            // 暂停
+            audio.onPause(obj => {
+                _ts.status = 'pause';
+
+                _ts.updateView({
+                    class:'audioForH2w'
+                });
+            });
+
+            // 停止
+            audio.onEnded(obj => {
+                _ts.status = 'end';
+
+                _ts.updateView({
+                    class:'audioForH2w audioForH2w--end'
+                });
+            });
+            return audio;
+        }
+
+        // 数字补位
+        fillIn = val => {
+            return `${val < 10 ? '0' : ''}${val}`;
+        }
+
+        // 格式化时间  
+        formatTime = time => {
+            let fillIn = this.fillIn,
+                second = Math.floor(time % 60),
+                minute = Math.floor(time / 60 % 60),
+                hour = Math.floor(time / 60 / 60);
+            return `${fillIn(hour)}:${fillIn(minute)}:${fillIn(second)}`;
+        }
+    };
+    return new Audio(option);
+};

File diff suppressed because it is too large
+ 5 - 0
towxml/lib/markdown-it.js


File diff suppressed because it is too large
+ 2 - 0
towxml/lib/parse5.js


+ 64 - 0
towxml/lib/tagsAndAttrs.js

@@ -0,0 +1,64 @@
+let wxml = [
+    // 建议保留的解析标签
+    'view',
+    'video',
+    'text',
+    'image',
+    'navigator',
+    'swiper',
+    'swiper-item',
+    'block',
+    'form',
+    'input',
+    'textarea',
+    'button',
+    'checkbox-group',
+    'checkbox',
+    'radio-group',
+    'radio',
+
+    // 可以解析的标签(html或markdown中会很少使用)
+    // 'canvas',
+    // 'map',
+    // 'slider',
+    // 'scroll-view',
+    // 'movable-area',
+    // 'movable-view',
+    // 'progress',
+    // 'label',
+    // 'switch',
+    // 'picker',
+    // 'picker-view',
+    // 'switch',
+    // // 'audio',
+    // 'contact-button'
+],
+binds = [
+    // 建议保留的事件
+    'bind:touchstart',
+    'bind:touchmove',
+    'bind:touchcancel',
+    'bind:touchend',
+    'bind:tap',
+    // 'bind:longpress',
+    // 'bind:longtap',
+    // 'bind:transitionend',
+    // 'bind:animationstart',
+    // 'bind:animationiteration',
+    // 'bind:animationend',
+    // 'bind:touchforcechange'
+],
+attrs = [
+    'class',
+    'width',
+    'height',
+    'data',
+    'id',
+    'style'
+];
+
+module.exports = {
+    wxml:wxml,
+    binds:binds,
+    attrs:[...binds,...attrs]
+};

+ 296 - 0
towxml/lib/toJson.js

@@ -0,0 +1,296 @@
+const Audio = require('./Audio'),
+    tagsAndAttrs = require('./tagsAndAttrs');
+class ToJson {
+    constructor(html,app){
+        const _ts = this;
+
+        let m = _ts.m = {};
+        m.parse = require('./parse5');
+
+        _ts.html = html;
+        _ts.data = {};
+        _ts.app = app;
+
+        // 得到整体页面的数据
+        _ts.data.document = m.parse.parse(_ts.html);
+
+        // 得到body部分的数据
+        _ts.data.body = _ts.getBodyData(_ts.data.document);
+
+        // 生成当前的数据ID
+        _ts.id  = `dataId_${+new Date}_${(Math.random()+'').slice(2)}`;
+
+        // 将数据保存到全局
+        global.__towxmldata__ = global.__towxmldata__ || {};
+        global.__towxmldata__[_ts.id] = global.__towxmldata__[_ts.id] || {};
+        global.__towxmldata__[_ts.id].audio = {};
+    }
+
+    getData(){
+        const _ts = this,
+            m = _ts.m;
+
+        let data = _ts.data,
+            outData = _ts.sortOut(data.body); 
+
+        outData.node = 'root';
+        
+        // 为数据添加ID
+        outData.id = _ts.id;
+
+        
+        global.__towxmldata__[_ts.id].article = outData;
+
+        return global.__towxmldata__[_ts.id].article;
+    }
+
+    /**
+     * 遍历页面数据整理成小程序想要的
+     */
+    sortOut(bodyData){
+        const _ts = this,
+            app = _ts.app,
+            appData = app.data ;
+        let result = {},
+            arrange;      
+        (arrange = (data,result)=>{  
+            // 当有数据且有子元素时则遍历
+            if(data && data.childNodes && data.childNodes.length){
+                // 子元素数据不存在时,创建一个空的数组用以存储子元素数据
+                if(!result.child){
+                    result.child = [];
+                };
+                // 遍历子节点,处理节点的数据
+                for(let i=0,len=data.childNodes.length; i<len; i++){
+                    let node = data.childNodes[i],                              // 得到具体的节点
+                        attrs = node.attrs,                                     // 得到节点的属性(一个数组)
+                        attrsLength = attrs && attrs.length ? attrs.length : 0, // 得到节点属性的长度
+                        current = {                                             // 创建一个空对象,用于存储节点属性及处理之后的属性
+                            _e:{},
+                            attr:{}                                             // html的原始数据
+                        };                                           
+                    if(node){
+                        result.child.push(current);
+                    };
+                    // 如果有属性则处理其属性
+                    if (attrsLength) {              
+                        if (current._e.attr === undefined) {
+                            //current.attr = {};
+                            current._e.attr = {};
+                        };
+                        for (let i = 0; i < attrsLength; i++) {
+                            let attrsItem = attrs[i],
+                                key = attrsItem.name,
+                                val = attrsItem.value;
+                            
+                            current.attr[key] = val;
+                            current._e.attr[key] = val;
+                        }; 
+                    };
+
+                    for(let key in node){
+                        // 保留最原始的html数据,父节点数据去掉(小程序会报错)
+                        if(typeof node[key] !== 'object'){
+                            current._e[key] = node[key];
+                        };
+                        switch (node.nodeName) {
+                            case 'body':
+                                current['node'] = 'root';
+                            break;
+                            case '#text':
+                                current['node'] = 'text';
+                                current['text'] = node.value;
+                            break;
+                            default:
+                                current['node'] = 'element';
+                            break;
+                        };
+                    };
+
+                    // 当前标签是audio的情况下
+                    if(node.tagName === 'audio'){
+                        current.tag = "view";
+                        current.attr = {};
+                        current.attr.class = 'audioForH2w';
+
+                        current._id = `audio_${+new Date()}_${(Math.random()+'').slice(2)}`;
+
+                        // // 用于保存播放器数据(小程序在setData完成之后,新的数据会重新占用内存空间,故此处保存没有必要)
+                        // if(appData){
+                        //     appData.__audioData__ = appData.__audio__ || {};
+                        //     appData.__audioData__[current._id] = current;
+                        // };
+
+                        // 创建播放器子元素
+                        current.child = [
+                            {   
+                                node:"element",
+                                tag:"view",
+                                attr:{
+                                    class:"h2w__view audioForH2w__icon"
+                                }
+                            },{
+                                node:"element",
+                                tag:"view",
+                                attr:{
+                                    class:"h2w__view audioForH2w__cover"
+                                },
+                                child:[
+                                    {
+                                        node:"element",
+                                        tag:"image",
+                                        type:"audio",
+                                        attr:{
+                                            class:"h2w__img"
+                                        }
+                                    }
+                                ]
+                            },{
+                                node:"element",
+                                tag:"view",
+                                attr:{
+                                    class:"h2w__view audioForH2w__info"
+                                },
+                                child:[
+                                    {
+                                        node:"element",
+                                        tag:"view",
+                                        attr:{
+                                            class: "h2w__view audioForH2w__schedule",
+                                            style: "width:0px;"
+                                        }
+                                    },{
+                                        node:"element",
+                                        tag:"view",
+                                        attr:{
+                                            class:"audioForH2w__title"
+                                        },
+                                        child:[
+                                            {
+                                                node:"text",
+                                                text: "--",
+                                                attr: {}
+                                            }
+                                        ]
+                                    },{
+                                        node:"element",
+                                        tag:"view",
+                                        attr:{
+                                            class:"audioForH2w__author"
+                                        },
+                                        child:[
+                                            {
+                                                node:"text",
+                                                text: "佚名",
+                                                attr: {}
+                                            }
+                                        ]
+                                    },{
+                                        node:"element",
+                                        tag:"view",
+                                        attr:{
+                                            class:"audioForH2w__time"
+                                        },
+                                        child:[
+                                            {
+                                                node:"text",
+                                                text: "00:00:00 / 00:00:00",
+                                                attr: {}
+                                            }
+                                        ]
+                                    }
+                                ]
+                            }
+                        ];
+
+                        if(appData){
+                            // 得到音频选项
+                            let audioOption = ((node)=>{
+                                let option = {},
+                                    nodeAttrs = node.attrs;
+
+                                for(let i=0,len=nodeAttrs.length; i<len; i++){
+                                    let attrItem = nodeAttrs[i];
+                                    option[attrItem.name] = attrItem.value;
+                                };
+
+                                return option;
+                            })(node);
+
+                            // 保存当前播放器数据
+                            global.__towxmldata__[_ts.id].audio[current._id] = current;
+
+                            //用于保存播放器对象
+                            appData.__audioObj__ = appData.__audioObj__ || {};
+                            appData.__audioObj__[current._id] = Audio({
+                                app:app,                            // 传入APP
+                                playerId:current._id,               // 当前播放器ID
+                                dataId:_ts.id,                      // 数据ID
+                                option:audioOption                  // 传入音频选项
+                            });
+                        };
+                    }else if(node.tagName){
+                        current.tag = _ts.getTag(node.tagName);
+                        current.attr.class = current.attr.class ? `h2w__${node.tagName} ${current.attr.class}` : `h2w__${node.tagName}`;
+                    };
+                    arrange(node,current);
+                };
+            };
+        })(bodyData,result);
+        return result;
+    }
+
+    /**
+     * 获取属于body那部分的数据
+     */
+    getBodyData(documentData){
+        let data,
+            getBody;
+        (getBody = (list)=>{
+            for(let i=0,len=list.length; i<len; i++){
+                let item = list[i];
+
+                if(item.nodeName === 'body' && item.tagName === 'body'){
+                    data = item;
+                    break;
+                }else if (item.childNodes){
+                    getBody(item.childNodes);
+                };
+            }
+        })(documentData.childNodes);
+        return data;
+    }
+
+    /**
+     * 得到转换对应的tag
+     */
+    getTag(tagName){
+        let correspondTag = this.correspondTag(),
+            wxmlTag = correspondTag[tagName] === undefined ? 'view' : correspondTag[tagName];
+        return wxmlTag;
+    }
+
+    /**
+     * 组织html与小程序的tag对应关系
+     */
+    correspondTag(){
+        let data = {
+            'a':'navigator',
+            'img':'image',
+            'todogroup':'checkbox-group'
+        };
+
+        // 该系列的标签都转换为text
+        ['span','b','strong','i','em','code','sub','sup','g-emoji','mark','ins'].forEach(item => {
+            data[item] = 'text';
+        });
+
+        // 该系列是小程序原生tag,不需要转换
+        tagsAndAttrs.wxml.forEach(item => {
+            data[item] = item;
+        });
+        return data;
+    }
+};
+
+module.exports = ToJson;

+ 137 - 0
towxml/main.js

@@ -0,0 +1,137 @@
+const Audio = require('./lib/Audio'),
+	tagsAndAttrs = require('./lib/tagsAndAttrs');
+
+class towxml {
+	constructor(option) {
+		const _ts = this;
+		option = option || {};
+
+		for (let i in option) {
+			_ts.config[i] = option[i];
+		};
+
+		_ts.m = {};
+
+		let mdOption = {
+			html: true,
+			xhtmlOut: true,
+			typographer: true,
+			breaks: true,
+			highlight: function (code, lang, callback) {
+				return _ts.m.highlight.highlightAuto(code).value;
+			}
+		};
+		
+		_ts.m.toJson = require('./lib/toJson');
+		_ts.m.highlight = require('./plugins/hljs/index');
+
+		_ts.m.md = require('./lib/markdown-it')(mdOption);
+		_ts.m.md_sub = require('./plugins/markdown-it-sub');
+		_ts.m.md_sup = require('./plugins/markdown-it-sup');
+		_ts.m.md_ins = require('./plugins/markdown-it-ins');
+		_ts.m.md_mark = require('./plugins/markdown-it-mark');
+		_ts.m.md_emoji = require('./plugins/markdown-it-emoji');
+		_ts.m.md_todo = require('./plugins/markdown-it-todoList');
+
+		_ts.m.md.use(_ts.m.md_sub);
+		_ts.m.md.use(_ts.m.md_sup);
+		_ts.m.md.use(_ts.m.md_ins);
+		_ts.m.md.use(_ts.m.md_mark);
+		_ts.m.md.use(_ts.m.md_emoji);
+		_ts.m.md.use(_ts.m.md_todo);
+
+		_ts.m.md.renderer.rules.emoji = function (token, idx) {
+			return '<g-emoji class="h2w__emoji h2w__emoji--' + token[idx].markup + '">' + token[idx].content + '</g-emoji>';
+		};
+	}
+
+	/**
+	 * markdown转html
+	 */
+	md2html(mdContent) {
+		const _ts = this;
+		return _ts.m.md.render(mdContent);
+	}
+
+	/**
+	 * html2json
+	 * @param  {string} content html或markdown字符串
+	 * @param  {string} type 'html'、'marddown'
+	 * @param  {object} app 小程序对象
+	 */
+	toJson(content, type, app){
+		const _ts = this;
+		type = type || 'html';
+
+		let json = '',
+			sortOutJson;
+
+		if (type === 'markdown') {
+			json = new _ts.m.toJson(_ts.md2html(content),app).getData();
+		} else if (type === 'html') {
+      		json = new _ts.m.toJson(content,app).getData();
+		};
+
+		json.theme = 'light';
+
+		if(app){
+			// 定义播放器点击时的播放与暂停方法
+			if(typeof app.__audioPlayAndPause__ !== 'function'){
+				app.__audioPlayAndPause__ = (event)=>{
+					let currentTarget = event.currentTarget || {},
+						dataset = currentTarget.dataset || {},
+						_el = dataset._el || {},
+						id = _el._id || {},
+						player = typeof app.data.__audioObj__ === 'object' ? app.data.__audioObj__[id] : undefined;
+					// 正在播放中则暂停,否则就播放
+					if(player && player.status !== 'play' && player.status !== 'update'){
+						player.play();
+					}else{
+						player.pause();
+						player.status = 'pause';
+					};
+				};
+			};
+
+
+			tagsAndAttrs.binds.forEach(item => {
+				let aItem = item.split(':'),
+					bindType = aItem[0],		// 事件绑定类型
+					evenType = aItem[1];		// 事件类型
+				
+
+				// 检查,如果有添加自定义事件,则运行该事件
+				app[`__${bindType}_${evenType}`] = (event)=>{
+					let funName = `event_${bindType}_${evenType}`,
+						timer = `${funName}_timer`,
+						runFun = app[funName];
+
+					// 为audio标签绑定音频播放
+					if(event && 
+						event.type === 'tap' && 
+						event.currentTarget &&
+						event.currentTarget.dataset &&
+						event.currentTarget.dataset._el &&
+						event.currentTarget.dataset._el._e && 
+						event.currentTarget.dataset._el._e.tagName === 'audio'){
+						app.__audioPlayAndPause__(event);
+					};
+
+					if(typeof runFun === 'function'){
+
+						// 由于小程序的事件绑定方式与冒泡机制问题,此处使用计时器以避免事件被同时多次调用
+						clearTimeout(app[timer]);
+						app[timer] = setTimeout(()=>{
+							runFun(event)
+						});
+					};
+				};
+			});
+			app[`__todo_checkboxChange`] = (event)=>{};
+		};
+
+		return json;
+	}
+};
+
+module.exports = towxml;

+ 177 - 0
towxml/outTemplate.js

@@ -0,0 +1,177 @@
+
+const tagsAndAttrs = require('./lib/tagsAndAttrs');
+class outwxml{
+    constructor(option){
+        const _ts = this;
+        _ts.config = {};
+
+        option = option || {};
+
+        for(let i in option){
+          _ts.config[i] = option[i];
+        };
+
+        _ts.m = {
+            fs:require('fs'),
+            path:require('path')
+        };
+    }
+    init(){
+        const _ts = this;
+        _ts.outtag();
+
+        let s = _ts.outwxml();
+        _ts.m.fs.writeFileSync('./renderTemplate.wxml',s);
+    }
+
+    //输出tag
+    outtag(id){
+        const _ts = this;
+        let s = '',
+            wxmlTag = tagsAndAttrs.wxml;
+        
+        wxmlTag.forEach((item,index)=>{
+            let imgMode = '',
+                attr = _ts.outattr(item);
+	        if(item === 'image'){
+		        imgMode = `mode="{{item.type === 'audio' ? '' : 'widthFix'}}"`;
+            };
+
+            // todo添加绑定事件
+            if(item === 'checkbox-group'){
+                attr += `bindchange="{{item.attr['bindchange']}}"`;
+            };
+            if(item === 'checkbox'){
+                attr += `value="{{item.attr['value']}}"`;
+            };
+
+            s+= `<${item} wx:if="{{item.node === 'element' && item.tag === '${item}'}}" ${attr} ${imgMode}><block wx:for="{{item.child}}" wx:key="{{item}}"><template is="m${id}" data="{{item}}"/></block></${item}>`;
+        });
+
+        return s;
+    }
+
+    //生成模版对应属性
+    outattr(tagName){
+        tagName = tagName || '';
+        const _ts = this;
+        
+        let s = '',
+            attr = [];
+        attr.push(...tagsAndAttrs.attrs);
+
+        switch (tagName) {
+            case 'navigator':
+                attr.push('href');
+            break;
+            case 'checkbox':
+            case 'radio':
+            case 'switch':
+                attr.push('checked');
+            break;
+            case 'audio':
+                attr.push('poster');
+                attr.push('src');
+                attr.push('name');
+                attr.push('author');
+                attr.push('loop');
+                // attr.push('controls');
+                s += 'controls="true" ';
+            break;
+            case 'video':
+                attr.push('poster');
+                attr.push('src');
+            break;
+            case 'image':
+                attr.push('src');
+            break;
+        };
+
+        s += `data-_el="{{item}}"`;
+        attr.forEach((item,index)=>{
+            switch (item) {
+                case 'class':
+                    s += `${item}="{{item.attr.class}}"`;
+                break;
+                case 'href':
+                    s += `url="{{item.attr.${item}}}"`;
+                break;
+                default:
+                    let aItem = item.split(':');
+                    if(aItem.length > 1){
+                        s += `${item}='__${aItem[0]}_${aItem[1]}'`;
+                    }else{
+                        s += `${item}="{{item.attr['${item}']}}"`;
+                    };
+                break;
+            };                   
+        });
+        return s;
+    }
+
+    //wxml模版生成
+    outwxml(){
+        const _ts = this;
+        let s = '';
+
+        for (let i = 0, len = _ts.config.depth; i<len; i++){
+            let c = i < len - 1 ? i+1 : i;
+            let temp = `<template name="m${i}"><block wx:if="{{item.node === 'text'}}">{{item.text}}</block>${_ts.outtag(c)}</template>`;
+            // let temp = `<template name="m${i}">
+            //         <!--文字-->
+            //         <block wx:if="{{item.node === 'text'}}">
+            //             {{item.text}}
+            //         </block>
+                    
+            //         ${_ts.outtag(c)}
+                    
+            //     </template>
+            // `;
+            // let temp = `
+            //     <template name="m${i}">
+            //         <!--文字-->
+            //         <block wx:if="{{item.node === 'text'}}">
+            //             {{item.text}}
+            //         </block>
+                    
+            //         <!--视图-->
+            //         <view
+            //             wx:if="{{item.node === 'element' && item.tag === 'view'}}"
+            //             class="{{item.attr.class}}"
+            //             width="{{item.attr.width}}"
+            //             height="{{item.attr.height}}"
+            //             data="{{item.attr.data}}"
+            //             src="{{item.attr.src}}"
+            //             id="{{item.attr.id}}"
+            //             style="{{item.attr.style}}"
+            //         >
+            //             <block wx:for="{{item.child}}" wx:key="{{item}}">
+            //                 <template is="m${c}" data="{{item}}"/>
+            //             </block>
+            //         </view>
+
+            //         <!--按钮-->
+            //         <button
+            //             wx:if="{{item.tag === 'button'}}"
+            //             class="{{item.attr.class}}"
+            //             width="{{item.attr.width}}"
+            //             height="{{item.attr.height}}"
+            //             data="{{item.attr.data}}"
+            //             src="{{item.attr.src}}"
+            //             id="{{item.attr.id}}"
+            //             style="{{item.attr.style}}"
+            //         >
+            //             <block wx:for="{{item.child}}" wx:key="{{item}}">
+            //                 <template is="m${c}" data="{{item}}"/>
+            //             </block>
+            //         </button>
+                    
+            //     </template>
+            // `;
+
+            s+=temp;
+        };
+        return s;
+    }
+};
+new outwxml({depth:10}).init();

File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/highlight.js


+ 29 - 0
towxml/plugins/hljs/index.js

@@ -0,0 +1,29 @@
+var hljs = require('./highlight');
+
+hljs.registerLanguage('bash', require('./languages/bash'));
+hljs.registerLanguage('coffeescript', require('./languages/coffeescript'));
+hljs.registerLanguage('css', require('./languages/css'));
+hljs.registerLanguage('dns', require('./languages/dns'));
+hljs.registerLanguage('dos', require('./languages/dos'));
+hljs.registerLanguage('erlang', require('./languages/erlang'));
+hljs.registerLanguage('go', require('./languages/go'));
+hljs.registerLanguage('htmlbars', require('./languages/htmlbars'));
+hljs.registerLanguage('http', require('./languages/http'));
+hljs.registerLanguage('java', require('./languages/java'));
+hljs.registerLanguage('javascript', require('./languages/javascript'));
+hljs.registerLanguage('json', require('./languages/json'));
+hljs.registerLanguage('less', require('./languages/less'));
+hljs.registerLanguage('makefile', require('./languages/makefile'));
+hljs.registerLanguage('markdown', require('./languages/markdown'));
+hljs.registerLanguage('nginx', require('./languages/nginx'));
+hljs.registerLanguage('php', require('./languages/php'));
+hljs.registerLanguage('powershell', require('./languages/powershell'));
+hljs.registerLanguage('python', require('./languages/python'));
+hljs.registerLanguage('ruby', require('./languages/ruby'));
+hljs.registerLanguage('scss', require('./languages/scss'));
+hljs.registerLanguage('shell', require('./languages/shell'));
+hljs.registerLanguage('sql', require('./languages/sql'));
+hljs.registerLanguage('swift', require('./languages/swift'));
+hljs.registerLanguage('typescript', require('./languages/typescript'));
+
+module.exports = hljs;

File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/bash.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/coffeescript.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/css.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/dns.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/dos.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/erlang.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/go.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/htmlbars.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/http.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/java.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/javascript.js


+ 1 - 0
towxml/plugins/hljs/languages/json.js

@@ -0,0 +1 @@
+module.exports=function(e){var n={literal:"true false null"},l=[e.QUOTE_STRING_MODE,e.C_NUMBER_MODE],i={end:",",endsWithParent:!0,excludeEnd:!0,contains:l,keywords:n},t={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE],illegal:"\\n"},e.inherit(i,{begin:/:/})],illegal:"\\S"},a={begin:"\\[",end:"\\]",contains:[e.inherit(i)],illegal:"\\S"};return l.splice(l.length,0,t,a),{contains:l,keywords:n,illegal:"\\S"}};

File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/less.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/makefile.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/markdown.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/nginx.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/php.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/powershell.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/python.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/ruby.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/scss.js


+ 1 - 0
towxml/plugins/hljs/languages/shell.js

@@ -0,0 +1 @@
+module.exports=function(s){return{aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}};

File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/sql.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/swift.js


File diff suppressed because it is too large
+ 1 - 0
towxml/plugins/hljs/languages/typescript.js


+ 99 - 0
towxml/plugins/hljs/style/github.wxss

@@ -0,0 +1,99 @@
+/*
+
+github.com style (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+
+.h2w-light .hljs {
+  display: block;
+  overflow-x: auto;
+  padding: 0.5em;
+  color: #333;
+  background: #f8f8f8;
+}
+
+.h2w-light .hljs-comment,
+.h2w-light .hljs-quote {
+  color: #998;
+  font-style: italic;
+}
+
+.h2w-light .hljs-keyword,
+.h2w-light .hljs-selector-tag,
+.h2w-light .hljs-subst {
+  color: #333;
+  font-weight: bold;
+}
+
+.h2w-light .hljs-number,
+.h2w-light .hljs-literal,
+.h2w-light .hljs-variable,
+.h2w-light .hljs-template-variable,
+.h2w-light .hljs-tag .hljs-attr {
+  color: #008080;
+}
+
+.h2w-light .hljs-string,
+.h2w-light .hljs-doctag {
+  color: #d14;
+}
+
+.h2w-light .hljs-title,
+.h2w-light .hljs-section,
+.h2w-light .hljs-selector-id {
+  color: #900;
+  font-weight: bold;
+}
+
+.h2w-light .hljs-subst {
+  font-weight: normal;
+}
+
+.h2w-light .hljs-type,
+.h2w-light .hljs-class .hljs-title {
+  color: #458;
+  font-weight: bold;
+}
+
+.h2w-light .hljs-tag,
+.h2w-light .hljs-name,
+.h2w-light .hljs-attribute {
+  color: #000080;
+  font-weight: normal;
+}
+
+.h2w-light .hljs-regexp,
+.h2w-light .hljs-link {
+  color: #009926;
+}
+
+.h2w-light .hljs-symbol,
+.h2w-light .hljs-bullet {
+  color: #990073;
+}
+
+.h2w-light .hljs-built_in,
+.h2w-light .hljs-builtin-name {
+  color: #0086b3;
+}
+
+.h2w-light .hljs-meta {
+  color: #999;
+  font-weight: bold;
+}
+
+.h2w-light .hljs-deletion {
+  background: #fdd;
+}
+
+.h2w-light .hljs-addition {
+  background: #dfd;
+}
+
+.h2w-light .hljs-emphasis {
+  font-style: italic;
+}
+
+.h2w-light .hljs-strong {
+  font-weight: bold;
+}

+ 70 - 0
towxml/plugins/hljs/style/monokai.wxss

@@ -0,0 +1,70 @@
+/*
+Monokai style - ported by Luigi Maselli - http://grigio.org
+*/
+
+.h2w-dark .hljs {
+  display: block;
+  overflow-x: auto;
+  padding: 0.5em;
+  background: #272822; color: #ddd;
+}
+
+.h2w-dark .hljs-tag,
+.h2w-dark .hljs-keyword,
+.h2w-dark .hljs-selector-tag,
+.h2w-dark .hljs-literal,
+.h2w-dark .hljs-strong,
+.h2w-dark .hljs-name {
+  color: #f92672;
+}
+
+.h2w-dark .hljs-code {
+  color: #66d9ef;
+}
+
+.h2w-dark .hljs-class .hljs-title {
+  color: white;
+}
+
+.h2w-dark .hljs-attribute,
+.h2w-dark .hljs-symbol,
+.h2w-dark .hljs-regexp,
+.h2w-dark .hljs-link {
+  color: #bf79db;
+}
+
+.h2w-dark .hljs-string,
+.h2w-dark .hljs-bullet,
+.h2w-dark .hljs-subst,
+.h2w-dark .hljs-title,
+.h2w-dark .hljs-section,
+.h2w-dark .hljs-emphasis,
+.h2w-dark .hljs-type,
+.h2w-dark .hljs-built_in,
+.h2w-dark .hljs-builtin-name,
+.h2w-dark .hljs-selector-attr,
+.h2w-dark .hljs-selector-pseudo,
+.h2w-dark .hljs-addition,
+.h2w-dark .hljs-variable,
+.h2w-dark .hljs-template-tag,
+.h2w-dark .hljs-template-variable {
+  color: #a6e22e;
+}
+
+.h2w-dark .hljs-comment,
+.h2w-dark .hljs-quote,
+.h2w-dark .hljs-deletion,
+.h2w-dark .hljs-meta {
+  color: #75715e;
+}
+
+.h2w-dark .hljs-keyword,
+.h2w-dark .hljs-selector-tag,
+.h2w-dark .hljs-literal,
+.h2w-dark .hljs-doctag,
+.h2w-dark .hljs-title,
+.h2w-dark .hljs-section,
+.h2w-dark .hljs-type,
+.h2w-dark .hljs-selector-id {
+  font-weight: bold;
+}

File diff suppressed because it is too large
+ 3 - 0
towxml/plugins/markdown-it-emoji.js


File diff suppressed because it is too large
+ 2 - 0
towxml/plugins/markdown-it-ins.js


File diff suppressed because it is too large
+ 2 - 0
towxml/plugins/markdown-it-mark.js


File diff suppressed because it is too large
+ 2 - 0
towxml/plugins/markdown-it-sub.js


File diff suppressed because it is too large
+ 2 - 0
towxml/plugins/markdown-it-sup.js


File diff suppressed because it is too large
+ 148 - 0
towxml/plugins/markdown-it-todoList.js


File diff suppressed because it is too large
+ 1 - 0
towxml/renderTemplate.wxml


+ 421 - 0
towxml/style/main.wxss

@@ -0,0 +1,421 @@
+/*音频播放器样式*/
+.audioForH2w {
+    height: 136rpx;
+    margin: 16rpx 0;
+    background: #f1f1f1;
+    position: relative;
+}
+
+.audioForH2w--play .audioForH2w__icon {
+    display: none;
+    opacity: 1;
+}
+
+.audioForH2w--play .audioForH2w__cover image {
+    opacity: 1;
+}
+
+/* .audioForH2w--end .audioForH2w__icon {width:20rpx; height:20rpx; background:white; border:0; left:24rpx; top:24rpx; border-radius:2rpx;} */
+.audioForH2w__cover {
+    width: 136rpx;
+    height: 136rpx;
+    background: black;
+    float: left;
+}
+
+.audioForH2w__cover image {
+    width: 100%;
+    height: 100%;
+    opacity: 0.6;
+    margin: 0;
+    transition: all 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
+}
+
+.audioForH2w__info {
+    padding-left: 20rpx;
+    padding-top: 16rpx;
+    position: absolute;
+    left: 136rpx;
+    right: 0;
+}
+
+.audioForH2w__schedule {
+    position: absolute;
+    left: 0;
+    top: 0;
+    background: rgba(0, 255, 0, 0.1);
+    height: 136rpx;
+    width: 0;
+}
+
+.audioForH2w__title {
+    display: block;
+    font-size: 24rpx;
+    height: 40rpx;
+    line-height: 40rpx;
+    font-weight: bold;
+}
+
+.audioForH2w__author {
+    display: block;
+    font-size: 20rpx;
+    height: 32rpx;
+    line-height: 32rpx;
+}
+
+.audioForH2w__time {
+    display: block;
+    font-size: 20rpx;
+    height: 32rpx;
+    line-height: 32rpx;
+}
+
+.audioForH2w__icon {
+    width: 0;
+    height: 0;
+    position: absolute;
+    left: 60rpx;
+    top: 48rpx;
+    border-width: 20rpx 0 20rpx 20rpx;
+    border-style: solid;
+    border-color: transparent transparent transparent #fff;
+    z-index: 1;
+}
+
+/*正文样式*/
+.h2w {
+    font-family: "STHeitiTC-Light", "Microsoft YaHei Light", "Hiragino Sans GB", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+    font-size: 32rpx;
+    line-height: 1.8;
+    word-wrap: break-word;
+    word-wrap: break-word;
+    word-break: break-all;
+}
+
+.h2w__main {
+    margin: 0 40rpx;
+    padding-top: 40rpx;
+}
+
+/**标题**/
+.h2w__h1,
+.h2w__h2,
+.h2w__h3,
+.h2w__h4,
+.h2w__h5,
+.h2w__h6 {
+    font-weight: bold;
+}
+
+.h2w__h1 {
+    border-bottom-style: double;
+    border-bottom-width: 6rpx;
+    font-size: 42rpx;
+    padding-bottom: 10rpx;
+    margin-bottom: 20rpx;
+}
+
+.h2w__h2 {
+    border-bottom-style: solid;
+    border-bottom-width: 1rpx;
+    font-size: 40rpx;
+    padding-bottom: 8rpx;
+    margin-bottom: 18rpx;
+}
+
+.h2w__h3 {
+    font-size: 38rpx;
+    padding-bottom: 6rpx;
+    margin-bottom: 12rpx;
+}
+
+.h2w__h4 {
+    font-size: 36rpx;
+    padding-bottom: 4rpx;
+    margin-bottom: 12rpx;
+}
+
+.h2w__h5 {
+    font-size: 34rpx;
+    padding-bottom: 2rpx;
+    margin-bottom: 12rpx;
+}
+
+.h2w__h6 {
+    margin-bottom: 12rpx;
+}
+
+
+/**表格**/
+.h2w__table {
+    width: 100%;
+    border-collapse: collapse;
+    border-spacing: 0;
+    display: table;
+    margin-bottom: 40rpx;
+}
+
+.h2w__table .h2w__tr:nth-child(2n) {
+    background-color: red;
+}
+
+.h2w__colgroup {
+    display: table-column-group;
+}
+
+.h2w__col {
+    display: table-column;
+}
+
+.h2w__thead {
+    display: table-header-group;
+}
+
+.h2w__tbody {
+    display: table-row-group;
+}
+
+.h2w__tfoot {
+    display: table-footer-group;
+}
+
+.h2w__tr {
+    display: table-row;
+}
+
+.h2w__th,
+.h2w__td {
+    padding: 8rpx 16rpx;
+    font-size: 28rpx;
+    border-width: 1rpx;
+    border-style: solid;
+    display: table-cell;
+}
+
+.h2w__th {
+    font-weight: bold;
+}
+
+/**代码块**/
+.h2w__pre {
+    /*white-space:nowrap;*/
+    padding: 20rpx;
+    font-size: 28rpx;
+    word-break: normal;
+    border-width: 1rpx;
+    border-style: solid;
+    margin-bottom: 40rpx;
+    white-space: nowrap;
+    overflow-x: auto;
+}
+
+.h2w__pre .h2w__code {
+    padding: 0;
+    border: 0;
+    font-size: 100%;
+}
+
+.h2w__pre,
+.h2w__code {
+    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace, "STHeitiTC-Light", "Microsoft YaHei Light", -apple-system, system-ui, BlinkMacSystemFont;
+}
+
+.h2w__code {
+    /* padding: 4rpx 8rpx; */
+    /* margin: 0 4rpx; */
+    /* border-width: 1rpx; */
+    /* border-style: solid; */
+    /* border-radius: 8rpx; */
+    font-size: 100%;
+    overflow-x: auto;
+}
+
+.h2w__pre .h2w__span,
+.h2w__pre .h2w__a,
+.h2w__pre .h2w__span,
+.h2w__pre .h2w__b,
+.h2w__pre .h2w__strong,
+.h2w__pre .h2w__i,
+.h2w__pre .h2w__em {
+    display: inline;
+}
+
+.h2w__pre {
+    white-space: pre;
+    display: block;
+}
+
+.h2w__pre .h2w__code {
+    white-space: pre;
+    width: 9999px;
+    display: block;
+    font-size: 80%;
+}
+
+/**列表**/
+.h2w__ul,
+.h2w__ol {
+    margin-bottom: 40rpx;
+    padding-left: 1rem;
+}
+
+.h2w__ul .h2w__ol,
+.h2w__ol .h2w__ul {
+    margin-bottom: 0;
+}
+
+.h2w__li {
+    display: list-item;
+}
+
+/**todo**/
+.h2w__todogroup {
+    margin-bottom: 40rpx;
+}
+
+.h2w__todogroup .h2w__todogroup {
+    padding-left: 1.6rem;
+}
+
+/**一级ol样式**/
+.h2w__ol {
+    list-style-type: decimal;
+}
+
+/**二级ol样式**/
+.h2w__ul .h2w__ol,
+.h2w__ol .h2w__ol {
+    list-style-type: lower-roman;
+}
+
+/**三级ol样式**/
+.h2w__ul .h2w__ul .h2w__ol,
+.h2w__ul .h2w__ol .h2w__ol,
+.h2w__ol .h2w__ul .h2w__ol,
+.h2w__ol .h2w__ol .h2w__ol {
+    list-style-type: lower-alpha;
+}
+
+/**一级ul样式**/
+.h2w__ul {
+    list-style-type: disc;
+}
+
+/**二级ul样式**/
+.h2w__ul .h2w__ul,
+.h2w__ol .h2w__ul {
+    list-style-type: circle;
+}
+
+/**三级样式**/
+.h2w__ol .h2w__ol .h2w__ul,
+.h2w__ol .h2w__ul .h2w__ul,
+.h2w__ul .h2w__ol .h2w__ul,
+.h2w__ul .h2w__ul .h2w__ul {
+    list-style-type: square;
+}
+
+/**块元素**/
+.h2w__p {
+    margin: 20rpx 0 20rpx 0;
+    /*word-wrap:break-word;
+    word-break:break-all;*/
+    /*text-align:justify;*/
+}
+
+.h2w__div {
+    /*text-align:justify;*/
+}
+
+.h2w__blockquote {
+    border-left-width: 8rpx;
+    border-left-style: solid;
+    padding: 0 20rpx;
+}
+
+/**内连元素**/
+.h2w__a,
+.h2w__span,
+.h2w__b,
+.h2w__strong,
+.h2w__i,
+.h2w__em {
+    display: inline;
+}
+
+.h2w__b,
+.h2w__strong {
+    font-weight: bold;
+}
+
+.h2w__i,
+.h2w__em {
+    font-style: italic;
+}
+
+/**文本删除线**/
+.h2w__s,
+.h2w__strike,
+.h2w__del {
+    text-decoration: line-through;
+}
+
+/**文本下划线**/
+.h2w__ins,
+.h2w__u {
+    text-decoration: underline;
+}
+
+/**链接**/
+.h2w__a {
+    margin: 0 8rpx;
+    border-bottom-width: 1rpx;
+    border-bottom-style: solid;
+    line-height: 1;
+}
+
+.h2w__hr {
+    height: 8rpx;
+    margin: 40rpx 0;
+}
+
+/**荧光标记**/
+.h2w__mark {
+    border-radius: 4rpx;
+}
+
+/**上标、下标**/
+.h2w__sup,
+.h2w__sub {
+    font-size: 75%;
+    position: relative;
+}
+
+.h2w__sup {
+    top: -0.5em;
+}
+
+.h2w__sub {
+    bottom: -0.25em;
+}
+
+/**emoji表情**/
+.h2w__g-emoji {
+    margin: 0 0.1em;
+    font-family: "Apple Color Emoji", "Segoe UI", "Segoe UI Emoji", "Segoe UI Symbol";
+}
+
+/**内置元素**/
+image,
+video {
+    width: 100%;
+    margin: 10rpx auto;
+}
+
+image {
+    height: auto;
+}
+
+video {
+    height: 220px;
+}

+ 87 - 0
towxml/style/theme/dark.wxss

@@ -0,0 +1,87 @@
+/*音频播放器样式*/
+.h2w-dark  .audioForH2w {
+    background: #1f1f1f;
+}
+
+.h2w-dark .audioForH2w__cover {
+    background: black;
+}
+
+.h2w-dark .audioForH2w__schedule {
+    background: rgba(0, 255, 0, 0.2);
+}
+
+.h2w-dark .audioForH2w__icon {
+    border-color: transparent transparent transparent #fff;
+}
+
+/*正文样式*/
+.h2w-dark {
+  color:#ddd;
+  background-color:#000;
+}
+
+/**标题**/
+.h2w-dark .h2w__h1,
+.h2w-dark .h2w__h2 {
+    border-color:#3d3d3d;
+}
+
+
+/**表格**/
+.h2w-dark .h2w__thead .h2w__tr {
+    background-color:#1f1f1f;
+}
+.h2w-dark .h2w__table .h2w__tr:nth-child(2n){
+    background-color:#090909;
+}
+.h2w-dark .h2w__th,
+.h2w-dark .h2w__td {
+    border-color:#333;
+}
+
+
+/**代码块**/
+.h2w-dark .h2w__pre,
+.h2w-dark .h2w__pre .h2w__code {
+    background-color:#1b1b1b;
+    border-color:#262626;
+}
+
+.h2w-dark .h2w__code {
+    background-color:#272822;
+    border-color:#1b1c18;
+}
+
+
+/**块元素**/
+.h2w-dark .h2w__blockquote {
+    border-left-color:#10230f;
+}
+
+/**内连元素**/
+.h2w-dark .h2w__a {
+    color:#1aad16; border-color:#4d804b;
+}
+
+.h2w-dark .h2w__hr {
+    background-color:#242424;
+}
+
+.h2w-dark .h2w__mark {
+    background:yellow;
+    color:black;
+}
+
+.h2w-dark .h2w__todoCheckbox .wx-checkbox-input {
+    background:#2e2e2e; border-color:#494949;
+}
+.h2w-dark .h2w__todoCheckbox .wx-checkbox-input.wx-checkbox-input-checked {
+    background:green; border-color:#4d804b;
+}
+.h2w-dark .h2w__todoCheckbox .wx-checkbox-input.wx-checkbox-input-checked::before {
+    color:white;
+}
+
+/**代码高亮样式**/
+@import '/towxml/plugins/hljs/style/monokai.wxss';

+ 75 - 0
towxml/style/theme/light.wxss

@@ -0,0 +1,75 @@
+/*音频播放器样式*/
+.h2w-light .audioForH2w {
+    background: #f1f1f1;
+}
+
+.h2w-light .audioForH2w__cover {
+    background: black;
+}
+
+.h2w-light .audioForH2w__schedule {
+    background: rgba(0, 255, 0, 0.1);
+}
+
+.h2w-light .audioForH2w__icon {
+    border-color: transparent transparent transparent #fff;
+}
+
+/*正文样式*/
+.h2w-light {
+  color:#333;
+  background-color:white;
+}
+
+/**标题**/
+.h2w-light .h2w__h1,
+.h2w-light .h2w__h2 {
+    border-color:#eee;
+}
+
+
+/**表格**/
+.h2w-light .h2w__thead .h2w__tr {
+    background-color:#f6f8fa;
+}
+.h2w-light .h2w__table .h2w__tr:nth-child(2n){
+    background-color:#fbfcfd;
+}
+.h2w-light .h2w__th,
+.h2w-light .h2w__td {
+    border-color:#dfe2e5;
+}
+
+
+/**代码块**/
+.h2w-light .h2w__pre {
+    background-color:#f6f8fa;
+    border-color:#eaedf0;
+}
+
+.h2w-light .h2w__code {
+    color: red;
+}
+
+
+/**块元素**/
+.h2w-light .h2w__blockquote {
+    border-left-color:#dfe2e5;
+}
+
+/**内连元素**/
+.h2w-light .h2w__a {
+    color:#1aad16; border-color:#b9d9b8;
+}
+
+.h2w-light .h2w__hr {
+    background-color:#eee;
+}
+
+.h2w-light .h2w__mark {
+    background:yellow;
+    color:black;
+}
+
+/**代码高亮样式**/
+@import '/towxml/plugins/hljs/style/github.wxss';