vue-quill-editor
安装
npm install vue-quill-editor -S
使用
.....
<quill-editor
style="padding-left: 0;padding-top: .0px;margin-top: 30px;"
ref="editorRef"
v-model="params.content" class="ql-editor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
/>
......
import { quillEditor } from 'vue-quill-editor'
// 上传至oss
import { uploadOss } from '@/api/uploadOss'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
var sizes = [false, "16px", "18px", "20px", "22px", "26px", "28px", "30px"];
......
components: {
quillEditor
},
data(){
return{
editorOption: {
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
['blockquote', 'code-block'], // 引用 代码块
[{ header: 1 }, { header: 2 }], // 1、2 级标题
[{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
[{ script: 'sub' }, { script: 'super' }], // 上标/下标
[{ indent: '-1' }, { indent: '+1' }], // 缩进
[{ direction: 'rtl' }], // 文本方向
[{ size: sizes }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6,false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
// [{ font: ['songti'] }], // 字体种类
[{ align: [] }], // 对齐方式
['clean'], // 清除文本格式
['image', 'video'] // 链接、图片、视频
],
handlers: {
image: this.imageUploadOss
}
},
placeholder: '请输入正文'
},
}
}
....
methods:{
// 失去焦点事件
onEditorBlur(quill) {
},
// 获得焦点事件
onEditorFocus(quill) {
},
// 准备富文本编辑器
onEditorReady(quill) {
},
// 内容改变事件
onEditorChange({ quill, html, text }) {
this.params.content = html
},
}
图片拖拽及图片缩放
安装
npm i quill-image-drop-module -S
npm i quill-image-resize-module -S
使用
1. 新增样式文件.css
目录: assets/styles/quillEditor.css
.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";
}
/* 字号设置 */
/* 默认字号 */
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
content: "14px";
font-size: 14px;
}
.ql-size-14px {
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
content: "16px";
font-size: 16px;
}
.ql-size-16px {
font-size: 16px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before {
content: "18px";
font-size: 18px;
}
.ql-size-18px {
font-size: 18px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
content: "20px";
font-size: 20px;
}
.ql-size-20px {
font-size: 20px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="22px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="22px"]::before {
content: "22px";
font-size: 22px;
}
.ql-size-22px {
font-size: 22px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="26px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="26px"]::before {
content: "26px";
font-size: 26px;
}
.ql-size-26px {
font-size: 26px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="28px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="28px"]::before {
content: "28px";
font-size: 28px;
}
.ql-size-28px {
font-size: 28px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="30px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="30px"]::before {
content: "30px";
font-size: 30px;
}
.ql-size-30px {
font-size: 30px;
}
2.配置及使用
// vue.config.js 中增加
const webpack = require('webpack');
new webpack.ProvidePlugin({
'window.Quill': 'quill/dist/quill.js',
'Quill': 'quill/dist/quill.js'
})
// 新建的css文件的保存位置,如不同,需要修改
import "@/assets/styles/quillEditor.css";
import imageResize from 'quill-image-resize-module'
Quill.register('modules/imageResize', imageResize )
import { ImageDrop } from 'quill-image-drop-module'
Quill.register('modules/imageDrop', ImageDrop)
// 调整字体大小选项
var sizes = [false, "16px", "18px", "20px", "22px", "26px", "28px", "30px"];
var Size = Quill.import("formats/size");
Size.whitelist = sizes;
Quill.register(Size, true)
// toobar同级增加,如下图
imageDrop: true, // 拖动加载图片组件。
imageResize: { //调整大小组件。
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
}
视图效果
完整代码
<template>
<div class="app-container" style="min-height: calc(100vh - 50px);">
<el-tabs v-model="params.type" @tab-click="tabClick">
<el-tab-pane label="医院简介" name="BRIEF" />
<el-tab-pane label="楼宇分布" name="BUILDING" />
<el-tab-pane label="科室分布" name="DEPARTMENT" />
</el-tabs>
<div style="position: relative;margin-top: 10px;">
<span style="display: block;position: absolute;top: 10px;padding-left: 18px;box-sizing: border-box;">
<a style="font-size: 40px;color: red;position: absolute;left: 0;top: -5px;">*</a>介绍内容
</span>
</div>
<quill-editor
style="padding-left: 0;padding-top: .0px;margin-top: 30px;"
ref="editorRef"
v-model="params.content" class="ql-editor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
/>
<div style="width: 100%;text-align: center;">
<el-button style="width: 100px;" icon="el-icon-delete" @click="() => params.content = ''">清空</el-button>
<el-button style="width: 100px;" icon="el-icon-tickets" :loading="loading" type="primary" @click="saveContent()"
v-if="checkPer(['admin', 'unicameral:introduce:edit'])"
>保存</el-button>
</div>
</div>
</template>
<script>
import { Notification, Loading } from 'element-ui'
import { quillEditor } from 'vue-quill-editor'
import { uploadOss } from '@/api/uploadOss'
import * as introduceService from '@/api/unicameral/introduceService'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 新建的css文件的保存位置,如不同,需要修改
import "@/assets/styles/quillEditor.css";
import imageResize from 'quill-image-resize-module'
Quill.register('modules/imageResize', imageResize )
import { ImageDrop } from 'quill-image-drop-module'
Quill.register('modules/imageDrop', ImageDrop)
var sizes = [false, "16px", "18px", "20px", "22px", "26px", "28px", "30px"];
var Size = Quill.import("formats/size");
Size.whitelist = sizes;
Quill.register(Size, true)
export default {
name: 'UnicameralIntroduce',
components: {
quillEditor
},
data() {
return {
params: {
hosId: '',
type: 'BRIEF',
content: ''
},
loading: false,
editorOption: {
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
['blockquote', 'code-block'], // 引用 代码块
[{ header: 1 }, { header: 2 }], // 1、2 级标题
[{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
[{ script: 'sub' }, { script: 'super' }], // 上标/下标
[{ indent: '-1' }, { indent: '+1' }], // 缩进
[{ direction: 'rtl' }], // 文本方向
[{ size: sizes }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6,false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
// [{ font: ['songti'] }], // 字体种类
[{ align: [] }], // 对齐方式
['clean'], // 清除文本格式
['image', 'video'] // 链接、图片、视频
],
handlers: {
image: this.imageUploadOss
}
},
imageDrop: true, // 拖动加载图片组件。
imageResize: { //调整大小组件。
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
}
},
placeholder: '请输入正文'
},
}
},
mounted() {
this.getContent()
},
methods: {
tabClick() {
// 清空内容
this.params.content = ''
this.getContent()
},
// 失去焦点事件
onEditorBlur(quill) {
},
// 获得焦点事件
onEditorFocus(quill) {
},
// 准备富文本编辑器
onEditorReady(quill) {
},
// 内容改变事件
onEditorChange({ quill, html, text }) {
this.params.content = html
},
getContent() {
const options = {
fullscreen: false,
target: document.querySelector('.platform-wrap')
}
const loadingInstance = Loading.service(options)
this.params.content = ""
introduceService.getIntroduce(this.params).then(res => {
if(res.status == '200'){
this.params.content = res.result
}
}).finally(() => loadingInstance.close())
},
saveContent() {
this.loading = true;
introduceService.saveIntroduce(this.params).then(res => {
if(res.status == '200'){
Notification.success('操作成功')
}else {
Notification.error('操作成功')
}
}).finally(() => this.loading = false)
},
imageUploadOss() {
const { quill } = this.$refs.editorRef
let fileInput = quill.container.querySelector('input.ql-image[type=file]')
if (fileInput === null) {
fileInput = document.createElement('input')
fileInput.setAttribute('type', 'file')
// 设置图片参数名
fileInput.setAttribute('name', 'file')
// 可设置上传图片的格式
fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon')
fileInput.classList.add('ql-image')
// 监听选择文件
fileInput.addEventListener('change', function() {
const formData = new FormData()
formData.append('file', fileInput.files[0])
formData.append('imageUrl', 'hos/unicameral-introduce/')
uploadOss(formData).then(res => {
if (res.status === '200') {
const length = quill.getSelection(true).index
quill.insertEmbed(length, 'image', process.env.VUE_APP_DOMAIN_STATIC + res.result)
quill.setSelection(length + 1)
}
}).catch(err => {
console.log(err)
Notification.error('图片上传失败')
})
})
}
fileInput.click()
},
imageUpload() {
// var self = this
const { quill } = this.$refs.editorRef
let fileInput = quill.container.querySelector('input.ql-image[type=file]')
if (fileInput === null) {
fileInput = document.createElement('input')
fileInput.setAttribute('type', 'file')
// 设置图片参数名
fileInput.setAttribute('name', 'file')
// 可设置上传图片的格式
fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon')
fileInput.classList.add('ql-image')
// 监听选择文件
fileInput.addEventListener('change', () => {
const formData = new FormData()
formData.append('file', fileInput.files[0])
// let length = self.quill.getSelection(true).index;
// quill.insertEmbed(length, 'image', data.data.data.url);
// quill.insertEmbed(length, 'title', data.data.data.fileName);
// quill.setSelection(length + 1)
})
quill.container.appendChild(fileInput)
}
fileInput.click()
}
}
}
</script>
<style scoped lang="scss">
.codeJs {
font-size: 11pt;
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
}
::v-deep .el-tabs {
margin-bottom: 0px;
}
// ::v-deep .ql-editor{
// height:260px;
// }
</style>
<style>
.CodeMirror-hints{
z-index: 8888!important;
}
</style>