这个编辑器,可支持上传图片、视频链接或视频,
插入视频功能做了一下改进;
图片和视频是上传到阿里云oss,拿到oss地址后 插到编辑器里回显的;
注意:
上传视频后,视频回显标签是用iframe包裹的,在手机端可能会有显示问题,显示页面获取接口video标签替换 iframe 标签:
this.details.articleContent=this.details.articleContent.replace('<iframe', `<video controls="" autoplay="" style="width: 100%;"`).replace('</iframe>', '</video>')
安装
npm install vue-quill-editor --save
在main.js 引入
import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css'
// 页面引入
import { quillEditor,Quill } from 'vue-quill-editor'
import Video from '../../../utils/video'
Quill.register(Video, true)
// 配置项
editorOption: {
modules:{
toolbar:{
container: [
['bold', 'italic', 'underline', 'strike'], //加粗,斜体,下划线,删除线
[{ 'header': 1 }, { 'header': 2}], // 标题,键值对的形式;1、2表示字体大小
[{'list': 'ordered'}, {'list': 'bullet'}], //列表
[{ 'script': 'sub'}, {'script': 'super' }], // 上下标
[{ 'indent': '-1'}, {'indent': '+1'}], // 缩进
[{'direction': 'rtl' }], // 文本方向
['clean'], //清除字体样式
['image', 'video'] //上传图片、上传视频
],
handlers: {
'video':(val)=>{
// 覆盖默认的上传视频
this.onVideo();
},
'image':(value)=>{
// 覆盖默认的图片上传
// 获取光标所在的位置
var range = this.$refs.myQuillEditor.quill.getSelection();
if (range == null) {
this.indexVideo = 0;
} else {
this.indexVideo = range.index;
}
// 点击隐藏的上传表单
if (value) {
document.querySelector('.avataruploaderTip input').click()
} else {
this.quill.format('image', false)
}
}
}
}
},
placeholder:'请输入'
},
// 相关变量
indexVideo:0,
videoUrl:'',
videoTab:{
tabUrl:true,
tabUpd:false
},
videoProgress:false,
// 声明组件
components: {
quillEditor
},
// 富文本相关
onVideo(){
this.videoFlag = true;
//当编辑器中没有输入文本时,这里获取到的 range 为 null 获取光标位置
var range = this.$refs.myQuillEditor.quill.getSelection();
if (range == null) {
this.indexVideo = 0;
} else {
this.indexVideo = range.index;
}
},
onVideoTab(val){ // 链接与视频上传 tab切换
if(val == 1){
this.videoTab.tabUrl = true;
this.videoTab.tabUpd = false;
}else{
this.videoTab.tabUpd = true;
this.videoTab.tabUrl = false;
}
},
// 上传之前请求后台接口 拿上传oss需要的参数
async beforeAvatarUploadTwo(file) {
let that = this
this.uillUpdateImg = true
this.videoFlag = false
await http.get("/photo/fetchStsCredentials", {})
.then(function (res) {
that.accessKeyId= res.data.accessKey;
that.accessKeySecret = res.data.accessKeySecret;
that.securityToken = res.data.securityToken
})
.catch(function (err) {
console.log("连接失败" + err);
});
},
//上传文件到阿里云,返回数据,拿到url oss地址
uploadAvatarTwo(options) {
let that = this
let client = new OSS({
region: "oss-cn-qingdao",
accessKeyId: that.accessKeyId1,
accessKeySecret: that.accessKeySecret1,
stsToken: that.securityToken,
bucket: "medai",
});
let file = options.file; // 拿到 file
let fileName = file.name.substr(0, file.name.lastIndexOf('.'))
let date = new Date().getTime()
let fileNames = `${date}_${fileName}`
client.put(fileNames, file,).then(res => {
if (res.res.statusCode === 200) {
console.log(res);
options.onSuccess(res)
} else {
options.onError("上传失败")
}
})
},
// 上传视频成功回调
upVideoUrl(res) {
console.log(res);
res.url?this.videoUrl=res.url: this.uillUpdateImg = true
if (this.videoUrl) {
// 获取富文本
let quill = this.$refs.content.quill
// 在光标所在位置 插入视频
quill.insertEmbed(this.indexVideo, 'video', this.videoUrl)
quill.setSelection(this.indexVideo + 1)
this.videoFlag = false;
this.videoUrl=''
} else {
this.$message({
message: '请填写视频链接',
type: 'warning'
});
}
this.uillUpdateImg = false
},
// 上传图片链接
upVideoUrl(){
if(this.videoUrl){
let quill = this.$refs.myQuillEditor.quill
quill.insertEmbed(this.indexVideo,'video', this.videoUrl)
quill.setSelection(this.indexVideo + 1)
this.videoFlag = false;
}else{
this.$message({
message: '请填写视频链接',
type: 'warning'
});
}
},
// 图片上传
uploadImgTip(param){
const formData = new FormData()
formData.append('file', param.file)
fetchImg(formData).then(response => {
let url = response.imgUrl
let quill = this.$refs.myQuillEditor.quill
// 插入图片链接
quill.insertEmbed(this.indexVideo, 'image', url)
quill.setSelection(this.indexVideo + 1)
});
},
}
// 隐藏图片上传表单 HTML
<el-upload
class="avataruploaderTip"
ref="uploadtip"
:limit="999"
action="#"
:show-file-list="false"
:http-request="uploadImgTip"
>
</el-upload>
// 视频上传弹出框
<el-dialog
title="视频上传"
:visible.sync="videoFlag"
:close-on-click-modal="false"
class="editerV"
width="500px">
<div class="editerVideo">
<div class="editerVideo_title">
<div :class="['editerVideo_title_item',videoTab.tabUrl?'editerVideo_title_act':''] " @click="onVideoTab(1)">添加链接</div>
<div :class="['editerVideo_title_item',videoTab.tabUpd?'editerVideo_title_act':''] " @click="onVideoTab(2)">上传视频</div>
</div>
<div class="editerVideo_main">
<div class="editerVideo_main_url" v-if="videoTab.tabUrl">
<div>视频地址:</div>
<el-input size="small" v-model="videoUrl" style="width:300px"></el-input>
<el-button type="primary" style=" margin-left:10px; height:30px" @click="upVideoUrl" size="small" >添加</el-button>
</div>
<div v-if="videoTab.tabUpd">
<div v-if="videoProgress" class="videoProgress">视频上传中,请耐心等待!</div>
<el-upload
v-else
class="avatar-uploader_video"
:limit=1
action="#"
:show-file-list="false"
:http-request="uploadAvatarTwo"
:before-upload="beforeAvatarUploadTwo"
:on-success="upVideoUrl"
>
<i class="el-icon-plus avatar-uploader-videoiocn"></i>
</el-upload>
</div>
</div>
</div>
</el-dialog>
// 视频上传组件
.editerV /deep/ .el-dialog__body{
padding: 0px 20px 20px 20px;
}
.editerVideo{
width: 100%;
}
.editerVideo_title{
display: flex;
height: 30px;
line-height: 30px;
width: 100%;
color: #1f2f3d;
font-weight: bold;
justify-content: flex-start;
border-bottom: 2px solid #DCDFE6;
}
.editerVideo_title_act{
color: #409eff;
border-bottom: 2px solid #409eff;
margin-bottom: -2px;
}
.editerVideo_title_item{
margin-right: 10px;
}
.editerVideo_main{
width: 100%;
height: 120px;
}
.editerVideo_main_url{
width: 100%;
height: 200px;
line-height: 30px;
display: flex;
flex-direction: row;
justify-content:flex-start;
margin-top: 35px;
}
.avatar-uploader_video{
width: 100px;
height: 100px;
border: 1px solid #D9D9D9;
display: flex;
justify-content: center;
align-items: center;
margin-top: 30px;
}
.avatar-uploader-videoiocn {
font-size: 28px;
color: #D9D9D9;
line-height: 90px;
text-align: center;
}
.videoProgress{
margin-top: 30px;
}
.quillWidthmain{
width: 800px;
height:320px;
}
.quillWidth{
width:800px;
height:270px;
}