blog开发:markdown编辑器预览patch更新

markdownmermaidmorphdom


发表于 2019-06-24 16:38


关于预览html的渲染,在之前,我都是之前通过$('#').setHtml()这个方法来渲染的,但是存在图片或者图表的时候,会出现如下问题:

screen_1.gif

最好的更新方法是只更新变更的dom,找了一番后,发现了如下插件: morphdom

morphdom使用很简单,首先创建一个div

var m2h = md.render(editor.getValue());
var div = document.createElement('div');
div.id = "preview-block";
div.innerHTML = m2h;

然后通过morphdom更新

morphdom($("#preview-block").get(0),div);

但这样我发现每次mermaid图表都会被更新,看了一下之后发现,mermaid是需要额外渲染的,根据官网推荐:

var renderer = new marked.Renderer();
renderer.code = function (code, language) {
    if(code.match(/^sequenceDiagram/)||code.match(/^graph/)){
        return '<div class="mermaid">'+code+'</div>';
    }
    else{
        return '<pre><code>'+code+'</code></pre>';
    }
};

它并没有在渲染的时候返回一个完整的html,而是返回了一个有mermaid样式的div元素,返回之后再通过

mermaid.init({},'.mermaid');

这个方法来渲染,因此在比对的时候,通过$("#preview-block").get(0)得到的是一个渲染完成后的mermaid html元素,而后面markdown解析得到的,还没有渲染完成,因此每次都会先更新,再渲染。要解决这个问题,想到了两种思路:

  1. 将markdown得到的html文本也用mermaid渲染一下,然后再对比元素
  2. 比对生成mermaid图表的语言

实际操作过程中,第一种情况行不通,因为mermaid渲染之后每次都会都会生成一个id不同的svg元素,而svg通过这个id来定义样式。所以转为第二种方法,首先改下markdown对mermaid的渲染逻辑,多生成一个包含图表语言的div:

var renderer = new marked.Renderer();
renderer.code = function (code, language) {
    if(code.match(/^sequenceDiagram/)||code.match(/^graph/)){
        return '<div class="mermaid-block"><div class="mermaid">'+code+'</div><div class="mermaid-source" style="display:none">'+code+'</div></div>';
    }
    else{
        return '<pre><code>'+code+'</code></pre>';
    }
};

然后再通过morphdom来判断是否需要变更:

morphdom($("#preview-block").get(0),div,{
  onBeforeElUpdated  : function(f,t){
      if(f.classList.contains('mermaid-block')
          && t.classList.contains('mermaid-block')){
              var old =  f.getElementsByClassName('mermaid-source')[0].textContent;
              var now =  t.getElementsByClassName('mermaid-source')[0].textContent;
              if(old == now){
                  //更新属性
                  cloneAttributes(f,t);
                  return false;
              }
          }
      return true;
  }
});

附上使用后效果:
screen_2.gif


搜索