效果:
前提:
实现:
1、引入vue-quill-editor
cnpm install vue-quill-editor
2、使用vue-quill-editor
template:
注意1:
此行为新加的标签,以此方式引用,简单又有页面效果!
注意2:
在上传视频、音频、图片时,用到了element上传文件组件
script:
import {
Quill,quillEditor
} from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 自定义字体大小
let Size = Quill.import('attributors/style/size')
Size.whitelist = ['10px', '12px', '14px', '16px', '18px', '20px', '30px']
Quill.register(Size, true)
// 自定义字体类型
var fonts = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif',
'宋体', '黑体']
var Font = Quill.import('formats/font')
Font.whitelist = fonts
Quill.register(Font, true)
//视频标签插入(样式保持宽度100%)
import Video from './video.js'
Quill.register(Video, true)
//音频标签插入
import Audio from './audio.js'
Quill.register(Audio, true)
export default {
components: {
quillEditor
},
data() {
return {
content: '',
editorOption: {
placeholder: "请输入", //文章初始化提示语
theme: "snow", // or 'bubble'
modules: {
toolbar: {
container: '#toolbar',
handlers: {
'image': function (value) {
if (value) {
// 触发input框选择图片文件
document.querySelector('.avatar-uploader-editor input').click()
} else {
this.quill.format('image', false);
}
},
'video': function (value) {
if (value) {
// 触发input框选择视频文件
document.querySelector('.avatar-uploader-editor-video input').click()
} else {
this.quill.format('video', false);
}
},
'audio': function (value) {
if (value) {
// 触发input框选择音频文件
document.querySelector('.avatar-uploader-editor-voice input').click()
} else {
this.quill.format('audio', false);
}
},
}
}
}
},
serverUrl: '/api/files/headUpload', //上传的图片服务器地址
}
},
methods: {
// 富文本图片上传成功
uploadSuccess(res,file) {
// console.log(res)
let quill = this.$refs.myQuillEditor.quill
// 如果上传成功
if (res.code == 0) {
// 获取光标所在位置
let length = quill.getSelection().index;
// 插入图片res.url为服务器返回的图片地址
quill.insertEmbed(length, 'image', res.data.url)
// 调整光标到最后
quill.setSelection(length + 1)
} else {
this.$message.error('图片插入失败')
}
},
//上传视频
uploadSuccessVideo(res,file) {
let quill = this.$refs.myQuillEditor.quill
// 如果上传成功
if (res.code == 0) {
// 获取光标所在位置
let length = quill.getSelection().index;
// 插入图片res.url为服务器返回的地址
quill.insertEmbed(length, 'video', res.data.url)
// 调整光标到最后
quill.setSelection(length + 1)
} else {
this.$message.error('视频插入失败')
}
},
//上传音频-处理很重要!!!!
uploadSuccessVoice(res,file) {
let quill = this.$refs.myQuillEditor.quill
// 如果上传成功
if (res.code == 0) {
// 获取光标所在位置
let length = quill.getSelection().index;
let BlockEmbed = Quill.import('blots/block/embed');
class AudioBlot extends BlockEmbed {
static create(value) {
let node = super.create();
node.setAttribute('src', res.data.url); //设置audio的src属性
node.setAttribute('controls', true); //设置audio的controls,否则他将不会显示
node.setAttribute('controlsList', 'nodownload'); //设置audio的下载功能为不能下载
node.setAttribute('id', 'voice'); //设置一个id
return node;
}
}
AudioBlot.blotName = 'audio';
AudioBlot.tagName = 'audio'; //自定义的标签为audio
Quill.register(AudioBlot);
// insertEmbed(index: Number(插入的位置), type: String(标签类型), value: any(参数,将传入到create的方法中去), source: String = 'api')
quill.insertEmbed(length, 'audio', res.data.url);
quill.setSelection(length + 1); //光标位置向后移动一位
} else {
this.$message.error('音频插入失败')
}
},
// 富文本图片/视频/音频上传失败
uploadError() {
this.$message.error('插入失败')
},
}
}
style:
.avatar-uploader-editor{
display: inline-block;
}
.avatar-uploader-editor-video{
display: inline-block;
}
.avatar-uploader-editor-voice{
display: inline-block;
}
引入资源:video.js
import { Quill } from 'vue-quill-editor'
// 源码中是import直接倒入,这里要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')
const ATTRIBUTES = ['height', 'width']
class Video extends BlockEmbed {
static create (value) {
const node = super.create(value)
// 添加video标签所需的属性
node.setAttribute('controls', 'controls') // 控制播放器
//删除原生video的控制条的下载或者全屏按钮的方法
//
//不用哪个在下面加上哪个
node.setAttribute('controlsList', 'nofullscreen') // 控制删除
node.setAttribute('type', 'video/mp4')
node.setAttribute('style', 'object-fit:fill;width: 100%;')
node.setAttribute('preload', 'auto') // auto - 当页面加载后载入整个视频 meta - 当页面加载后只载入元数据 none - 当页面加载后不载入视频
node.setAttribute('playsinline', 'true')
node.setAttribute('x-webkit-airplay', 'allow')
// node.setAttribute('x5-video-player-type', 'h5') // 启用H5播放器,是wechat安卓版特性
node.setAttribute('x5-video-orientation', 'portraint') // 竖屏播放 声明了h5才能使用 播放器支付的方向,landscape横屏,portraint竖屏,默认值为竖屏
node.setAttribute('x5-playsinline', 'true') // 兼容安卓 不全屏播放
node.setAttribute('x5-video-player-fullscreen', 'true') // 全屏设置,设置为 true 是防止横屏
node.setAttribute('src', this.sanitize(value))
return node
}
static formats (domNode) {
return ATTRIBUTES.reduce((formats, attribute) => {
if (domNode.hasAttribute(attribute)) {
formats[attribute] = domNode.getAttribute(attribute)
}
return formats
}, {})
}
static sanitize (url) {
return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
}
static value (domNode) {
return domNode.getAttribute('src')
}
format (name, value) {
if (ATTRIBUTES.indexOf(name) > -1) {
if (value) {
this.domNode.setAttribute(name, value)
} else {
this.domNode.removeAttribute(name)
}
} else {
super.format(name, value)
}
}
html () {
const { video } = this.value()
return `${video}`
}
}
Video.blotName = 'video' // 这里不用改,楼主不用iframe,直接替换掉原来,如果需要也可以保留原来的,这里用个新的blot
Video.className = 'ql-video'
Video.tagName = 'video' // 用video标签替换iframe
export default Video
audio.js
import { Quill } from 'vue-quill-editor'
// 源码中是import直接倒入,这里要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')
const ATTRIBUTES = ['height', 'width']
class audio extends BlockEmbed {
static create (value) {
const node = super.create(value)
// 添加audio标签所需的属性
node.setAttribute('controls', 'controls')
node.setAttribute('type', 'audio/mp4')
node.setAttribute('src', this.sanitize(value))
return node
}
static formats (domNode) {
return ATTRIBUTES.reduce((formats, attribute) => {
if (domNode.hasAttribute(attribute)) {
formats[attribute] = domNode.getAttribute(attribute)
}
return formats
}, {})
}
static sanitize (url) {
return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
}
static value (domNode) {
return domNode.getAttribute('src')
}
format (name, value) {
if (ATTRIBUTES.indexOf(name) > -1) {
if (value) {
this.domNode.setAttribute(name, value)
} else {
this.domNode.removeAttribute(name)
}
} else {
super.format(name, value)
}
}
html () {
const { audio } = this.value()
return `${audio}`
}
}
audio.blotName = 'audio' // 这里不用改,楼主不用iframe,直接替换掉原来,如果需要也可以保留原来的,这里用个新的blot
audio.className = 'ql-audio'
audio.tagName = 'audio' // 用audio标签替换iframe
export default audio
font.css(此文件为修改编辑器的样式,必引!)
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
content: "宋体";
font-family: "SimSun";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
content: "黑体";
font-family: "SimHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
content: "微软雅黑";
font-family: "Microsoft YaHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
content: "楷体";
font-family: "KaiTi";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
content: "仿宋";
font-family: "FangSong";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
content: "Arial";
font-family: "Arial";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
content: "Times New Roman";
font-family: "Times New Roman";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
content: "sans-serif";
font-family: "sans-serif";
}
.ql-font-SimSun {
font-family: "SimSun";
}
.ql-font-SimHei {
font-family: "SimHei";
}
.ql-font-Microsoft-YaHei {
font-family: "Microsoft YaHei";
}
.ql-font-KaiTi {
font-family: "KaiTi";
}
.ql-font-FangSong {
font-family: "FangSong";
}
.ql-font-Arial {
font-family: "Arial";
}
.ql-font-Times-New-Roman {
font-family: "Times New Roman";
}
.ql-font-sans-serif {
font-family: "sans-serif";
}
复制粘贴即可实现!调研N久,拿走不谢!