start
前言,总是要说点啥,哈哈。作为一个前端,也碰到了,需要使用富文本编辑器的需求了。经过两天时间的努力,终于把这个需求弄的差不多了,心里百感交集呀。不容易。哭一下 o(╥﹏╥)o 。写个文档记录一下自己的这两天的踩过的坑和收获。
1.富文本插件的选择
这个我就不逼逼赖赖了,看个人需求。目前我熟练的是
wangeditor
,其他的了解不多,看你自己选择。这里放个讲插件区别的 博客 自己看,或者自己百度都可以
这里放一下讲富文本区别比较靠谱的链接
https://panjiachen.github.io/vue-element-admin-site/zh/feature/component/rich-editor.html
- 我这里就选择
wangeditor
,我挑了很久,选这个,没其他原因,简洁,简单。(下面放效果图)
2.代码环境
-
Angular
:8.2.12 -
wangeditor
:3.1.1 -
ng-zorro-antd
: 8.5.2
ps
(上面三个,好想用的人不多,所以同时包含上面三个的博客,文章真的好少,百度都难找,心累)
3.啰嗦几句
-
wangeditor
官网并没有直接给出在Angular中的使用案例,但是文档还是很实在的,可以多看看http://www.wangeditor.com/
- 话不多说,直接开始,不要慌,很简单。
4.正式使用
-
创建项目
// 创建一个项目 ng new mydemo // Would you like to add Angular routing? No // 不开启路由N //Which stylesheet format would you like to use? CSS //使用css Y
-
创建组件
//1.进入到我们创建的项目目录中 cd mydemo //2. 把app.component.html 文件清空 //3.创建组件(我这里偷懒了,就直接app文件下创建了) ng g c home //4.找到 home.component.ts》@Component》selector》app-home (获取到我们这个组件的组件名) //5.
写到app.component.html中 (默认我们ng g c home 就直接把组件在app.modul.ts中声明了) //6. ng serve 看一下 //7.停止服务 ctrl+c
-
下载
wangeditor
npm i wangeditor
-
home.component.ts
之后引入我们下好的文件import * as wangEditor from '../../../node_modules/wangeditor/release/wangEditor.js'; //'../../../node_modules/wangeditor/release/wangEditor.js'这个路径不是固定的 看你创建的组件文件路径 应该比较好找 自己../ 慢慢找 vscode有提示
-
home.component.html
写html
代码{{defaultMessage}}
-
home.component.ts
中 初始化一下我们的插件editor: any defaultMessage = '默认值' constructor() { } ngOnInit() { this.editor = new wangEditor("#editorMenu", "#editor") this.editor.create() }
ng serve
运行一下 基本 ok样式什么的 就自己设置吧,
-
完整的demo代码
home.component.ts
import { Component, OnInit } from '@angular/core'; import * as wangEditor from '../../../node_modules/wangeditor/release/wangEditor.js'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent implements OnInit { editor: any defaultMessage = '默认值' showhtmlcon = '' constructor() { } ngOnInit() { this.editor = new wangEditor("#editorMenu", "#editor") this.setEditorConfig() this.editor.create() } // 获取编辑器内容,带html showhtml() { this.showhtmlcon = this.editor.txt.html(); } // 设置富文本编辑器 setEditorConfig() { // 菜单展示项配置 this.editor.customConfig.menus = this.getMenuConfig(); // 使用 base64 保存图片 this.editor.customConfig.uploadImgShowBase64 = true; // 自定义配置颜色(字体颜色、背景色) this.editor.customConfig.colors = this.getColorConfig(); } // 设置可选颜色 getColorConfig(): string[] { return [ '#ffffff', '#000000', '#eeece0', '#1c487f', '#4d80bf', '#c24f4a', '#8baa4a', '#7b5ba1', '#46acc8', '#f9963b', '#0076B8', '#E2C08D', '#8EE153', '#B6001F' ]; } // 获取显示菜单项 getMenuConfig(): string[] { return [ 'bold', // 粗体 'italic', // 斜体 'underline', // 下划线 'head', // 标题 'fontName', // 字体 'fontSize', // 字号 'strikeThrough', // 删除线 'foreColor', // 文字颜色 'backColor', // 背景颜色 'link', // 插入链接 'list', // 列表 'justify', // 对齐方式 'quote', // 引用 'table', // 表格 'image', // 插入图片 // 'video', // 插入视频 'code', // 插入代码 'undo', // 撤销 'redo' // 重复 ]; } }
home.component.html
{{defaultMessage}}
样式自己写,特殊的地方,百度一下吧
5.然后呢?
- 上面基本的就可以使用了,可以直接复制粘贴,但是我的需求不仅仅是这样
- 将富文本插件放在
ng zorro
(UI
框架中)??
6.问题一
- 我在将富文本插件放到
ng zorro
对话中的时候,哇,加载不出来,放在页面中是可以正常显示的。
我思考了很多原因,第一个思路,是不是初始化的问题?
- 初始化的代码:
this.editor = new wangEditor("#editorMenu", "#editor")
this.editor.create()
-
尝试着将代码,放在,对话框打开的事件中 去初始化
//对话框打开的事件中 当对话框显示之后,再去初始化 showModal(): void { this.isVisible = true; this.editor = new wangEditor("#editorMenu", "#editor") this.editor.create() }
第二个思路,是不是样式出了问题?
- 尝试着去 查看对话框的
z-index
,结果并不解决问题 - 给元素设置好宽高,看是不是因为宽高的原因
第三个思路,要是实在用不了了,我自己手写一个对话框出来,先实现效果再说
- 理论上是没有问题的
- 但是由于已经用了
ui
框架了 再去重置样式非常麻烦。
第四个思路,可能ng zorro
和 wangEditor
有些地方有冲突,换个插件算了
- 重新弄一个效率太低了,不开心,花时间弄了好久,结果失败在这里了
第五个思路,找好兄弟问问,说不定,他有经验
- 还是兄弟靠谱。笑一下
- 经过很仔细的检查,基本的东西都很简单,这东西没有想象中的复杂。最后还是觉得,应该是初始化的地方有问题。他叫我试一下,添加一个定时器,来个2秒延迟,会咋样
showModal(): void {
this.isVisible = true;
setInterval(()=>{
this.editor = new wangEditor("#editorMenu", "#editor")
this.editor.create()
},2000)
}
- 后来理解到的是,要等到对话框加载完成再去初始化才能成功
- 初始化成功(但是用定时器去做,并不友好,用户体验还是要考虑的,咋整?)
- 对话框的
API
有一个方法:nzAfterOpen
(对话框打开后的回调) - 三个小时 终于算完美的解决问题了。
7.问题2
我自己实验的时候,打卡关闭对话框,会重复的去初始化富文本编辑框,这样肯定不行的,咋整?
-
官方解释
-
默认关闭后状态不会自动清空, 如果希望每次打开都是新内容,请采用NzModalService
服务方式创建对话框(当以服务方式创建时,默认会监听nzAfterClose
并销毁对话框)。通过
NzModalService
服务方式创建的对话框需要自行管理其生命周期。比如你在页面路由切换时,服务方式创建的对话框并不会被销毁,你需要使用对话框引用来手动销毁(NzModalRef.close()
或NzModalRef.destroy()
)。
8.问题3
Base64
存储图片放在一个string中,还是太大了 ,当我编辑了很多的图片的时候,上传,后台数据库就报错了,没办法,继续优化一下,将图片上传到服务器,然后获取到图片的url
,存储在string中。上代码
this.editor.customConfig.menus = this.getMenuConfig();
// 使用 base64 保存图片 (BASE64文件过大,暂时关闭)
// this.editor.customConfig.uploadImgShowBase64 = true;
// 自定义配置颜色(字体颜色、背景色)
this.editor.customConfig.colors = this.getColorConfig();
// ***设置富文本编辑器上传图片配置***
// 开启图片上传至服务器
this.editor.customConfig.uploadImgServer = '/upload'
// 限制图片大小为3M以下
this.editor.customConfig.uploadImgMaxSize = 3 * 1024 * 1024
/*
自定义图片上传事件
参数1 :files 是 input 中选中的文件列表
参数2 :insert 是获取图片 url 后,插入到编辑器的方法
*/
this.editor.customConfig.customUploadImg = (files, insert) => {
// 限制一次最多上传 1 张图片
if (files.length !== 1) {
this.messageService.showErrorMessage('单次只能上传一个图片')
return
}
// 下面的代码就是去根据自己的需求请求数据
// 注意这两个参数 参数1 :files 是 input 中选中的文件列表
// 参数2 :insert 是获取图片 url 后,插入到编辑器的方法
let formData = new FormData();
formData.append('file', files[0] as any);
this.service.saveAttachment(formData).subscribe(res => {
if(res.code =='ok'){
insert(res.data.viewUrl)
this.messageService.showInfoMessage('上传成功')
}else{
this.messageService.showErrorMessage(res.message)
}
})
}
9.最终效果
end
经过5个小时,终于完成了,写点啥,纪念一下,以后写代码还是要考虑一下DOM渲染的顺序,切记。还是太菜啊,加油啦。