通过ckeditor组件在vue2中实现上传图片
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
1,开始实现逻辑前,优先启项目,然后将ckeditor引入,大概如下:
1,npm i @ckeditor/ckeditor5-vue2
2,下载sdk,https://ckeditor.com/ckeditor-5/online-builder/#,打开这个地址,配完就可以下载
3,启动sdk,运行npm install ,npm run build,在build文件夹下就有一个ckeditor.js
直接将这个js放到我们的项目public下,通过script引入即可
接下来就是项目配置
1,配置图片上传,其实就是imageUpload这个插件,首先在组件ckeditor添加属性config
2,配置菜单
3,在初始化方法中调用上传api
4,创建MyUploadAdapter类
import axios from 'axios'
export default class MyUploadAdapter {
constructor(loader, url, token) {
// 文件
this.loader = loader;
// 链接
this.url = url;
// token
this.token = token;
}
// 特定方法,必须得有
async upload() {
return this.uploadFile(this.loader.file);
}
//上传文件
async uploadFile(file, resolve, reject) {
const data = new FormData();
data.append("file", file);
let res = await axios({
url: this.url,
method: "POST",
headers: {
Host: this.url,
"Content-Type": "multipart/form-data",
},
data: {
fileBinaryData: data,
upload_token: this.token,
fileName: file.name,
},
})
// console.log(res.data.tableListData[0].classIntroduce)
return {
// default: res.data.tableListData[0].classIntroduce,
// 返回请求的图片路径
default: res.data.url
};
}
// 取消请求
abort() {
server.abortUpload();
}
}
5,在我们的组件中引入即可,这样上传图片就完成了,整体代码
<template>
<div>
<ckeditor :editor="editor" :value="editorData" :disabled="disabled" :config="editorConfig" @ready="onEditorReady" @focus="onEditorFocus" @blur="onEditorBlur" @input="onEditorInput" @destroy="onEditorDestroy"></ckeditor>
</div>
</template>
<script>
import MyUploadAdapter from './MyUploadAdapter.js'
export default {
name: 'app',
props: {
editorData: { // 初始默认值
type: String,
default: '',
},
disabled: { // 是否只读
type: Boolean,
default: false,
},
},
data() {
return {
editor: ClassicEditor,
// 七牛云的地址
// url: '',
// 本地mock数据接口
url:'',
// token
token: '',
editorConfig: {
toolbar: [
'heading', // 标题
'|',
'fontfamily', // 字体
'fontsize', // 字号
'fontColor', // 字体颜色
'fontBackgroundColor', // 背景颜色
'|',
'bold', // 加粗
'italic', // 斜体
'underline', // 下划线
'strikethrough', // 删除线
'|',
'alignment:left', // 左对齐
'alignment:right', // 右对齐
'alignment:center', // 居中对齐
'alignment:justify', // 分散对齐
'|',
'numberedList', // 数字编号
'bulletedList', // 项目符号
'|',
'outdent', // 左缩进
'indent', // 右缩进
'|',
'link', // 链接
'blockquote', // 引用
'insertTable', // 插入表格
'imageUpload', // 插入图片
'MediaEmbed', // 视频插入
'html5video',
'|',
'undo', // 撤销
'redo', // 重做
],
}
};
},
methods: {
// 初始化
onEditorReady(editor) {
console.log('初始化')
// 上传图片的逻辑
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
return new MyUploadAdapter(loader, this.url, this.token)
}
},
// 聚焦
onEditorFocus() {
console.log('聚焦')
},
// 失去焦点
onEditorBlur() {
console.log('失去焦点')
},
// 输入
onEditorInput() {
console.log('输入')
},
// 页面卸载
onEditorDestroy() {
console.log('卸载')
}
},
}
</script>
<style >
.ck-rounded-corners .ck.ck-editor__main>.ck-editor__editable, .ck.ck-editor__main>.ck-editor__editable.ck-rounded-corners {
height: 200px !important;
}
</style>
更新完整版,具体可根据自己需求进行删减
<template>
<div>
<div style="border: 1px solid #ccc;">
<Toolbar v-if="isToolbar" style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" />
<Editor id="editor" v-model="model" v-resize="onResize" :style="{height:height}" @onFocus="onFocus" @onChange="onChange" :defaultConfig="editorConfig" @onCreated="onCreated" />
</div>
</div>
</template>
<script>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
export default {
components: { Editor, Toolbar },
name: 'wangeditor_',
props: {
height: { // 高度
type: String,
default: '300px'
},
row: { // 表单数据
type: Object,
default: () => { }
},
col: { // 列属性
type: Object,
default: () => { }
},
value: { // 内容
type: String,
default: ''
},
isToolbar: { // 是否显示工具栏
type: Boolean,
default: true
},
read: { // 是否只读
type: Boolean,
default: false
},
autoFocus: { // 是否默认聚焦
type: Boolean,
default: false
},
scroll: { // 是否支持滚动
type: Boolean,
default: true
},
maxLength: { // 最大长度
type: Number,
default: 0
},
placeholder: { // 默认提示
type: String,
default: '请输入内容...'
},
config: { // 上传配置项
type: Object,
default: () => {
// useCdnDomain: true, // 是否使用cdn加速域名
// disableStatisticsReport: false, // 是否禁用日志报告
// uphost: [], //上传的host
// upprotocol: 'https', // 上传域名协议
// region: null, // 选择上传域名区域
// retryCount: 3, // 上传自动重试次数
// concurrentRequestLimit: 3, // 分片上传并发请求量
// checkByServer: false, // 是否开启服务端文件签名校验
// checkByMD5: false, // 是否开启MD5校验,在断点续传时,开启MD5校会将已上传的分片与当前分片进行MD5值对比,若不一致,则重传该分片,避免使用错误的分片,读取分片内容并计算md5会消耗一些时间,默认为false
// forceDirect: false, // 是否上传全部采用直传方式
// chunkSize: 4, // 分片上传时每片的大小,默认为4,最大不超过1024,单位MB
// debugLogLevel: 'OFF', // 允许程序在控制台输出日志
}
},
putExtra: { // 输入配置项
type: Object,
default: () => {
// fname: '', // 文件原始文件名
// customVars: {}, // 自定义变量
// metadata: {}, //防止自定义meta
// mimeType: '', // 所传的文件类型
}
},
token: { // token
type: String,
default: window.qiniuToken
},
url: { // 上传地址
type: String,
default: 'url'
}
},
data() {
let w = this
return {
editor: null, // 工具栏编辑器
toolbarConfig: { // 工具栏配置项
// toolbarKeys: [ // 显示的菜单,默认全部
// ],
excludeKeys: [ // 隐藏的菜单
// "bold", // 粗体
// "underline", // 下划线
// "italic", // 斜体
// "through", // 删除线
// "code", // 行内代码
// "sub", // 下标
// "sup", // 上标
// "clearStyle", // 清除格式
// "color", // 字体颜色
// "bgColor", // 背景色
// "fontSize", // 字号
// "fontFamily", // 字体
// "indent", // 增加缩进
// "delIndent", // 减少缩进
// "justifyLeft", // 左对齐
// "justifyRight", // 右对齐
// "justifyCenter", // 居中对齐
// "justifyJustify", // 两端对齐
// "lineHeight", // 行高
// "insertImage", // 网络图片
// "deleteImage", // 删除图片
// "editImage", // 编辑图片
// "viewImageLink", // 查看链接
// "imageWidth30", // 图片宽度相对于编辑器宽度的百分比30
// "imageWidth50", // 图片宽度相对于编辑器宽度的百分比50
// "imageWidth100", // 图片宽度相对于编辑器宽度的百分比100
// "divider", // 分割线
// "emotion", // 表情
// "insertLink", // 插入链接
// "editLink", // 修改链接
// "unLink", // 取消链接
// "viewLink", // 查看链接
// "codeBlock", // 代码块
// "blockquote", // 引用
// "headerSelect", // 标题
// "header1", // 标题1
// "header2", // 标题2
// "header3", // 标题3
// "header4", // 标题4
// "header5", // 标题5
// "todo", // 待办
// "redo", // 重做
// "undo", // 撤销
// "fullScreen", // 全屏
// "enter", // 回车
// "bulletedList", // 无序列表
// "numberedList", // 有序列表
// "insertTable", // 插入表格
// "deleteTable", // 删除表格
// "insertTableRow", // 插入行
// "deleteTableRow", // 删除行
// "insertTableCol", // 插入列
// "deleteTableCol", // 删除列
// "tableHeader", // 表头
// "tableFullWidth", // 宽度自适应
// "insertVideo", // 插入网络视频
// "uploadVideo", // 上传视频
// "editVideoSize", // 修改视频尺寸
// "uploadImage", // 上传图片
// "codeSelectLang", // 选择语言
// 'group-video', // 上传视频工具
// "group-image", // 上传图片工具
// "group-indent", // 缩进
// "group-justify", // 对齐
// "group-more-style" // 更多
]
},
percent: 0, // 上传进度
editorConfig: { // 编辑器配置项
placeholder: w.placeholder, // 编辑器默认值
readOnly: w.read, // 编辑器只读
autoFocus: w.autoFocus, // 编辑器自动聚焦
scroll: w.scroll, // 编辑器是否可滚动
maxLength: w.maxLength, // 编辑器输入最大长度
MENU_CONF: { // 菜单配置项
uploadImage: { // 上传图片
server: `url`, // 服务器地址
fieldName: 'file', // 文件名称
meta: { // 配置参数
token: window.qiniuToken,
},
customInsert(res, insertFn) { // 上传成功回调
insertFn(res.data.url)
},
},
uploadVideo: { // 上传视频
async customUpload(file, insertFn) { // 自定义上传
let url = await w.upload(file)
insertFn(url)
}
}
}
},
mode: 'default' // or 'simple'
}
},
computed: {
model: {
get:function(){ //显示
return this.value;
},
set:function(newValue){ //赋值
this.$emit('input', newValue)
}
}
},
methods: {
onResize(rect) {
// 给底下元素加宽度百分百
if (rect.width > 600) {
this.$el.classList.add('restrictWidth');
this.$el.classList.remove('noWidth');
} else {
this.$el.classList.add('noWidth');
this.$el.classList.remove('restrictWidth');
}
},
// 初始化
onCreated(editor) {
this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
this.$nextTick(() => {
// console.log(this.editor)
})
},
onFocus() {
},
// 编辑器变化
onChange(editor) {
// console.log("onChange", editor.getHtml()); // onChange 时获取编辑器最新内容
if (this.row) {
// 使用正则表达式匹配img标签并添加style属性 设置宽度100%
const regex = /<img([^>]*)>/g;
let richText = editor.getHtml().replace(regex, '<img$1 style="white-space: pre-wrap; word-break: break-all; width: 100% ">')
this.row[this.col.key] = richText
}
const demoElements = document.querySelectorAll('.w-e-image-container');
demoElements.forEach(function(element) {
element.style.width = '100%';
});
},
// 获取编辑区的文本
getContent() {
const editor = this.editor;
if (editor == null) return;
// console.log(editor.getText()); // 执行 editor API
},
// 获取编辑区的html
printEditorHtml() {
const editor = this.editor;
if (editor == null) return;
return editor.getHtml()
},
// 替换编辑区的文本
setContent(content) {
const editor = this.editor;
if (editor == null) return;
editor.setHtml(content)
},
// 上传
async upload(files) {
this.files = files;
let notification = this.$notify({
message: '<span>正在上传' + this.percent + '%</span>',
dangerouslyUseHTMLString: true,
duration: 0
});
return new Promise((resolve, reject) => {
// 集成分片上传sdk
let observable = window.qiniu.upload(files, files.name, this.token, this.config, this.putExtra)
observable.subscribe({
next: (result) => {
// 主要用来展示进度
if (notification) {
notification.message = '<i class="el-icon-loading"></i><span>正在上传' + Math.floor(result.total.percent) + '%</span>'
}
},
error: (errResult) => {
if(errResult.error && errResult.error == 'bad auth'){
notification.close()
this.$store.dispatch('getQiniuToken')
this.upload(this.files)
}else {
notification.close()
this.$notify({
type: 'error',
message: '上传失败',
});
}
},
complete: (result) => {
// 接收成功后返回的信息
notification.close()
resolve(result.data.url)
}
})
})
},
},
mounted() {
this.$store.dispatch('getQiniuToken').then(()=>{
this.onCreated()
})
},
beforeDestroy() {
const editor = this.editor
if (editor == null) return
editor.destroy() // 组件销毁时,及时销毁编辑器
}
}
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style >
.restrictWidth .w-e-text-container {
width: 40.4rem;
min-height: 100px;
margin: auto;
padding-bottom: 0.5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
}
.noWidth .w-e-text-container {
width: 100%;
/* min-height: 30px; */
margin: auto;
padding-bottom: 0.5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
}
/* 将图片百分比大小控制去除 */
.w-e-bar > .w-e-bar-item:first-child,
.w-e-bar > .w-e-bar-item:nth-child(2),
.w-e-bar > .w-e-bar-item:nth-child(3) {
display: none;
}
.w-e-toolbar > .w-e-bar-item:first-child,
.w-e-toolbar > .w-e-bar-item:nth-child(2),
.w-e-toolbar > .w-e-bar-item:nth-child(3) {
display: block;
}
/* 取消图片可变化大小 */
.w-e-image-dragger {
display: none;
}
/* 视频宽度100%,并消除间隙 */
.w-e-textarea-video-container > video {
width: 100%;
vertical-align: top;
}
/* 去除内边距 */
.w-e-textarea-video-container {
padding: 0;
}
/* 去除图片自带底部间隙4px */
.w-e-selected-image-container > img {
vertical-align: top;
}
/* 多个富文本组件同时存在时,让当前富文本最大化时保持在最顶层 */
.w-e-full-screen-container {
z-index: 9999999999;
}
.w-e-full-screen-container #editor {
background-color: #fff;
}
</style>
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献6条内容
所有评论(0)