vue-kindEditor --前端富文本编辑器-的使用过程的一次记录

在这里插入图片描述

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" /> &nbsp;',
			'<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)|(&nbsp;)/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
},
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值