Angular4+ng2-ckeditor踩坑

机缘巧合,刚好公司准备做一个新闻版块。
在网上找了很多富文本插件感觉都跟angular4不大契合,最终踩坑CKEditor,这款强到爆炸得富文本插件!
发现国内几乎没有分享这方面踩坑得文章,所以最终决定把这段踩坑血泪史写下来,供大家参考。
CKEditor官网:  https://www.ckeditor.com  

CKEditor插件列表: https://ckeditor.com/cke4/addons/plugins/all

国内被墙了,各位大佬搭把梯子吧!脱坑必备!

1.安装ng2-ckeditor插件(因为我得angular版本是4.2.6所以就没有安装最新版本了):

npm install ng2-ckeditor@1.1.9 --save

2.引入module.ts你懂得

import {CKEditorModule} from 'ng2-ckeditor';
@NgModule({
  imports: [
      xxx..,
      CKEditorModule,
    ]

3.将翻墙下载得ckeditor包解压放到assert目录下:assert/ckeditor,并在index.html中引用它

  <!-- 引入ckeditor -->
  <script src="assets/ckeditor/ckeditor.js"></script>

4.component.html

  <!-- 富文本框 -->
  <ckeditor [(ngModel)]="article.content"
            debounce="500"
            [config]="config">
  </ckeditor>

5.component.ts配置

config: any = {
    // 文件上传路径
    filebrowserUploadUrl :`/api-admin/admin/public/flashUpload`,
    // 图片上传后端url
    filebrowserImageUploadUrl:`/api-admin/admin/public/imageUpload`,
    // flash上传后端url
    filebrowserFlashUploadUrl:`/api-admin/admin/public/flashUpload`,
    // audio上传url
    filebrowserAudioUploadUrl:`/api-admin/admin/public/flashUpload`,
    // 其他插件,字数统计,提示信息
    extraPlugins:`widget,html5video,emojione,video,audio,
        image2,wordcount,notification,notificationaggregator`,
};
// 注意: 需要注意得是在官网下载得full压缩包并未含有
// html5video,emojione,video,audio,image2,wordcount等插件,需要自行配置!!!
// 我在此处只配置了各种文件上传得链接,主要配置在assert/ckeditor/config.js中

6.assert/ckeditor/config.js配置

CKEDITOR.editorConfig = function (config) {
  /**
   * 插件语言
   * @type {string}
   */
  config.language = 'zh-cn';
  /**
   * 插件字体
   * @type {string}
   */
  config.font_names = '宋体/宋体;黑体/黑体;仿宋/仿宋_GB2312;楷体/楷体_GB2312;隶书/隶书;幼圆/幼圆;微软雅黑/微软雅黑;宋体/SimSun;'
    + '新宋体/NSimSun;仿宋_GB2312/FangSong_GB2312;楷体_GB2312/KaiTi_GB2312;黑体/SimHei;微软雅黑/Microsoft YaHei;幼圆/YouYuan;华文彩云/STCaiyun;华文行楷/STXingkai;'
    + '方正舒体/FZShuTi;方正姚体/FZYaoti;Arial;Comic Sans MS;Courier New;Georgia;Lucida Sans Unicode;Tahoma;Times New Roman;Trebuchet MS;Verdana;';
  /**
   * 插件默认字体
   * @type {string}
   */
  config.font_defaultLabel = '宋体';

  /**
   * 设置工具栏显示模式
   * @type {string}
   */
  config.toolbar = 'Full';
  /**
   * 工具栏全显示模式
   * @type {[null,null,null,string,null,null,null,null,null,string,null,null,null]}
   */
  config.toolbar_Full = [
      {
        name: 'document', items: [
        'Source', '-', 'NewPage', 'DocProps', 'Preview', 'Print', '-', 'Templates'
      ]
      },
      {
        name: 'clipboard', items: [
        'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo'
      ]
      },
      {
        name: 'editing', items: [
        'Find', 'Replace', '-', 'SelectAll', '-', 'SpellChecker', 'Scayt'
      ]
      },
      '/',
      {
        name: 'forms', items: [
        'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'
      ]
      },
      {
        name: 'basicstyles', items: [
        'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'
      ]
      },
      {
        name: 'links', items: [
        'Link', 'Unlink', 'Anchor'
      ]
      },
      {
        name: 'paragraph', items:
        ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv',
          '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'
        ]
      },
      // todo 在这里设定需要的插件 ...
      // ,'Flash','Smiley','Video' Video是用得国产插件
      {
        name: 'insert', items: [
        'Image', 'Html5video', 'Table', 'HorizontalRule', 'Emojione', 'Video', 'Audio', 'Image2','SpecialChar', 'PageBreak', 'Iframe'
      ]
      },
      '/',
      {
        name: 'styles', items: [
        'Styles', 'Format', 'Font', 'FontSize'
      ]
      },
      {
        name: 'colors', items: [
        'TextColor', 'BGColor'
      ]
      },
      {
        name: 'tools', items: [
        'Maximize', 'ShowBlocks', '-'
        // ,'About'
      ]},
  ];
  /**
   * 基础模式插件列表
   * @type {[null]}
   */
  config.toolbar_Basic = [['Bold', 'Italic', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink', '-'
    // , 'About'
  ]];
  /**
   * 工具栏是否可以被收缩
   * @type {boolean}
   */
  config.toolbarCanCollapse = true;
  /**
   * 工具栏默认是否展开
   * @type {boolean}
   */
  config.toolbarStartupExpanded = true;
  /**
   * 取消 “拖拽以改变尺寸”功能 plugins/resize/plugin.js
   * @type {boolean}
   */
  config.resize_enabled =  true;
  /**
   * 取消文章体得html头
   * @type {boolean}
   */
  config.fullPage = false;
  /**
   * 图片展示方式
   * @type {string}
   */
  config.removeDialogTabs = 'image:advanced;image:advanced';
  /**
   * 禁止图片上传完毕后自动填充长宽
   * @type {boolean}
   */
  config.image_prefillDimensions = false;
  /**
   * 图片展示文字
   */
  config.image_previewText = '';

  /**
   * 字符统计插件
   * @type {{showParagraphs: boolean, showWordCount: boolean, showCharCount: boolean, countSpacesAsChars: boolean, countHTML: boolean, maxWordCount: number, maxCharCount: number, filter: *}}
   */
  config.wordcount = {
    // 段落统计
    showParagraphs: true,
    // 词数统计
    showWordCount: true,
    // 字数统计
    showCharCount: true,
    // 将空格计入字符
    countSpacesAsChars: false,
    // 统计html
    countHTML: false,
    // 最大词数 -1代表无上限
    maxWordCount: -1,
    // 最大字数 -1代表无上限
    maxCharCount: -1,
    // 移除关键词统计 类似mediaembed 节点之类,可以设置不统计
    filter: new CKEDITOR.htmlParser.filter({
      elements: {
        div: function (element) {
          if (element.attributes.class == 'mediaembed') {
            return false;
          }
        }
      }
    })
  };
// 更多配置请参见官网;
// 需要注意得是config.toolbar_Full得配置,原有配置为'Image','Flash',xxx
// 因为我得业务不需要用到flash,所以我将它禁用了。
// 'Html5video','Emojione','Audio','Image2',插件都是我从官网下载过来得。粘贴到
// assert/ckeditor/plugins/目录中,如果引用了Image2那么原有得Image插件就失效了,Image2可以自
// 由调整图片宽高位置,所以我选择了Image2,它得插件名在官网叫做Enhanced Image
// ------------------- 分割线 -------------------
// 要在此处使用如上插件就需要配置extraPlugins
// extraPlugins : 'widget,html5video,emojione,video,audio,image2,wordcount,
// notification,notificationaggregator',
// 这个配置写在assert/ckeditor/config.js或者对应得component.ts得config中都可以,但是建议配置 
// 在component.ts中,方便每个页面灵活使用CKEditor插件
// -------------------- 巨坑线 ------------------**
// 在使用Audio插件得时候需要特别注意,官网得工程师因为粗心大意给大家留了一个bug,
// 目测评论都在喷他,想静静......
// 解决之道:首先将解压后得Audio文件夹改为小写audio,然后放到plugins中,在audio/plugin.js中修改
// 第25行 CKEDITOR.plugins.add( 'audio', // 将大写'Audio'改为小写'audio'就搞定了 = =
// -------------------- 样式修改 ----------------
// 在某些皮肤下可能会导致dialog弹出框样式散乱所以在/skins/xxx/dialog.css中最后一行添加如下样式

// .cke_dialog_ui_html{height:350px;overflow:auto;}

7.后端接口

 因为考虑到大家可能使用不同得后端服务这里就说一下upload接口得返回值吧;
  // 成功:{"uploaded":1,"fileName":"文件名.文件格式","url":"上传成功后得资源路径url"}
  // 失败: {"uploaded":0,"error":{"message":"资源上传错误得原因..."}}
  做Java得同学们我就附赠一小块后端实现代码吧(为了方便演示就没有刻意封装了,大神勿喷....)


/**
 * CKEditor上传图片接口
 * @param request
 * @return
 * @throws IOException
 * @Author Jack
 */
@RequestMapping(value = "/imageUpload")
public String imageUpload(HttpServletRequest request) throws IOException {
    boolean uploadFlag = false;
    // 创建一个通用的多部分解析器
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession()
            .getServletContext());
    // 图片名称
    String fileName = null;
    // 判断 request 是否有文件上传,即多部分请求
    if (multipartResolver.isMultipart(request)) {
        // 转换成多部分request
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
        // 取得request中的所有文件名
        Iterator<String> iter = multiRequest.getFileNames();
        //    定义存库相对路径名称
        String relativeName = "";
        //    功能文件夹,注意:代码只能创建一级文件夹,需先在服务器创建文件夹目录
        String tmpPath = AdminConstant.ADMIN_FILE_PATH;
        //    时间文件夹
        String folderYMD = new DateTime().toString("yyyyMMdd") + "/";

        while (iter.hasNext()) {
            // 取得上传文件
            MultipartFile file = multiRequest.getFile(iter.next());
            if (file != null) {
                // 取得当前上传文件的文件名称
                String myFileName = file.getOriginalFilename();
                // 如果名称不为“”,说明该文件存在,否则说明该文件不存在
                if (myFileName.trim() != "") {
                    // 获得图片的原始名称
                    String originalFilename = file.getOriginalFilename();
                    // 获得图片后缀名称,如果后缀不为图片格式,则不上传
                    String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
                    if (!fileTypes.contains(suffix)) {
                        continue;
                    }
                    InputStream is = file.getInputStream();
                    byte[] picData = IOUtils.toByteArray(is);
                    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(picData);

                    if (picData != null && picData.length > 0) {
                        try {
                            //    真实文件名,DigestUtils.md5Hex方法可以根据文件byte[]生成唯一哈希!!!(节省服务器内存)
                            String realName = DigestUtils.md5Hex(picData) + suffix;
                            //    存库相对文件路径
                            relativeName = tmpPath + folderYMD + realName;
                            //    文件在图片服务器的路径前缀
                            String directory = UPLOAD_PATH + tmpPath + folderYMD;
                            String imageContextPath = FILE_PATH + UPLOAD_PATH + relativeName;
                            //  ftp上传文件
                            uploadFlag = ftpUtil.uploadInputStreamFile(byteArrayInputStream, realName, directory);
                            if (uploadFlag) {
                                return "{\"uploaded\":1,\"fileName\":\""+relativeName+"\",\"url\":\"" + imageContextPath + "\"}";
                            } else {
                                return "{\"uploaded\":0,\"error\":{\"message\":\"upload file is not success!\"}}";
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    return "{\"uploaded\":0,\"error\":{\"message\":\"upload file is not success!\"}}";
}

8.CKEditor不愧是大厂神作!说了这么多我们来看看最终效果吧![手动滑稽]



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值