【问题标题】:Using Javascript or jQuery to clean WYSIWYG editor's HTML output使用 Javascript 或 jQuery 清理所见即所得编辑器的 HTML 输出
【发布时间】:2014-08-04 12:58:08
【问题描述】:

我使用的 CMS 有一个非常烦人的 WYSIWYG 编辑器,叫做 Summernote。这个编辑器看起来很漂亮,实际上工作得很好,但是它输出的 HTML 非常糟糕,并且没有任何用于样式输出的配置选项。例如,这是一些带有下划线的粗斜体文本:

<span style="text-decoration: underline;">
    <span style="font-style: italic;">
        <span style="font-weight: bold;">
            Help!! I'm being squashed by 3 heavy tags.
        </span>
    </span>
</span>

图像具有内联 CSS 样式,为图像提供固定宽度,这对于响应式网站来说毫无用处:

<img src="..." style="width:832px;">

YouTube iFrame 具有固定尺寸,可以在手机屏幕上显示:

<iframe src="..." width="560" height="380">

所以,如您所见,这不是很好,但我没有更改编辑器的选项(不允许),我需要想出一种方法来纠正这些问题,然后再将 HTML 保存到数据库。在我的例子中,使用 jQuery。

所以,经过一些试验和错误,我设法用这个小 sn-p 解决了响应问题:

var code = $('#summernote').code();
var newCode = $('<div></div>').append(code)
    .find('iframe').wrap('<div class="flexVideo"/>')
    .end()
    .find('img').removeAttr('style').wrap('<div class="flexPhoto"/>')
    .end()
    .html();

Working JSFIDDLE demo.

如您所见,这会将所有 iFrame 包装在一个响应式包装器中,将所有图像包装在另一个包装器中(用于非响应式目的),并从图像中删除所有内联样式,使它们更加流畅。这很好用,但我在最后一部分真的很挣扎;用适当的元素替换所有这些跨度标签,不幸的是我需要寻求帮助。

我知道使用这样的东西可以为 BOLD 选择 SPAN 元素,使用 wrapInner()unwrap() 我可以用适当的文本元素替换跨度:

$('span').filter(function() {
     return $(this).css('font-weight') == 'bold';
}).wrapInner('<b></b>').unwrap()

但是

1) 我什至无法让 wrapInner() 自己工作 (check this fiddle)。

2) 如果这在物理上和效率上都是可行的,请提供建议,并建议如何将它们全部链接在一起。

3) 有时跨度顺序不同,取决于单击按钮的顺序。

这是我的粗制滥造,失败的尝试:

var code = $('#summernote').code();
var newCode = $('<div></div>').append(code)
    .find('iframe').wrap('<div class="flexVideo"/>')
    .end()
    .find('img').removeAttr('style').wrap('<div class="flexPhoto"/>')
    .end()
    .find('span').filter(function() {
        return $(this).css('font-weight') == 'bold';
    })
    .wrapInner('<b></b>')
    .unwrap()
    .end()
    .html();

查看这个失败的JSFIDDLE 演示。没有错误,但它肯定没有按照它所说的那样做。我试过大喊大叫,但没用。

惊人的答案

对于所有受挫的 Summernote 用户,您可能会发现这很有用。为什么神奇?好吧,虽然在这个例子中它被分成了多行,但这实际上是一个单行!

var newCode = $('<div></div>').append(code)
   .find('iframe')
       .wrap('<div class="flexVideo"/>')
   .end()
   .find('img')
       .removeAttr('style')
       .wrap('<div class="flexPhoto"/>')
   .end()
   .find('span')
       .filter("[style*='underline']")
           .removeAttr('style')
           .addClass('underline')
       .end()
       .filter("[style*='bold']")
           .wrapInner('<b></b>')
           .children()
               .unwrap()
           .end()
       .end()
       .filter("[style*='italic']")
           .wrapInner('<i></i>')
           .children()
               .unwrap()
           .end()
       .end()
   .end()
   .html();

它有什么作用?

  • 从限制响应能力的图像中删除内联样式。
  • 将图像包裹在 DIV 中(个人偏好用按钮和文本覆盖图像)。
  • 将 iframe 视频包装在 DIV 中以实现响应。
  • 用类underline替换内联text-decoration:underline
  • 用正确的&lt;i&gt; 标签替换&lt;span style="font-style:italic"&gt; 标签。
  • 用正确的&lt;b&gt; 标签替换&lt;span style="font-weight:bold"&gt; 标签。

