This commit is contained in:
clay
2022-01-09 13:42:41 +08:00
parent 95eb461aab
commit 0e62e7e3da
6 changed files with 415 additions and 165 deletions

View File

@@ -66,7 +66,8 @@
"vue-router": "3.0.2", "vue-router": "3.0.2",
"vue-splitpane": "1.0.4", "vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0", "vuedraggable": "2.20.0",
"vuex": "3.1.0" "vuex": "3.1.0",
"wangeditor": "^4.7.11"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "4.4.4", "@vue/cli-plugin-babel": "4.4.4",

View File

@@ -1,20 +1,16 @@
<template> <template>
<div class="editor" ref="editor" :style="styles"></div> <div class="editor" :style="styles" ref="editor"></div>
</template> </template>
<script> <script>
import Quill from "quill"; import Editor from 'wangeditor'
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
export default { export default {
name: "Editor", name: "Editor",
props: { props: {
/* 编辑器的内容 */ /* 编辑器的内容 */
value: { value: {
type: String, type: String,
default: "", default: ''
}, },
/* 高度 */ /* 高度 */
height: { height: {
@@ -26,36 +22,17 @@ export default {
type: Number, type: Number,
default: null, default: null,
}, },
meanArray: {
// 自定义菜单
type: Array,
default: null
}
}, },
data() { model: {
return { prop: 'value',
Quill: null, event: 'change'
currentValue: "",
options: {
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
// 工具栏配置
toolbar: [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
[{ indent: "-1" }, { indent: "+1" }], // 缩进
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"], // 链接、图片、视频
[{ 'script': 'sub'}, { 'script': 'super' }],
],
},
placeholder: "请输入内容",
readOnly: false,
},
};
}, },
computed: { computed: {
styles() { styles() {
let style = {}; let style = {};
@@ -63,134 +40,95 @@ export default {
style.minHeight = `${this.minHeight}px`; style.minHeight = `${this.minHeight}px`;
} }
if (this.height) { if (this.height) {
style.height = `${this.height}px`; style.height = `${this.height+50}px`;
} }
return style; return style;
}, },
}, },
watch: { watch: {
value: { value: function (value) {
handler(val) { if (value !== this.editor.txt.html()) {
if (val !== this.currentValue) { this.editor.txt.html(this.value)
this.currentValue = val === null ? "" : val; }
if (this.Quill) { }
this.Quill.pasteHTML(this.currentValue); // value为编辑框输入的内容这里我监听了一下值当父组件调用得时候如果给value赋值了子组件将会显示父组件赋给的值
}
}
},
immediate: true,
},
}, },
mounted() { data () {
this.init(); return {
},
beforeDestroy() { // 默认有这么多菜单meanArray有值以meanArray为准
this.Quill = null; defaultMeanus: [
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'indent',
'lineHeight',
'foreColor',
'backColor',
'link',
'list',
'justify',
'quote',
'emoticon',
'image',
'video',
'table',
'code',
'splitLine',
'undo',
'redo'
],
editor: ''
}
}, },
methods: { methods: {
init() { init () {
const editor = this.$refs.editor; const _this = this
this.Quill = new Quill(editor, this.options); this.editor = new Editor(this.$refs.editor)
this.Quill.pasteHTML(this.currentValue); this.editor.config.uploadImgShowBase64 = true // 使用 base64 保存图片
this.Quill.on("text-change", (delta, oldDelta, source) => { this.editor.config.height = this.height
const html = this.$refs.editor.children[0].innerHTML; this.setMenus() // 设置菜单
const text = this.Quill.getText(); this.editor.config.onchange = (html) => {
const quill = this.Quill; _this.$emit('change', html) // 将内容同步到父组件中
this.currentValue = html; }
this.$emit("input", html); this.editor.create() // 创建编辑器
this.$emit("on-change", { html, text, quill });
});
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.$emit("on-text-change", delta, oldDelta, source);
});
this.Quill.on("selection-change", (range, oldRange, source) => {
this.$emit("on-selection-change", range, oldRange, source);
});
this.Quill.on("editor-change", (eventName, ...args) => {
this.$emit("on-editor-change", eventName, ...args);
});
}, },
setMenus () {
// 设置菜单
if (this.meanArray) {
this.editor.config.menus = this.meanArray
} else {
this.editor.config.menus = this.defaultMeanus
}
},
getHtml () {
// 得到文本内容
return this.editor.txt.html()
},
setHtml (txt) {
// 设置富文本里面的值
this.editor.txt.html(txt)
}
}, },
}; mounted () {
const that = this
that.$nextTick(function () {
that.init()
})
}
}
</script> </script>
<style> <style scoped lang="scss">
.editor, .ql-toolbar {
.editor{
z-index: 1!important;
white-space: pre-wrap!important; white-space: pre-wrap!important;
line-height: normal !important; line-height: normal !important;
} }
.quill-img {
display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: "保存";
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
content: "请输入视频地址:";
}
.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="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
</style> </style>

View File

