粗略了解一下编译器的底层
ckeditor的使用
<template>
<div :style="containerStyle" class="rich-text-editor">
<div v-if="textInput" class="rich-text-editor-wrap">
<div v-show="!isFocus && !isFullScreen" class="preview-container">
<el-input
v-model="textValue"
:placeholder="placeholder"
@focus="showEditor"
></el-input>
</div>
<div v-show="isFocus || isFullScreen">
<textarea :id="editorId"></textarea>
</div>
</div>
<div v-else class="rich-text-editor-wrap">
<textarea :id="editorId"></textarea>
</div>
</div>
</template>
<script>
import { CKEDITOR } from ''@/util/ckeditor.js''
let count = 0
export default {
props: {
width: {
type: String,
default: ''100%''
},
height: {
type: String,
default: ''100%''
},
textInput: {
type: Boolean,
default: false
},
autoSaveKey: {
type: String,
default: ''''
},
value: {
type: String,
default: ''''
},
// 工具栏:Basic、Full、Common
toolbar: {
type: [String, Array],
default: ''Common''
},
placeholder: {
type: String,
default: ''''
},
readonly: {
type: Boolean,
default: false
}
},
watch: {
editor: {
handler (val) {
if (val === null) {
this.initRichText()
}
}
},
value (val) {
if (this.itemValue !== val) {
this.itemValue = val
this.setValue()
}
}
},
data () {
return {
editorId: ''rich-text-editor-'' + ++count,
itemValue: this.value,
editor: null,
copyPopover: null,
copyValue: '''',
isFocus: false,
textValue: '''',
// 是否全屏
isFullScreen: false
}
},
computed: {
containerStyle () {
let style = {}
if (this.width.indexOf(''%'') < 0 && !this.textInput) {
style.minWidth = this.width
}
if (this.height.indexOf(''%'') < 0 && !this.textInput) {
style.minHeight = this.height
}
return style
}
},
methods: {
initRichText () {
let $ = window.jQuery
let config = {
height: this.height,
width: this.width,
autoSaveKey: this.autoSaveKey,
placeholder: this.placeholder,
readOnly: this.readonly
}
if (this.isTextInput === true) {
config.startupFocus = true
}
if (this.toolbar !== ''Common'') {
config.toolbar = this.toolbar
}
let editor = CKEDITOR.replace(this.editorId, config)
this.editor = editor
let self = this
if (this.editor && this.editor !== null) {
// CKEDITOR.on(''instanceReady'', function (e) {
// 设置值
// 加载完毕事件
editor.on(''loaded'', () => {
this.$emit(''loaded'', editor)
})
// 设置值
if (this.itemValue) {
this.setValue()
}
// 内容改变事件
editor.on(''change'', function (evt) {
let value = evt.editor.getData()
let textValue = evt.editor.document.getBody().getText()
self.handleChange(value, textValue)
})
// 粘贴事件
editor.on(''paste'', function (evt) {
let data = evt.data
let type = data.type
let value = data.dataValue
if (type === ''html'') {
// html内容
try {
let editor = evt.editor
let $obj = $(value)
if ($obj.is(''img'')) {
let src = $obj.attr(''src'')
let maxWidth = window.editorImageMaxWidth
$(''<img/>'')
.attr(''src'', src)
.load(function () {
let width = this.width
if (maxWidth && width > maxWidth) {
$obj.css(''width'', maxWidth + ''px'')
$obj.css(''height'', ''auto'')
}
editor.insertHtml($obj.prop(''outerHTML''))
})
return false
}
} catch (e) {
console.error(e)
}
}
value && self.createCopyPopover(value)
})
// 键盘输入事件
editor.on(''key'', function (evt) {
self.removeCopyPopover()
})
// 最大化最小化事件
editor.on(''maximize'', function (evt) {
self.isFullScreen = !self.isFullScreen
if (window.fullScreenEditor) {
window.fullScreenEditor = null
} else {
window.fullScreenEditor = evt.editor
}
})
// 失去焦点事件
editor.on(''blur'', function (evt) {
// self.validate(''blur'')
if (
window.fullScreenEditor == null ||
window.fullScreenEditor === undefined
) {
self.$emit(''blur'')
}
self.isFocus = false
})
// 获得焦点事件
editor.on(''focus'', function (evt) {
self.isFocus = true
})
// })
}
},
showEditor () {
this.isFocus = true
this.$nextTick(() => {
if (this.editor && this.editor !== null) {
this.editor.focus()
}
})
},
木易楊@:
handleChange (value, textValue) {
this.itemValue = value
this.textValue = textValue
this.validate(''change'')
// 判断是否为全部空格
let newValue = ''''
if (
!textValue.trim() &&
!value.includes(''<img'') &&
!value.includes(''<table'')
) {
newValue = ''''
} else {
newValue = value
}
this.$emit(''input'', value)
this.$emit(''change'', newValue)
},
setValue () {
this.editor.setData(this.itemValue)
this.textValue = this.getText()
},
木易楊@:
getText () {
if (!this.itemValue) {
return ''''
}
if (this.editor.document) {
try {
return this.editor.document.getBody().getText()
} catch (e) {
console.info(e)
}
}
let html = this.itemValue
if (!html.startsWith(''<'')) {
html = ''<div>'' + html + ''</div>''
}
return window.jQuery(html).text()
},
getEditorDom () {
return document.getElementById(''cke_'' + this.editorId)
},
getOffsetTop (obj) {
obj = obj || this.getEditorDom()
let offsetTop = obj.offsetTop || 0
return offsetTop === 0
? obj.parentNode
? this.getOffsetTop(obj.parentNode)
: 0
: offsetTop
},
getOffsetLeft (obj) {
obj = obj || this.getEditorDom()
let offsetLeft = obj.offsetLeft || 0
return offsetLeft === 0
? obj.parentNode
? this.getOffsetLeft(obj.parentNode)
: 0
: offsetLeft
},
getCenterPosition () {
let offsetTop = this.getOffsetTop()
let getOffsetLeft = this.getOffsetLeft()
let height = this.getEditorDom().offsetHeight
let width = this.getEditorDom().offsetWidth
return {
top: offsetTop + height / 2,
left: getOffsetLeft + width / 2
}
},
getEditorDocument () {
return this.editor.document.$
},
createCopyPopover (value) {
this.removeCopyPopover()
let div = document.createElement(''div'')
div.innerHTML = `
<ul>
<li class="source-text-li"><i class="source-text"></i><span>保留源格式</span></li>
<li class="plain-text-li"><i class="plain-text"></i><span>保留纯文本</span></li>
</ul>
`
div.className = ''cke_popover''
let ckeInner = this.getEditorDom().querySelector(''.cke_inner'')
div.style.position = ''absolute''
div.style.top = ''50%''
div.style.left = ''50%''
ckeInner.appendChild(div)
this.copyPopover = div
this.copyValue = value
// 监听事件
let self = this
div
.querySelector(''.source-text-li'')
.addEventListener(''click'', function () {
self.removeCopyPopover()
})
div.querySelector(''.plain-text-li'').addEventListener(''click'', function () {
self.removeCopyPopover()
self.editor.execCommand(''undo'')
div = document.createElement(''div'')
div.innerHTML = self.copyValue
self.editor.insertHtml(div.innerText)
})
},
removeCopyPopover () {
if (this.copyPopover != null) {
this.copyPopover.remove()
this.copyPopover = null
}
},
getParentVNode (vnode, tagName) {
if (!vnode) {
vnode = this
}
if (!vnode.$vnode || !vnode.$vnode.componentOptions) {
return null
}
let tag = vnode.$vnode.componentOptions.tag
if (tag === tagName) {
return vnode
}
if (!vnode.$parent) {
return null
}
return this.getParentVNode(vnode.$parent, tagName)
},
getElFormItem (vnode) {
return this.getParentVNode(null, ''el-form-item'')
},
getElForm (vnode) {
return this.getParentVNode(null, ''el-form'')
},
validate (eventName) {
let elFormItem = this.getElFormItem()
if (elFormItem) {
let elForm = this.getElForm(elFormItem)
let prop = elFormItem.prop
if (prop && elForm.rules) {
for (let name in elForm.rules) {
if (name === prop) {
let isNeddValidate = false
elForm.rules[name].forEach(rule => {
if (rule.trigger === eventName) {
isNeddValidate = true
}
})
isNeddValidate && elForm.validateField(prop)
}
}
}
}
}
},
mounted () {
this.initRichText()
}
}
</script>
<style lang="less">
/* 去除路径显示 */
.cke_path {
display: none;
}
.cke_popover {
font-size: 13px;
ul {
background: #fff;
list-style: none;
border: 1px solid #ccc;
border-bottom: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
li {
padding: 5px;
border-bottom: 1px solid #ccc;
cursor: pointer;
height: 20px;
line-height: 20px;
> span {
vertical-align: middle;
}
i {
display: inline-block;
width: 15px;
height: 15px;
vertical-align: middle;
background-size: 15px 15px;
margin-right: 5px;
}
i.plain-text {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAkElEQVQ4T+3TPQ4BYRCH8d8egiO4gUqzhUajcwiVOIQLyN5CLRqi1WodgUvIJitZrx0iS7fTzswzn/9MS8ta5ksBG/Q+QG+YPWJSwAUF1shxrALHOGCJOQYR4IQprgGgjy2GEaCstK+cTR2Urgl2EaA+fgR4WtG7K3SA5j94+bG/LXGFUVLujEXaws/F9LU47xkkIBGRZtDbAAAAAElFTkSuQmCC);
}
i.source-text {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABHUlEQVQ4T6XTsSuGURTH8c+LFUUZKIsyCKNdSozYTUoZRBZKIrEoWSx2k8IqKX+CEItJGSVMDOjqvk/X7cHw3ul5zjnP957fOb+nosZTqfF7KeAJW9iP0Do0xudXfKABGxhFc8ilgD0s4THp6rsIz0msFfNYzgF9uMokreITa1l8CGc5oBfXSWGQ8BDfO6KEaroHNzmgH5cJYAyLGMA4jpJcUZvOoGgrFh5iBvc4x3ACKJWQAjqxgikcYALduIuQUkA6xLDOerzEdc1hGwsRUNSmEqq6wq5PMZi0fIt2tOENf85gBF3YTQCzaMEFjn8DrGMnM1KZ04ORNjGdrzFY+SQ67D3OoCkSwiyClcOZjE4MHf2wctlt/8Zq/hu/ABKzNxFN8ClKAAAAAElFTkSuQmCC);
}
}
li:hover {
background-color: #eee;
}
}
}
</style>
使用
<rich-text-editor width="81%" v-model="formModel.march" :toolbar="toolbar"></rich-text-editor>
data(){
return{
toolbar: [
{ name: ''basicstyles'', items: [''Bold'', ''Italic'', ''Underline'', ''Strike'', ''Subscript'', ''Superscript'', ''RemoveFormat''] },
{ name: ''editing'', items: [''Find'', ''Replace'', ''SelectAll''] },
{ name: ''document'', items: [''Source'', ''DocProps'', ''Preview''] },
{ name: ''paragraph'', items: [''NumberedList'', ''Outdent'', ''Indent'', ''Blockquote'', ''CreateDiv'', ''JustifyLeft'', ''JustifyCenter'', ''JustifyRight'', ''JustifyBlock'', ''BidiLtr'', ''BidiRtl''] },
{ name: ''forms'', items: [ ''Form'', ''Checkbox'', ''Radio'', ''TextField'', ''Textarea'', ''Select'' ] },
{ name: ''links'', items: [ ''Link'', ''Unlink'', ''Anchor'', ''uploadbutton'' ] },
{ name: ''insert'', items: [ ''Table'', ''HorizontalRule'', ''Smiley'', ''SpecialChar'', ''PageBreak'' ] },
{ name: ''styles'', items: [ ''Styles'', ''Format'', ''Font'', ''FontSize'' ] },
{ name: ''clipboard'', items: [''Cut'', ''Copy'', ''Paste'', ''PasteText'', ''Undo'', ''Redo''] },
{ name: ''colors'', items: [''TextColor'', ''BGColor''] }
]
}
}
CKEditor (Toolbar Definition)工具栏自定义配置
工具栏的定义英汉对照说明:
Source = 源码模式
Save = 保存(提交表单)
NewPage = 新建
Preview = 预览
- = 分割线
Templates = 模板
Cut = 剪切
Copy = 复制
Paste = 粘贴
PasteText = 粘贴为无格式文本
PasteFromWord = 从 MS WORD 粘贴
Print = 打印
SpellChecker = 拼写检查
Scayt = 即时拼写检查
Undo = 撤销
Redo = 重做
Find = 查找
Replace = 替换
SelectAll = 全选
RemoveFormat = 清除格式
Form = 表单
Checkbox = 复选框
Radio = 单选框
TextField = 单行文本
Textarea = 多行文本
Select = 列表/菜单
Button = 按钮
ImageButton = 图片按钮
HiddenField = 隐藏域
Bold = 加粗
Italic = 倾斜
Underline = 下划线
Strike = 删除线
Subscript = 下标
Superscript = 上标
NumberedList = 编号列表
BulletedList = 项目列表
Outdent = 减少缩进量
Indent = 增加缩进量
Blockquote = 块引用
CreateDiv = 创建DIV容器
JustifyLeft = 左对齐
JustifyCenter = 居中
JustifyRight = 右对齐
JustifyBlock = 两端对齐
BidiLtr = 文字方向从左到右
BidiRtl = 文字方向从右到左
Link = 插入/编辑超链接(上传文件)
Unlink = 取消超链接
Anchor = 插入/编辑锚点链接
Image = 图像(上传)
Flash = 动画(上传)
Table = 表格
HorizontalRule = 插入水平线
Smiley = 插入表情
SpecialChar = 插入特殊符号
PageBreak = 插入分页符
Styles = 样式快捷方式
Format = 文本格式
Font = 字体
FontSize = 文字大小
TextColor = 文字颜色
BGColor = 背景颜色
Maximize = 全屏编辑模式
ShowBlocks = 显示区块
About = 显示关于
本文内容图片来自https://www.zhihu.com/questio...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。