vue-kindEditor
npm install vue-kindeditor -S
npm install kindeditor -S
"vue-kindeditor": "^0.4.5",
- 我没有有main.js中引入 而是放在了组件中使用的vue.component()
- 分为3个组件
-
-kindeditor --image.js --index.vue --KindEditor.vue
1.image.js
/* eslint-disable */
/*******************************************************************************
*******************************************************************************/
import axios from 'axios'
import {Message} from "element-ui";
import { getToken } from '@/base/cookie';
KindEditor.plugin('image', function(K) {
var self = this, name = 'image',
allowImageUpload = K.undef(self.allowImageUpload, true),
allowImageRemote = K.undef(self.allowImageRemote, true),
formatUploadUrl = K.undef(self.formatUploadUrl, true),
allowFileManager = K.undef(self.allowFileManager, false),
uploadJson = K.undef(self.uploadJson, self.basePath + 'php/upload_json.php'),
imageTabIndex = K.undef(self.imageTabIndex, 0),
imgPath = self.pluginsPath + 'image/images/',
extraParams = K.undef(self.extraFileUploadParams, {}),
filePostName = K.undef(self.filePostName, 'imgFile'),
fillDescAfterUploadImage = K.undef(self.fillDescAfterUploadImage, false),
lang = self.lang(name + '.');
self.plugin.imageDialog = function(options) {
var imageUrl = options.imageUrl,
imageWidth = K.undef(options.imageWidth, ''),
imageHeight = K.undef(options.imageHeight, ''),
imageTitle = K.undef(options.imageTitle, ''),
imageAlign = K.undef(options.imageAlign, ''),
showRemote = K.undef(options.showRemote, true),
showLocal = K.undef(options.showLocal, true),
tabIndex = K.undef(options.tabIndex, 0),
clickFn = options.clickFn;
var target = 'kindeditor_upload_iframe_' + new Date().getTime();
var html = [
'<div style="padding:20px;">',
//local upload - start
'<iframe name="' + target + '" style="display:none;"></iframe>',
'<form class="ke-upload-area ke-form" method="post" enctype="multipart/form-data" target="' + target + '" action="' + K.addParam(uploadJson, 'dir=image') + '">',
//file
'<div class="ke-dialog-row">',
'<label style="width:60px;">' + lang.localUrl + '</label>',
'<input type="text" name="localUrl" class="ke-input-text" tabindex="-1" style="width:200px;" readonly="true" /> ',
'<input type="button" class="ke-upload-button" value="' + lang.upload + '" />',
'</div>',
'</form>',
//local upload - end
'</div>'
].join('');
var dialogWidth = showLocal || allowFileManager ? 450 : 400,
dialogHeight = showLocal && showRemote ? 300 : 250;
var dialog = self.createDialog({
name : name,
width : dialogWidth,
height : dialogHeight,
title : self.lang(name),
body : html,
yesBtn : {
name : self.lang('yes'),
click : function(e) {
var zipFormData = new FormData();
let file = document.querySelector('.ke-upload-file').files[0]
if (file==null) {
Message({
type: 'warning',
message: "请选择图片"
})
return
} else if(file.size>10*1024*1024){
Message({
type: 'warning',
message: "图片不能大于10M"
})
return
}
zipFormData.append('file',file );//filename是键,file是值,就是要传的文件,test.zip是要传的文件名
let config = { headers: { 'Content-Type': 'multipart/form-data','X-Token': getToken() } };
axios.post(self.uploadJson, zipFormData,config).then(res=> {
self.uploadbutton.options.afterUpload(res.data)
});
// Bugfix: http://code.google.com/p/kindeditor/issues/detail?id=319
if (dialog.isLoading) {
return;
}
// insert local image
if (showLocal && showRemote && tabs && tabs.selectedIndex === 1 || !showRemote) {
if (uploadbutton.fileBox.val() == '') {
alert(self.lang('pleaseSelectFile'));
return;
}
// dialog.showLoading(self.lang('uploadLoading'));
// uploadbutton.submit();
localUrlBox.val('');
}
}
},
beforeRemove : function() {
viewServerBtn.unbind();
widthBox.unbind();
heightBox.unbind();
refreshBtn.unbind();
}
}),
div = dialog.div;
var urlBox = K('[name="url"]', div),
localUrlBox = K('[name="localUrl"]', div),
viewServerBtn = K('[name="viewServer"]', div),
widthBox = K('.tab1 [name="width"]', div),
heightBox = K('.tab1 [name="height"]', div),
refreshBtn = K('.ke-refresh-btn', div),
titleBox = K('.tab1 [name="title"]', div),
alignBox = K('.tab1 [name="align"]', div);
var uploadbutton = K.uploadbutton({
button : K('.ke-upload-button', div)[0],
fieldName : filePostName,
form : K('.ke-form', div),
target : target,
width: 60,
afterUpload : function(data) {
dialog.hideLoading();
if (data.code === 200) {
var url = data.data.url;
console.log(url)
if (formatUploadUrl) {
url = K.formatUrl(url, 'absolute');
console.log(url, 'formatUrl')
}
if (self.afterUpload) {
self.afterUpload.call(self, url, data, name);
}
if (!fillDescAfterUploadImage) {
clickFn.call(self, url, data.title, data.width, data.height, data.border, data.align);
} else {
K(".ke-dialog-row #remoteUrl", div).val(url);
K(".ke-tabs-li", div)[0].click();
K(".ke-refresh-btn", div).click();
}
} else {
alert(data.message);
}
},
afterError : function(html) {
dialog.hideLoading();
self.errorDialog(html);
}
});
uploadbutton.fileBox.change(function(e) {
localUrlBox.val(uploadbutton.fileBox.val());
});
self.uploadbutton = uploadbutton
var originalWidth = 0, originalHeight = 0;
function setSize(width, height) {
widthBox.val(width);
heightBox.val(height);
originalWidth = width;
originalHeight = height;
}
refreshBtn.click(function(e) {
var tempImg = K('<img src="' + urlBox.val() + '" />', document).css({
position : 'absolute',
visibility : 'hidden',
top : 0,
left : '-1000px'
});
tempImg.bind('load', function() {
setSize(tempImg.width(), tempImg.height());
tempImg.remove();
});
K(document.body).append(tempImg);
});
widthBox.change(function(e) {
if (originalWidth > 0) {
heightBox.val(Math.round(originalHeight / originalWidth * parseInt(this.value, 10)));
}
});
heightBox.change(function(e) {
if (originalHeight > 0) {
widthBox.val(Math.round(originalWidth / originalHeight * parseInt(this.value, 10)));
}
});
urlBox.val(options.imageUrl);
setSize(options.imageWidth, options.imageHeight);
titleBox.val(options.imageTitle);
alignBox.each(function() {
if (this.value === options.imageAlign) {
this.checked = true;
return false;
}
});
return dialog;
};
self.plugin.image = {
edit : function() {
var img = self.plugin.getSelectedImage();
console.log(img, 'img')
self.plugin.imageDialog({
imageUrl : img ? img.attr('data-ke-src') : 'http://',
imageWidth : img ? img.width() : '',
imageHeight : img ? img.height() : '',
imageTitle : img ? img.attr('title') : '',
imageAlign : img ? img.attr('align') : '',
showRemote : allowImageRemote,
showLocal : allowImageUpload,
tabIndex: img ? 0 : imageTabIndex,
clickFn : function(url, title, width, height, border, align) {
if (img) {
img.attr('src', url);
img.attr('data-ke-src', url);
img.attr('width', width);
img.attr('height', height);
img.attr('title', title);
img.attr('align', align);
img.attr('alt', title);
} else {
self.exec('insertimage', url, title, width, height, border, align);
}
// Bugfix: [Firefox] 上传图片后,总是出现正在加载的样式,需要延迟执行hideDialog
setTimeout(function() {
self.hideDialog().focus();
}, 0);
}
});
},
'delete' : function() {
var target = self.plugin.getSelectedImage();
if (target.parent().name == 'a') {
target = target.parent();
}
target.remove();
// [IE] 删除图片后立即点击图片按钮出错
self.addBookmark();
}
};
self.clickToolbar(name, self.plugin.image.edit);
});
2
- index.vue
<template>
<div>
<editor :id="id" ref="kingEditor" class='editor' width="100%" :height="height" :content="content"
:items="items"
pluginsPath="/static/kindeditor/plugins/"
:upload-json="uploadJson"
:allow-file-manager="false"
:allow-image-upload="true"
:pasteType="1"
:allow-image-remote="false"
:resizeType="0"
:zIndex="zIndex"
file-post-name="file"
:loadStyleMode="false"
:afterFocus="onEditorFocus"
:afterBlur="onEditorBlur"
@on-content-change="onContentChange"></editor>
</div>
</template>
<script>
// import Vue from 'vue'
import editor from './KindEditor'
// import VueKindEditor from 'vue-kindeditor'
import '../../../public/kindeditor/kindeditor-all.js'
import '../../../public/kindeditor/themes/default/default.css'
import './image.js'
// Vue.use(VueKindEditor)
export default {
name: 'kingeditor',
components: {
editor
},
props: {
content: {
type: String,
default: ''
},
height: {
type: String,
default: '500px'
},
zIndex: {
type: Number,
default: 3000
},
items:{
type: Array,
default:function () {
//不传则用这个作为默认值
return [
'undo', 'redo', '|', 'preview', 'print', 'cut', 'copy', 'paste',
'|', 'formatblock', 'fontname', 'fontsize', '|',
'justifyleft', 'justifycenter', 'justifyright',
'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
'superscript', 'clearhtml', 'quickformat', 'selectall',
'|', 'forecolor', 'hilitecolor', 'bold',
'italic', 'underline', 'lineheight', 'removeformat', '|', 'image', 'table', 'hr', 'pagebreak',
'anchor', 'link', 'unlink'
]
}
},
id: {
type: String,
default: "editor_id"
}
},
data () {
return {
uploadJson: `${process.env.VUE_APP_BASE_API}/common/uploadFile`,
}
},
mounted() {},
methods: {
onContentChange(val) {
// this.content = val
this.$emit('on-content-change', val)
},
afterChange(val) {
// this.content = val
},
onEditorFocus() {
// 获得焦点事件
this.$emit('focus')
},
onEditorBlur() {
// 失去焦点事件
this.$emit('blur')
}
}
}
</script>
<style lang='scss' scoped>
</style>
3
- KindEditor.vue
<template>
<div :id="'_'+id" class="kindeditor">
<textarea :id="id" name="content" v-model="outContent"></textarea>
<span v-if="maxlength >0" class="maxlength">已输入 {{textLength}}/{{maxlength}} 字</span>
</div>
</template>
<script>
export default {
name: 'kindeditor',
data () {
return {
editor: null,
outContent: this.content,
textLength: 0
}
},
props: {
placeholder: {
type: String,
default: ''
},
maxlength: {
type: Number,
default: -1
},
content: {
type: String,
default: ''
},
id: {
type: String,
required: true
},
width: {
type: String
},
height: {
type: String
},
minWidth: {
type: Number,
default: 650
},
minHeight: {
type: Number,
default: 100
},
items: {
type: Array,
default: function () {
return [
'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage',
'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
'anchor', 'link', 'unlink', '|', 'about'
]
}
},
noDisableItems: {
type: Array,
default: function () {
return ['source', 'fullscreen']
}
},
filterMode: {
type: Boolean,
default: true
},
htmlTags: {
type: Object,
default: function () {
return {
font: ['color', 'size', 'face', '.background-color'],
span: ['style'],
div: ['class', 'align', 'style'],
table: ['class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'style'],
'td,th': ['class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor', 'style'],
a: ['class', 'href', 'target', 'name', 'style'],
embed: ['src', 'width', 'height', 'type', 'loop', 'autostart', 'quality',
'style', 'align', 'allowscriptaccess', '/'],
img: ['src', 'width', 'height', 'border', 'alt', 'title', 'align', 'style', '/'],
hr: ['class', '/'],
br: ['/'],
'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6': ['align', 'style'],
'tbody,tr,strong,b,sub,sup,em,i,u,strike': [],
video: ['controls', 'width', 'height', 'class'],
source: ['src']
}
}
},
wellFormatMode: {
type: Boolean,
default: true
},
resizeType: {
type: Number,
default: 2
},
themeType: {
type: String,
default: 'default'
},
langType: {
type: String,
default: 'zh-CN'
},
designMode: {
type: Boolean,
default: true
},
fullscreenMode: {
type: Boolean,
default: false
},
basePath: {
type: String
},
themesPath: {
type: String
},
pluginsPath: {
type: String,
default: ''
},
langPath: {
type: String
},
minChangeSize: {
type: Number,
default: 5
},
loadStyleMode: {
type: Boolean,
default: true
},
urlType: {
type: String,
default: ''
},
newlineTag: {
type: String,
default: 'p'
},
pasteType: {
type: Number,
default: 2
},
dialogAlignType: {
type: String,
default: 'page'
},
shadowMode: {
type: Boolean,
default: true
},
zIndex: {
type: Number,
default: 811213
},
useContextmenu: {
type: Boolean,
default: true
},
syncType: {
type: String,
default: 'form'
},
indentChar: {
type: String,
default: '\t'
},
cssPath: {
type: [String, Array]
},
cssData: {
type: String
},
bodyClass: {
type: String,
default: 'ke-content'
},
colorTable: {
type: Array
},
afterCreate: {
type: Function,
default: function () { }
},
afterChange: {
type: Function
},
afterTab: {
type: Function
},
afterFocus: {
type: Function
},
afterBlur: {
type: Function
},
afterUpload: {
type: Function
},
uploadJson: {
type: String
},
fileManagerJson: {
type: Function
},
allowPreviewEmoticons: {
type: Boolean,
default: true
},
allowImageUpload: {
type: Boolean,
default: true
},
allowFlashUpload: {
type: Boolean,
default: true
},
allowMediaUpload: {
type: Boolean,
default: true
},
allowFileUpload: {
type: Boolean,
default: true
},
allowFileManager: {
type: Boolean,
default: false
},
fontSizeTable: {
type: Array,
default: function () {
return ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px']
}
},
imageTabIndex: {
type: Number,
default: 0
},
formatUploadUrl: {
type: Boolean,
default: true
},
fullscreenShortcut: {
type: Boolean,
default: false
},
extraFileUploadParams: {
type: Array,
default: function () {
return []
}
},
filePostName: {
type: String,
default: 'imgFile'
},
fillDescAfterUploadImage: {
type: Boolean,
default: false
},
afterSelectFile: {
type: Function
},
pagebreakHtml: {
type: String,
default: '<hr style=”page-break-after: always;” class=”ke-pagebreak” />'
},
allowImageRemote: {
type: Boolean,
default: true
},
autoHeightMode: {
type: Boolean,
default: false
},
fixToolBar: {
type: Boolean,
default: false
},
tabIndex: {
type: Number
}
},
watch: {
content (val) {
this.editor && val !== this.outContent && this.editor.html(val)
},
outContent (val) {
this.$emit('update:content', val)
this.$emit('on-content-change', val)
}
},
mounted () {
var _this = this
_this.editor = window.KindEditor.create('#' + this.id, {
width: _this.width,
height: _this.height,
minWidth: _this.minWidth,
minHeight: _this.minHeight,
items: _this.items,
noDisableItems: _this.noDisableItems,
filterMode: _this.filterMode,
htmlTags: _this.htmlTags,
wellFormatMode: _this.wellFormatMode,
resizeType: _this.resizeType,
themeType: _this.themeType,
langType: _this.langType,
designMode: _this.designMode,
fullscreenMode: _this.fullscreenMode,
basePath: _this.basePath,
themesPath: _this.cssPath,
pluginsPath: _this.pluginsPath,
langPath: _this.langPath,
minChangeSize: _this.minChangeSize,
loadStyleMode: _this.loadStyleMode,
urlType: _this.urlType,
newlineTag: _this.newlineTag,
pasteType: _this.pasteType,
dialogAlignType: _this.dialogAlignType,
shadowMode: _this.shadowMode,
zIndex: _this.zIndex,
useContextmenu: _this.useContextmenu,
syncType: _this.syncType,
indentChar: _this.indentChar,
cssPath: _this.cssPath,
cssData: _this.cssData,
bodyClass: _this.bodyClass,
colorTable: _this.colorTable,
afterCreate: () => {
this.$nextTick(() => {
var dom = document.getElementById('_' + this.id).querySelector('.ke-edit')
var ph = document.createElement('div')
ph.className = 'ph'
ph.style.position = 'absolute'
dom.style.position = 'relative'
ph.style.top = '0px'
ph.style.left = '8px'
ph.style.color = '#ccc'
ph.style.fontSize = '13px'
ph.style.pointerEvents = 'none'
ph.innerText = this.placeholder
if (this.content) {
ph.style.display = 'none'
}
dom.appendChild(ph)
this.ph = ph
})
_this.afterCreate()
},
afterChange: function () {
// _this.textLength = this.count('text')
// if (_this.maxlength > -1 && this.count('text') > _this.maxlength) {
// var strValue = this.text()
// this.text('')
// this.appendHtml(strValue.substring(0, _this.maxlength))
// }
//remark:----2021.04.16
var strValue = this.text()
const str = strValue.replace(/<\/?[^>]*>|(\n|\t|\r)|(\s)|( )/g,'')
_this.textLength = str.length
if (_this.maxlength > -1 && str.length > _this.maxlength) {
var complateStr = str.substring(0, _this.maxlength)
this.text('')
// this.text(complateStr)
this.appendHtml(complateStr)
}
_this.afterChange
_this.outContent = this.html()
if (_this.outContent === '' || _this.outContent === '<br />') {
if (_this.ph) { _this.ph.style.display = 'block' }
} else {
if (_this.ph) { _this.ph.style.display = 'none' }
}
},
afterTab: _this.afterTab,
afterFocus: _this.afterFocus,
afterBlur: _this.afterBlur,
afterUpload: _this.afterUpload,
uploadJson: _this.uploadJson,
fileManagerJson: _this.fileManagerJson,
allowPreviewEmoticons: _this.allowPreviewEmoticons,
allowImageUpload: _this.allowImageUpload,
allowFlashUpload: _this.allowFlashUpload,
allowMediaUpload: _this.allowMediaUpload,
allowFileUpload: _this.allowFileUpload,
allowFileManager: _this.allowFileManager,
fontSizeTable: _this.fontSizeTable,
imageTabIndex: _this.imageTabIndex,
formatUploadUrl: _this.formatUploadUrl,
fullscreenShortcut: _this.fullscreenShortcut,
extraFileUploadParams: _this.extraFileUploadParams,
filePostName: _this.filePostName,
fillDescAfterUploadImage: _this.fillDescAfterUploadImage,
afterSelectFile: _this.afterSelectFile,
pagebreakHtml: _this.pagebreakHtml,
allowImageRemote: _this.allowImageRemote,
autoHeightMode: _this.autoHeightMode,
fixToolBar: _this.fixToolBar,
tabIndex: _this.tabIndex
})
}
}
</script>
<style lang="scss">
.kindeditor{
position: relative;
.maxlength{
position: absolute;
right: 25px;
bottom: 13px;
background-color: #fff;
height: 20px;
line-height: 20px;
color: #C0C4CC;
}
}
</style>
4
- 页面的使用
<kindeditor :content="ruleForm1.detailItemDescriptionRtf" :z-index="3000" class="w-100" height="280" @on-content-change="contentChange" />
+ 或者
<kindeditor style="width: 800px;" :maxlength="5000" :content="ruleForm.noticeText" @on-content-change="contentChange"></kindeditor>
+ 方法
deserveEditData() {
this.ruleForm.noticeText = this.currentNoticeData.details
},
contentChange(val) {
this.ruleForm1.detailItemDescriptionRtf = val
},