共计 6128 个字符,预计需要花费 16 分钟才能阅读完成。
最近在写项目时,需要使用编辑器来编辑一个公司的描述信息,类似于这种效果:
在潘老师的指点下,一开始使用的 TinyMCE 这款编辑器,这也是一款很优秀的编辑器框架,但是后来提出了新的需求,在显示公司详情时,我们还需要能够插入公司的位置信息,类似于这样:
要实现这效果,我们需要调用百度地图的 api,潘老师还推荐了百度的一款编辑器:ueditor, 既然如此,既然如此,那就使用这款 ueditor 编辑器好了。
下载查看原型
我也不知道百度怎么想的,官网的演示既上传不了图片,也不能搜索地图,既然如此,只能把它下下来看看效果了。
之前写过 php,就选择了 php 版本下载,打开解压, 文件夹目录如下:
dialogs
: 弹出对话框对应的资源和 JS 文件lang
: 编辑器国际化显示的文件php 或 jsp 或 asp 或 net
: 涉及到服务器端操作的后台文件themes
: 样式图片和样式文件third-party
: 第三方插件(包括代码高亮,源码编辑等组件)ueditor.all.js
: 开发版代码合并的结果, 目录下所有文件的打包文件ueditor.all.min.js
: ueditor.all.js 文件的压缩版,建议在正式部署时采用ueditor.config.js
: 编辑器的配置文件,建议和编辑器实例化页面置于同一目录ueditor.parse.js
: 编辑的内容显示页面引用,会自动加载表格、列表、代码高亮等样式, 具体看内容展示文档ueditor.parse.min.js
: ueditor.parse.js 文件的压缩版,建议在内容展示页正式部署时采用
这里 php 就是它的后端了,我们有自己的后端,先不理会它,在这个目录下使用 http-serve
, 打开浏览器http://127.0.0.1:8080/
就能看到原型了:
点开地图,选择动态地图后点击确认,但是却没有效果,原因是因为动态地图的实现原理是用 <iframe>
标签加载上述 dialogs
文件夹下的 /map/show.html
,将经度和纬度通过 url 参数传给show.html
,它再调用百度地图 api 将位置信息显示出来,但是ueditor
编辑器为了防止 xss 攻击,把 <iframe>
标签过滤掉了。如果没有过滤掉,编辑器内容应该如下。
好在有解决方法,还记得在我们解压的文件夹下有一个 ueditor.config.js
文件,这就是编辑器的配置文件, 打开它在里边查找 whitList
这一项,这就是 xss 过滤的白名单,添加 iframe['frameborder','border','marginwidth','marginheight','width','height','src','id'],
这一项,我们的动态地图就不会被过滤掉了。
导入 angular
因为我们项目使用的是 angular,所以需要把 ueditor 导入到我们的项目来,将整个文件夹复制到 assets
下,并改名为ueditor
为了方便,我们使用 npm 下载 ngx-ueditor(可以看一下文档,挺少的)
npm install ngx-ueditor –save
在 AppModule 导入 UEditorModule 并配置:
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
LandingPageModule,
UEditorModule.forRoot({
js: [
`./assets/ueditor/ueditor.config.js`,
`./assets/ueditor/ueditor.all.js`,
],
// 默认前端配置项
options: {UEDITOR_HOME_URL: './assets/ueditor/'}
})
],
然后我们在 app.component.html
使用
<ueditor [(ngModel)]="html"></ueditor>
如果你看到了编辑器,那就说明成功的把 ueditor
导入到 angular
了。
配置后端
ueditor
的后台代码都有它自己的规范,与我们的后台代码规范不一样,既然如此,只能修改它的开发代码以适应我们的后端了。
后端的配置,主要配置图片,视频的上传和获取,我们只要保证我们后台的接口接收和返回的数据格式与它要求的一致就行了。
打开控制台:
报了一个 404 的错误,请求的路径为:http://localhost:8030/php/controller.php?action=config&&noCache=1567606213473
, 这个请求是用来请求后端的配置的,ueditor
编辑器在初始化时,就需要后端的配置来配置上传的信息。
点开 /php/config.json
文件,这就是我们要返回的后端配置。
为了方便,我们直接返回这个配置信息。观察上述控制台,报错的行数是在ueditor.all.js:8111
:
查看源代码发现它根据一个路径 (后边会修改这个) 请求后台的接口,并用返回来的 json
数据进行配置。所以在这里,直接把 json 数据返回就行了。
将 assets/ueditor/php/config.json
移动到 assets/ueditor/
下, 修改上述代码 configUrl
为:
var configUrl = 'assets/ueditor/config.json',
这时候我们就能成功使用图片上传的插件了。
接下来,我们还要配置后端上传的接口,首先修改根路径, 在 ueditor.config.js
里找到 serverUrl
这一项,可以看到它的默认值是:serverUrl: URL + "php/controller.php"
, 有关上传的所有功能,都会通过 http://localhost:8030/php/controller.php?action=xxxx
等方式进行上传,而 action
的名字就在后端配置 config.json
中,例如在 config.json
里的上传图片这一项:
{
/* 上传图片配置项 */
"imageActionName": "uploadimage", /* 执行上传图片的 action 名称 */
"imageFieldName": "upfile", /* 提交的图片表单名称 */
"imageMaxSize": 2048000, /* 上传大小限制,单位 B */
"imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
"imageCompressEnable": true, /* 是否压缩图片, 默认是 true */
"imageCompressBorder": 1600, /* 图片压缩最长边限制 */
"imageInsertAlign": "none", /* 插入的图片浮动方式 */
"imageUrlPrefix": "", /* 图片访问路径前缀 */
.....
}
ueditor
编辑器在一开始就要获取 config.json
文件的原因就是为了配置后端的上传接口,它会根据你在这里定义的配置来进行文件的上传.
首先,我们先修改 serverUrl
的值,改为你后台的地址,其次它的请求方法名是传递 action=XXX
参数,再由你后台获取这个参数进行判断,然后执行你需要的操作的,但是我们的后台接口一般都是在 url 上以 /action
来区分你要请求的方法,所以,还得改一下它的请求方法。
搜索getActionUrl
, 可以看到请求的接口地址都是从这里返回的,因此,我们只需要修改返回的格式就行了。
改为:
serverUrl = serverUrl + '/' + (actionName || '');
此时编写后台接口,我用的是 springboot:
@RestController
@RequestMapping("ueditor")
@Api(tags = "Ueditor 临时上传文件接口")
public class UeditorController {
@Autowired
AttachmentService attachmentService;
@ApiOperation(value = "上传图片类型的附件", notes = "上传图片类型的附件", nickname = "Attachment_uploadImage")
@PostMapping("/uploadImage")
@ResponseStatus(HttpStatus.CREATED)
public UeditorImage uploadImage(@RequestParam("file") MultipartFile[] submissions) {MultipartFile submission = submissions[0];
Attachment attachment = this.attachmentService.uploadImage(submission);
UeditorImage ueditorImage = new UeditorImage();
ueditorImage.setState("SUCCESS");
ueditorImage.setTitle(attachment.getSaveName());
ueditorImage.setOriginal(submission.getOriginalFilename());
ueditorImage.setUrl(attachment.getSavePath());
return ueditorImage;
}
}
// 需要返回此 json 数据 给 ueditor 显示
class UeditorImage {
private String state;
private String url;
private String title;
private String original;
public String getState() {return state;}
public void setState(String state) {this.state = state;}
public String getUrl() {return url;}
public void setUrl(String url) {this.url = url;}
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public String getOriginal() {return original;}
public void setOriginal(String original) {this.original = original;}
}
注意: PostMapping
必须要与 config.json
里的imageActionName
一致。@RequestParam("file")
参数名必须要与 imageFieldName
一致。
返回 json
数据要与百度要求的 json
数据一致,不然前端无法显示。
好了,此时就能成功的上传图片了。此时我们绑定的 ([ngmodel])=html,html
中存放的就是编辑框内容的 html 代码了,我们只要保存这个值到数据库,要显示详情的时候用 <div [innerhtml]="xxxx"></div>
就可以成功显示详情了。
注意,angular 的 innerhtml 也会过滤掉 iframe, 因此我们要使用 angular 内置方法来转换我们的描述文本,告诉 angular 这是安全的。
import {Component} from '@angular/core';
import {DomSanitizer} from '@angular/platform-browser';
@Component({
selector: 'yzpf-root',
template: '<div class="row col-md-6 offset-3"[innerHTML]="transform(html)">\n' +
'</div>\n',
styleUrls: ['./app.component.scss']
})
export class AppComponent {html = '<p><img src="attachment/image/2019731/bdf4e0a70bd90c650fd32ebdc675c24c.png"title="" alt="6a600c338744ebf803157a9adef9d72a6059a72a.png" width="534" height="306"/></p><p> 哔哩哔哩(英文名称:bilibili,简称 B 站)现为国内领先的年轻人文化社区,该网站于 2009 年 6 月 26 日创建,被粉丝们亲切的称为“B 站”。</p><p>B 站的特色是悬浮于视频上方的实时评论功能,爱好者称其为“弹幕”,这种独特的视频体验让基于互联网的弹幕能够超越时空限制,构建出一种奇妙的共时性的关系,形成一种虚拟的部落式观影氛围,让 B 站成为极具互动分享和二次创造的文化社区。B 站目前也是众多网络热门词汇的发源地之一。</p><p>2019 年 4 月 22 日,针对“后台源码泄露”一事,B 站在今晚已经做出回应,其表示,经内部紧急核查,确认该部分代码属于较老的历史版本 <span class="sup--normal" style="font-size: 12px; line-height: 0; position: relative; vertical-align: baseline; top: -0.5em; margin-left: 2px; color: rgb(51, 102, 204); cursor: pointer; padding: 0px 2px;"> [1]</span><a class="sup-anchor" style="color: rgb(19, 110, 194); position: relative; top: -50px; font-size: 0px; line-height: 0;"> </a> ;5 月 29 日,哔哩哔哩发布通知称,因弹幕系统技术升级,5 月 29 日起至 6 月 6 日网站将暂时关闭弹幕功能 </p><p><br/></p><p><br/></p><p> 位置:</p><p><iframe src="./assets/ueditor/dialogs/map/show.html#center=116.404,39.915&zoom=10&width=530&height=340&markers=116.404,39.915&markerStyles=l,A" frameborder="0" width="534" height="344"></iframe></p>';
title = 'platform';
constructor(private sanitizer: DomSanitizer) { }
transform(text: string) {return this.sanitizer.bypassSecurityTrustHtml(text);
}
}
好了,这样就能成功显示我们编辑的内容了,剩下的样式调整就行了。