<!-- 默认使用:-->
<quill-editor [(ngModel)]="content"></quill-editor>
<div style="height: 40px;"></div>
<!-- 自定义使用:-->
<quill-editor [(ngModel)]="content">
<div quill-editor-toolbar>
<span class="ql-formats">
<button class="ql-bold" [title]="'Bold'"></button>
<button type="button" class="ql-italic"></button>
<button type="button" class="ql-underline"></button>
<button type="button" class="ql-strike ql-active"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-blockquote"></button>
<button type="button" class="ql-code-block"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-header" value="1"></button>
<button type="button" class="ql-header" value="2"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-list" value="ordered"></button>
<button type="button" class="ql-list" value="bullet"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-script" value="sub"></button>
<button type="button" class="ql-script" value="super"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-indent" value="-1"></button>
<button type="button" class="ql-indent" value="+1"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-direction" value="rtl"></button>
</span>
<!-- <span class="ql-formats">
<span class="ql-size ql-picker ql-expanded">
<span class="ql-picker-label" tabindex="0" role="button" aria-expanded="true" aria-controls="ql-picker-options-0"></span>
<span class="ql-picker-options" aria-hidden="false" tabindex="-1" id="ql-picker-options-0">
<span tabindex="0" role="button" class="ql-picker-item" data-value="small"></span>
<span tabindex="0" role="button" class="ql-picker-item ql-selected"></span>
<span tabindex="0" role="button" class="ql-picker-item" data-value="large"></span>
<span tabindex="0" role="button" class="ql-picker-item" data-value="huge"></span>
</span>
</span>
<select class="ql-size" style="display: none;">
<option value="small"></option>
<option selected="selected"></option>
<option value="large"></option>
<option value="huge"></option>
</select>
</span> -->
<span class="ql-formats">
<button type="button" class="ql-link"></button>
<button type="button" (click)="imgFun()">
<svg viewBox="0 0 18 18">
<rect class="ql-stroke" height="10" width="12" x="3" y="4"></rect>
<circle class="ql-fill" cx="6" cy="7" r="1"></circle>
<polyline class="ql-even ql-fill" points="5 12 5 11 7 9 8 10 11 7 13 9 13 12 5 12"></polyline>
</svg>
</button>
<button type="button" (click)="videoFun()">
<svg viewBox="0 0 18 18">
<rect class="ql-stroke" height="12" width="12" x="3" y="3"></rect>
<rect class="ql-fill" height="12" width="1" x="5" y="3"></rect>
<rect class="ql-fill" height="12" width="1" x="12" y="3"></rect>
<rect class="ql-fill" height="2" width="8" x="5" y="8"></rect>
<rect class="ql-fill" height="1" width="3" x="3" y="5"></rect>
<rect class="ql-fill" height="1" width="3" x="3" y="7"></rect>
<rect class="ql-fill" height="1" width="3" x="3" y="10"></rect>
<rect class="ql-fill" height="1" width="3" x="3" y="12"></rect>
<rect class="ql-fill" height="1" width="3" x="12" y="5"></rect>
<rect class="ql-fill" height="1" width="3" x="12" y="7"></rect>
<rect class="ql-fill" height="1" width="3" x="12" y="10"></rect>
<rect class="ql-fill" height="1" width="3" x="12" y="12"></rect>
</svg>
</button>
</span>
<span class="ql-formats">
<select class="ql-align" [title]="'Aligment'">
<option selected></option>
<option value="center"></option>
<option value="right"></option>
<option value="justify"></option>
</select>
</span>
</div>
<input type="file" #fileUploadVideo>
<input type="file" #fileUploadImg>
</quill-editor>
<button (click)="getData()" id="btn">获取数据</button>
rich-text.component.ts
实现思路:将富文本中的图片上传、视频上传上面的按钮实现自定义,即删除class属性,然后自定义点击事件,在富文本中添加对应的input file表单元素。然后通过点击图片、视频图标按钮,调用input选择文件的弹框。
选择文件之后上传到服务器,然后服务器返回对应的链接地址,然后将地址插入到富文本中即可。
图片和视频的上传方式都试通过base64上传:
import { Component, OnInit, ViewChild } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
@Component({
selector: 'app-rich-text',
templateUrl: './rich-text.component.html',
styleUrls: ['./rich-text.component.css']
})
export class RichTextComponent implements OnInit {
@ViewChild('fileUploadVideo') fileUploadVideo: any;
@ViewChild('fileUploadImg') fileUploadImg: any;
content: any = '';
public api = 'http://192.168.1.112:8013/ActionApi/File/UploadHttpImage';
httpOptions = {
headers: new HttpHeaders().set('Content-Type', 'application/json').set('Content-Type', 'application/x-www-form-urlencoded')
};
constructor(public http: HttpClient) { }
ngOnInit() {}
getData() {
console.log(this.content);
}
// 上传视频
videoFun() {
const that = this;
// 调用弹框
this.fileUploadVideo.nativeElement.click();
this.fileUploadVideo.nativeElement.onchange = function() {
const filereader = new FileReader();
const fileType = this.files[0].type; // 获取文件类型
if (!/video\/\w+/.test(fileType)) {
alert('看清楚,这个需要视频!');
return false;
}
if (this.files[0]) {
if (this.files[0].size / 1024 / 1024 > 100) {
alert('视频上传大小不要超过100MB, 请重新上传!');
return;
}
}
const videoName = this.files[0].name;
filereader.readAsDataURL(this.files[0]); // 将文件以Data URL形式读入页面
filereader.onload = () => {
const result = filereader.result;
if (result) {
// ajax数据请求
const params = `Base64Video=${result}&Base64VideoName=${videoName}`;
that.http.post(that.api, params, that.httpOptions).subscribe((data: any) => {
console.log(data);
if (data.IsSucceed) {
const video = `<iframe src="${data.Data}" width="60%" height="200" align="center"></iframe>`; // 此处必须是iframe,不支持video标签
that.content += video;
} else {
alert('上传失败,请重新上传');
}
});
}
};
};
}
// 图片上传
imgFun() {
const that = this;
// 调用弹框
this.fileUploadImg.nativeElement.click();
this.fileUploadImg.nativeElement.onchange = function() {
const filereader = new FileReader();
const file = this.files[0]; // 获取文件类型
if (!/image\/\w+/.test(file.type)) {
alert('看清楚,这个需要图片!');
return false;
}
if (this.files[0]) {
if (this.files[0].size / 1024 / 1024 > 2) {
alert('图片上传大小不要超过2MB, 请重新上传!');
return;
}
}
const imgName = file.name;
filereader.readAsDataURL(file);
filereader.onload = () => {
const result = filereader.result;
if (result) {
// ajax数据请求
const params = `Base64Image=${result}&Base64ImageName=${imgName}`;
console.log(result);
that.http.post(that.api, params, that.httpOptions).subscribe((data: any) => {
console.log(data);
if (data.IsSucceed) {
const img = `<img src=${data.Data} />`; // 此处必须是写死的动态值,不能动态创建img标签
that.content += img;
} else {
alert('上传失败,请重新上传');
}
});
}
};
};
}
}
前台将图片视频转成base64通过post提交到后台之后,会出现如下的错误:不同的不同不同的错误,比如:参数无效,长度溢出等等。
核心原因:base64的数据传到后台之后会把json数据中的base64数据中的+号变成空格,导致的问题。
解决方法:编码问题
第一种:前端解决(未尝试)
'+' 字符在js传到后台的时候 都会被转义为' ' 的,所以可以将json字符串进行Base64转码之后再传到后台,安全性高一点,需要导入base64.js包代码如下:
var jsonStr = JSON.stringify(json)
var base = new Base64();
var jsonbase = base.encode(jsonStr)
//这样就把json数据转码成为了base64字符串,将这个字符串做参数传到后台就行了,就避免了'+'被转义为' '
第二种:后端解决
后端在转码的过程中设置和前端统一的编码格式,将所有的空格 ' ' 转成 +即可。
如果出现转码问题,还有就是base64转码的过程中,如果位数不够,后面的需要=补齐。
在视频上传成功之后,正确的视频地址却无法访问,需要单独在IIS里面设置一下格式即可访问。