@@ -4,13 +4,11 @@
<el-col :offset="1" :span="22"> <el-col :offset="1" :span="22">
<div class="context"> <div class="context">
<div class="title">{{ article.title }}</div> <div class="title">{{ article.title }}</div>
<!-- <Editor></Editor>-->
<div class="text" v-html="article.content"></div> <div class="text" v-html="article.content"></div>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-form ref="elForm" size="medium" label-width="100px"> <el-form ref="elForm" size="medium" label-width="100px">
<!-- <el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="100px">-->
<el-row> <el-row>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="是否顶置"> <el-form-item label="是否顶置">
@@ -65,9 +63,11 @@
<script> <script>
import {approve, getArticle, rejected} from "@/api/sist/article"; import {approve, getArticle, rejected} from "@/api/sist/article";
import Editor from '@/views/utils/Editor'
export default { export default {
components: {}, components: {
Editor
},
name: "approve", name: "approve",
data() { data() {
return { return {

View File

@@ -112,7 +112,7 @@
</el-row> </el-row>
<el-row> <el-row>
<el-col :offset="1" :span="22"> <el-col :offset="1" :span="22">
<Editor v-model="formData.content" :min-height="500"/> <Editor v-model="formData.content" :height="800"/>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
@@ -310,6 +310,11 @@ export default {
} }
</script> </script>
<style>
.el-select-dropdown{
z-index: 2147483647!important;
}
</style>
<style scoped lang="scss"> <style scoped lang="scss">
.article { .article {
margin-top: 20px; margin-top: 20px;

View File

@@ -1,21 +1,131 @@
<template> <template>
<div class="Editor"> <div class="editor" :style="styles" ref="editor"></div>
<ckeditor v-model="context"></ckeditor>
<div>{{context}}</div>
</div>
</template> </template>
<script> <script>
import Editor from 'wangeditor'
export default { export default {
name: "Editor", name: "Editor",
data(){ props: {
return{ /* 编辑器的内容 */
context:"" value: {
type: String,
default: ''
},
/* 高度 */
height: {
type: Number,
default: null,
},
/* 最小高度 */
minHeight: {
type: Number,
default: null,
},
meanArray: {
// 自定义菜单
type: Array,
default: null
} }
},
model: {
prop: 'value',
event: 'change'
},
computed: {
styles() {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
},
},
watch: {
value: function (value) {
if (value !== this.editor.txt.html()) {
this.editor.txt.html(this.value)
}
}
// value为编辑框输入的内容这里我监听了一下值当父组件调用得时候如果给value赋值了子组件将会显示父组件赋给的值
},
data () {
return {
// 默认有这么多菜单meanArray有值以meanArray为准
defaultMeanus: [
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'indent',
'lineHeight',
'foreColor',
'backColor',
'link',
'list',
'justify',
'quote',
'emoticon',
'image',
'video',
'table',
'code',
'splitLine',
'undo',
'redo'
],
editor: ''
}
},
methods: {
init () {
const _this = this
this.editor = new Editor(this.$refs.editor)
this.editor.config.uploadImgShowBase64 = true // 使用 base64 保存图片
this.setMenus() // 设置菜单
this.editor.config.onchange = (html) => {
_this.$emit('change', html) // 将内容同步到父组件中
}
this.editor.create() // 创建编辑器
},
setMenus () {
// 设置菜单
if (this.meanArray) {
this.editor.config.menus = this.meanArray
} else {
this.editor.config.menus = this.defaultMeanus
}
},
getHtml () {
// 得到文本内容
return this.editor.txt.html()
},
setHtml (txt) {
// 设置富文本里面的值
this.editor.txt.html(txt)
}
},
mounted () {
const that = this
that.$nextTick(function () {
that.init()
})
} }
} }
</script> </script>
<style scoped> <style scoped lang="scss">
.editor{
z-index: 1!important;
white-space: pre-wrap!important;
line-height: normal !important;
}
</style> </style>

View File

@@ -0,0 +1,196 @@
<template>
<div class="editor" ref="editor" :style="styles"></div>
</template>
<script>
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
export default {
name: "Editor",
props: {
/* 编辑器的内容 */
value: {
type: String,
default: "",
},
/* 高度 */
height: {
type: Number,
default: null,
},
/* 最小高度 */
minHeight: {
type: Number,
default: null,
},
},
data() {
return {
Quill: null,
currentValue: "",
options: {
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
// 工具栏配置
toolbar: [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
[{ indent: "-1" }, { indent: "+1" }], // 缩进
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"], // 链接、图片、视频
[{ 'script': 'sub'}, { 'script': 'super' }],
],
},
placeholder: "请输入内容",
readOnly: false,
},
};
},
computed: {
styles() {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
},
},
watch: {
value: {
handler(val) {
if (val !== this.currentValue) {
this.currentValue = val === null ? "" : val;
if (this.Quill) {
this.Quill.pasteHTML(this.currentValue);
}
}
},
immediate: true,
},
},
mounted() {
this.init();
},
beforeDestroy() {
this.Quill = null;
},
methods: {
init() {
const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options);
this.Quill.pasteHTML(this.currentValue);
this.Quill.on("text-change", (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
this.currentValue = html;
this.$emit("input", html);
this.$emit("on-change", { html, text, quill });
});
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.$emit("on-text-change", delta, oldDelta, source);
});
this.Quill.on("selection-change", (range, oldRange, source) => {
this.$emit("on-selection-change", range, oldRange, source);
});
this.Quill.on("editor-change", (eventName, ...args) => {
this.$emit("on-editor-change", eventName, ...args);
});
},
},
};
</script>
<style>
.editor, .ql-toolbar {
white-space: pre-wrap!important;
line-height: normal !important;
}
.quill-img {
display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: "保存";
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
content: "请输入视频地址:";
}
.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="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
</style>