【问题讨论】:

  • 请拒绝投票的原因?我第一次很好地解释了自己,提供了代码并分享了我的尝试。
  • 恕我直言,您正在破坏您的代码,@PaparazzoKid。如果您自己编写页面,我严重怀疑您是否会在em 标记内包含strong 标记。或相反亦然。样式不应该来自 html,而应该来自 css :)
  • @skip405 - 除非我误解了你的观点,否则我必须不同意你的观点。是的,如果我自己编写代码可能会有所不同,但我不会破坏我的代码。使用&lt;em&gt;You are in &lt;strong&gt;BIG&lt;/strong&gt; trouble&lt;/em&gt; 是完全可以接受的标记。这里有一个很好的阅读:stackoverflow.com/questions/2200590/…
  • 对不起,我不确定我是否得到您对另一个问题的参考,其中 6 个答案中有 4 个告诉您我做了什么))c2n.me/iFlZXD。至于将整个句子包裹在em 中,我当然会尽量避免这种情况。我想我只是没有让自己足够清楚。无论如何,我想这个问题已经得到解答并解决了你的问题。干杯:)
  • @skip405:喂,我还没说完呢,嘿嘿,开玩笑的。我想我现在明白你的意思了,尽管这整个主题开始让我感到困惑!那么你会建议使用 而不是 并使用 CSS 设置它们的样式吗?

标签: javascript jquery html


【解决方案1】:

您的选择器都混乱了,并且您没有正确引用链中所需的元素。

在这种情况下(出于诊断目的),我从末尾删除了 .html() 并将 newCode 输出到 console.log() 命令中,我可以在 fireBug 中查询该命令。

这表明过滤器选择器找不到匹配的元素。我更改了过滤器以使用不同的选择器。然后我意识到您正在尝试解开错误的元素,该元素正在删除您的大部分标记。所以我下降到匹配的粗体跨度的孩子,然后打开它们。然后我结束了链条。

var code = '<span style="text-decoration: underline;"><span style="font-style: italic;"><span style="font-weight: bold;">asdasdad</span></span></span><br><br><img src="" style="width:748px;"><br><br><iframe src="" width="560" height="380"><iframe>';

var newCode = $('<div></div>').append(code)
    .find('iframe')
        .wrap('<div class="flexVideo"/>')
    .end()
    .find('img')
        .removeAttr('style')
        .wrap('<div class="flexPhoto"/>')
    .end()
    .find('span')
        .filter("[style*='bold']")
            .wrapInner('<strong></strong>')
            .children()
                .unwrap()
            .end()    
        .end()   
    .end()
    .html();

$('.output').text(newCode);

有关详细信息,请参阅此更新的小提琴:http://jsfiddle.net/P2Ry8/6/

【讨论】:

  • 重点不是要正确渲染html,而是要得到想要的(改变的)html
  • 我特意使用text()将输出的HTML写成字符串,这样我就可以检查更改了。
  • @ChrisSpittles 请不要生气,但在你第一次回答之后,你是我认为最后一个会找到答案的人哈哈哈。事实证明,这是天才。这是一个艰难的人群,但你更坚强。谢谢。
  • 无害无犯规。我只是误解了你最初想要做什么。
【解决方案2】:

在您的情况下,.unwrap() 解开 span 元素,而您需要解开新创建的 &lt;strong&gt;。基本思路可以看这里:http://jsfiddle.net/skip405/DLuD4/

更改后的 html 包含两个 spans 而不是三个。

我决定从头开始写它:)

要深入研究覆盖跨度,我们需要检查所谓的“第一级”跨度并将它们更改为相应的 html-elements(我个人不喜欢,因为 html-tags 有它们的语义,使用所见即所得的人可能不清楚),但这是另一个要讨论的话题。我还搜索了孩子spans 并删除了他们的style 属性。

无论如何,我设法实际上更改了您的代码以获得所需的效果。您可以在这里找到:http://jsfiddle.net/skip405/DLuD4/2/

最终的结果不是 100% 好,但这是一个开始,希望你会发现它有用。

编辑: 为了让事情变得更干燥,我修改了我的原始版本并更新了小提琴。 http://jsfiddle.net/skip405/DLuD4/4/

$('.wysiwyg').each(function(){
    var $wysiwyg = $(this),
        $directSpans = $wysiwyg.children('span');

    //first lets create top-level elements
    $directSpans.each(function(){
        var $span = $(this),
            $innerSpans = $span.find('span'),
            element = '';

        switch( $span.attr('style') ) {
            case 'font-weight: bold;':
                element = 'strong';
                break;
            case 'font-style: italic;':
                element = 'em';
                break;
            case 'text-decoration: underline;':
                element = 'u';
                break;
        }

        $span.wrapInner('<' + element + ' />').find(element).unwrap();

        $innerSpans.each(function(){
            var innerSpan = $(this),
                innerStyle = innerSpan.attr('style'),
                className = '';

            switch( innerStyle ) {
                case 'font-weight: bold;':
                    className = 'bold';
                    break;
                case 'font-style: italic;':
                    className = 'italic';
                    break;
                case 'text-decoration: underline;':
                    className = 'underline';
                    break;
            }
            innerSpan.removeAttr('style').parent().addClass(className);
        });

    });

});

【讨论】:

  • 感谢您的努力,我的朋友,但我认为 Chris Spittles 非常坚定地一针见血。
  • @PaparazzoKid,同意,没问题)
猜你喜欢
  • 1970-01-01
  • 2012-11-04
  • 1970-01-01
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多