vue中wangEditor5编辑器的基本使用

目录
  • 一、wangEditor5是什么
  • 二、wangEditor5基本使用
    • (一)、安装
    • (二)、编译器引入
    • (三)、css及变量引入
  • 三、wangEditor5工具栏配置
    • (一)、editor.getAllMenuKeys()
    • (二)、toolbarConfig中的excludeKeys
  • 四、wangEditor5上传图片
  • 五、wangEditor5的一些问题收集及解决
  • 六、完整代码
  • 总结

一、wangEditor5是什么

wangEditor是一款富文本编译器插件,其他的我就不再过多赘述,因为官网上有一大截对于这个编译器的介绍,但我摸索使用的这两天里给我的最直观的感受就是,它是由中国开发者开发,所有的文档都是中文的,这一点上对我这个菜鸡来说非常友好,不用再去逐字逐句翻译,然后去读那些蹩脚的机翻中文。而且功能很丰富,能够满足很多需求,wangEditor5提供很多版本的代码,vue2,vue3,react都支持。

接下来就介绍一下wangEditor5的基本使用,以及博主在使用中遇到的各种问题以及其解决方案。

官方网站:

wangEditor开源 Web 富文本编辑器,开箱即用,配置简单https://www.wangeditor.com/

二、wangEditor5基本使用

(一)、安装

yarn add @wangeditor/editor-for-vue
# 或者 npm install @wangeditor/editor-for-vue --save

(二)、编译器引入

import { Editor, Toolbar } from '@wangeditor/editor-for-vue';

Editor:引入@wangEditor编译器

Toolbar:引入菜单栏

(三)、css及变量引入

<style src="@wangeditor/editor/dist/css/style.css" >

</style>

这里需要注意,引入的样式写在带有scoped标签的style内无效。只能引入在全局样式里,但可能会造成样式覆盖,一般会有个清除样式的文件,会把里面的样式覆盖掉。

三、wangEditor5工具栏配置

工具栏配置有很多选项,这里以官方为主,我只做一些常用的配置介绍。

(一)、editor.getAllMenuKeys()

查询编辑器注册的所有菜单 key (可能有的不在工具栏上)这里注意要在

    onCreated(editor) {
            this.editor = Object.seal(editor)
        },

这个函数中去调用 (这个函数是基本配置之一),不然好像调不出来,当然也有可能是博主太菜。

(二)、toolbarConfig中的excludeKeys

toolbarConfig: {
        excludeKeys:["uploadVideo","fullScreen","emotion","insertTable"]
       },

这个是菜单栏配置的一种:排除某项配置 ,这里填写的key值就是用上面那个方法,查出来的key值。

四、wangEditor5上传图片

首先在data中return以下信息。

editorConfig: {
        placeholder: '请输入内容...' ,
        MENU_CONF: {
					uploadImage: {
						customUpload: this.uploadImg,
					},
				}
      },

然后书写this.uploadImg函数。

 uploadImg(file, insertFn){
      let imgData = new FormData();
			imgData.append('file', file);
      axios({
        url: this.uploadConfig.api,
        method: 'post',
        data: imgData,
      }).then((response) => {
       insertFn(response.data.FileURL);
      });
    },

注意,这里因为返回的数据结构与@wangeditor要求的不一致,因此要使用 insertFn 函数 去包裹返回的url地址。

五、wangEditor5的一些问题收集及解决

(一)、引入@wangEditor 编译报错 " Module parse failed: Unexpected token (12828:18)You may need an appropriate loader to handle this file type."

解决方法:在 wwebpack.base.conf.js 文件的module>rules>.js 的include下加入

resolve('node_modules/@wangeditor')

就可以了。

(二)、@wangeditor有序列表无序列表的样式消失问题。

大概率是全局样式清除导致的样式消失,可以去调试工具里看一看,样式覆盖的问题。

然后在style里deep一下改变样式就行了。

.editorStyle{
  /deep/ .w-e-text-container>.w-e-scroll>div ol li{
    list-style: auto ;
  }
  /deep/ .w-e-text-container>.w-e-scroll>div ul li{
    list-style: disc ;
  }
  /deep/ .w-e-text-placeholder{
    top:7px;
  }

}

六、完整代码

<template>
  <div v-loading="Loading" class="app_detail">
    <el-form ref="form" :rules="rules" :model="appDetail" label-width="80px">
      <el-form-item prop="name" label="应用名称">
        <el-input v-model="appDetail.name" style="width: 360px"></el-input>
      </el-form-item>
      <el-form-item label="分类">
        <el-select
          v-model="appDetail.appClassificationID"
          style="width: 360px"
          placeholder="选择应用分类"
        >
          <template v-for="item in classes">
            <el-option
              v-if="item.parentAppClassificationID"
              :key="item.appClassificationID"
              :label="item.appClassificationName"
              :value="item.appClassificationID"
            ></el-option>
          </template>
        </el-select>
        <div class="inputdesc">为了适应前台展示,应用只能属于二级分类</div>
      </el-form-item>
      <el-form-item label="所属组织">
        <el-select
          v-model="appDetail.orgID"
          placeholder="请选择所属组织"
          style="width: 360px"
        >
          <el-option
            v-for="item in myorgs"
            :key="item.orgID"
            :label="item.name"
            :value="item.orgID"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item prop="tags" label="标签">
        <el-select
          v-model="appDetail.tags"
          multiple
          filterable
          style="width: 360px"
          placeholder="请输入或选择应用标签"
        >
          <el-option
            v-for="item in existTags"
            :key="item"
            :label="item"
            :value="item"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-row>
        <el-col :span="8" class="appsFrom">
          <el-form-item
            label="应用Logo"
            ref="uploadpic"
            class="el-form-item-cen"
            prop="logo"
          >
            <el-upload
              class="avatar-uploader"
              :action="uploadConfig.api"
              :with-credentials="true"
              :headers="uploadConfig.headers"
              :show-file-list="false"
              :on-success="handleAvatarSuccess"
              :on-error="handleAvatarError"
              :before-upload="beforeAvatarUpload"
            >
              <img v-if="appDetail.logo" :src="appDetail.logo" class="avatar" />
              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
              <i
                v-if="appDetail.logo"
                class="el-icon-delete"
                @click.stop="() => handleRemove()"
              ></i>
            </el-upload>
            <span style="color: #999999; font-size: 12px">
              建议上传 100*100 比例的Logo
            </span>
          </el-form-item>
        </el-col>
      </el-row>
      <el-form-item prop="desc" label="应用简介">
        <el-input
          type="textarea"
          v-model="appDetail.desc"
          :rows="3"
          style="width: 360px"
        ></el-input>
      </el-form-item>
      <el-form-item prop="introduction" label="应用详情">
        <div style="border: 1px solid #ccc; ">
        <Toolbar
            style="border-bottom: 1px solid #ccc"
            :editor="editor"
            :defaultConfig="toolbarConfig"
            :mode="mode"
            class="barStyle"
        />
        <Editor
            style="height: 500px; overflow-y: hidden;"
            v-model="appDetail.introduction"
            :defaultConfig="editorConfig"
            :mode="mode"
            @onCreated="onCreated"
            class="editorStyle"
        />
    </div>
      </el-form-item>
    </el-form>
    <el-button
      class="save_btn"
      type="primary"
      @click="onSubmit"
      :loading="commitLoading"
      >保存</el-button
    >
  </div>
</template>

<script>
import { updateApp } from '@/api/app';
import { getStoreAvailableTags } from '@/api/appStore';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import { errorHandle } from '../../../../utils/error';
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { IToolbarConfig, DomEditor, IEditorConfig } from '@wangeditor/editor'
export default {
  name: 'BasicInfo',
  components: { Editor, Toolbar },
  props: {
    appDetail: {
      type: Object
    },
    marketID: {
      type: String
    },
    Loading: Boolean
  },
  data() {
    var baseDomain = process.env.BASE_API;
    if (baseDomain == '/') {
      baseDomain = window.location.origin;
    }
    const isChinese = (temp) => {
      return /^[\u4e00-\u9fa5]+$/i.test(temp);
    };
    const tagValidate = (rule, value, callback) => {
      let checked = true;
      value.map((tag) => {
        if (tag.length < 2) {
          callback('每个标签至少两个字符');
          checked = false;
          return;
        }
        if (isChinese(tag) && tag.length > 5) {
          callback('中文标签字数应处于2-5个之间');
          checked = false;
          return;
        }
        if (Number(tag) > 0) {
          callback('标签不能为纯数字组成');
          checked = false;
          return;
        }
      });
      if (checked) {
        callback();
      }
    };
    return {
      editor: null,
      toolbarConfig: {
        excludeKeys:["uploadVideo","fullScreen","emotion","insertTable"]
       },
      editorConfig: {
        placeholder: '请输入内容...' ,
        MENU_CONF: {
					uploadImage: {
						customUpload: this.uploadImg,
					},
				}
      },
      mode: 'default', // or 'simple'
      commitLoading: false,
      classes: [],
      existTags: [],
      appPublishTypes: [
        {
          value: 'public',
          label: '免费公开'
        },
        {
          value: 'integral',
          label: '金额销售'
        },
        {
          value: 'private',
          label: '私有'
        },
        {
          value: 'show',
          label: '展览'
        }
      ],
      uploadConfig: {
        api: `${baseDomain}/app-server/uploads/picture`,
        headers: {
          Authorization: getToken()
        },
      },
      editorOption: {},
      rules: {
        name: [
          { required: true, message: '应用名称不能为空', trigger: 'blur' },
          { min: 2, message: '至少两个字符', trigger: 'blur' },
          { max: 24, message: '应用名称建议不超过24个字符', trigger: 'blur' }
        ],
        desc: [
          { required: true, message: '应用简介不能为空', trigger: 'blur' },
          { min: 10, message: '至少10个字符', trigger: 'blur' },
          { max: 82, message: '描述最多82个字符', trigger: 'blur' }
        ],
        introduction: [
          { max: 10140, message: '描述最多10240个字符', trigger: 'blur' }
        ],
        tags: [{ validator: tagValidate, trigger: 'change' }]
      }
    };
  },
  created() {
    this.fetchStoreAppClassList();
    this.fetchStoreAppTags();
  },
  computed: {
    myorgs() {
      return this.$store.state.user.userOrgs;
    }
  },

  methods: {
    uploadImg(file, insertFn){
      let imgData = new FormData();
			imgData.append('file', file);
      axios({
        url: this.uploadConfig.api,
        method: 'post',
        data: imgData,
      }).then((response) => {
       insertFn(response.data.FileURL);
      });
    },
    onCreated(editor) {
            this.editor = Object.seal(editor)
        },
    fetchStoreAppTags() {
      getStoreAvailableTags({
        marketID: this.marketID,
        size: -1
      })
        .then((res) => {
          if (res && res.tags) {
            const tags = [];
            res.tags.map((item) => {
              tags.push(item.name);
            });
            this.existTags = tags;
          }
        })
        .catch((err) => {
          this.Loading = false;
        });
    },
    fetchStoreAppClassList() {
      this.$store
        .dispatch('GetStoreAppClassificationList', {
          marketID: this.marketID,
          disableTree: true
        })
        .then((res) => {
          if (res) {
            this.classes = res;
          }
        })
        .catch(() => {});
    },
    fetchUserOrgs() {
      this.$store
        .dispatch('GetUserOrgList')
        .then((res) => {
          if (res) {
            this.myorgs = res;
          }
        })
        .catch(() => {});
    },
    markdownContentUpdate(md, render) {
      this.appData.introduction_html = render;
    },
    markdownImgAdd(pos, $file) {
      // 第一步.将图片上传到服务器.
      var formdata = new FormData();
      formdata.append('file', $file);
      axios({
        url: this.api,
        method: 'post',
        data: formdata,
        headers: this.Token
      }).then((re) => {
        if (re && re.data && re.data.data) {
          this.$refs.md.$img2Url(pos, re.data.data);
        }
      });
    },
    handleAvatarSuccess(res, file) {
      this.appDetail.logo = res.FileURL;
    },
    handleAvatarError(re) {
      if (re.code == 10024) {
        this.$message.warning(
          '上传图片类型不支持,请上传以.png .jpg .jpeg 结尾的图片'
        );
        return;
      }
      this.$message.warning('上传失败!');
    },
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg';
      const isPng = file.type === 'image/png';
      const isLt2M = file.size / 1024 / 1024 < 2;

      if (!isJPG && !isPng) {
        this.$message.warning('上传Logo图片只能是JPG、PNG格式!');
      }
      if (!isLt2M) {
        this.$message.warning('上传头像图片大小不能超过 2MB!');
      }
      return (isJPG || isPng) && isLt2M;
    },
    handleRemove() {
      this.$confirm('是否删除logo', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.appDetail.logo = '';
      });
    },
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    changeSelectApp_type_id(value) {
      this.appData.app_type_id = value;
      this.$forceUpdate();
    },
    changeSelectPublish_type(value) {
      this.appData.publish_type = value;
      this.$forceUpdate();
    },
    onSubmit() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          this.commitLoading = true;
          this.$confirm('是否提交数据', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          })
            .then(() => {
              updateApp(this.appDetail)
                .then((res) => {
                  this.$message.success('应用信息更新成功');
                  this.commitLoading = false;
                })
                .catch((err) => {
                  errorHandle(err);
                  this.commitLoading = false;
                });
            })
            .catch(() => {
              this.commitLoading = false;
            });
        } else {
          return false;
        }
      });
    }
  }
};
</script>
<style lang="scss" scoped >
.app_detail {
  position: relative;
  padding-bottom: 20px;
  .save_btn {
    margin-left: 80px;

  }
  .el-select {
    width: 100%;
  }
}
.editorStyle{
  /deep/ .w-e-text-container>.w-e-scroll>div ol li{
    list-style: auto ;
  }
  /deep/ .w-e-text-container>.w-e-scroll>div ul li{
    list-style: disc ;
  }
  /deep/ .w-e-text-placeholder{
    top:7px;
  }

}
.barStyle{
  /deep/ .w-e-bar-item{
    padding:2.5px
  }
    /deep/ .w-e-bar-item > button >.title{
    border-left:0 !important;
  }
}
</style>
<style src="@wangeditor/editor/dist/css/style.css" >
.inputdesc {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.45);
  transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1);
}
.app_detail img {
  width: auto;
}
.app_detail .ql-formats {
  line-height: 22px;
}
</style>

总结

到此这篇关于vue中wangEditor5编辑器的基本使用的文章就介绍到这了,更多相关vue wangEditor5的使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 轻量级富文本编辑器wangEditor结合vue使用方法示例

    1.安装 使用npm下载: `npm install wangeditor` 2. 创建实例 (1)基本用法: <template> <div> <div id="editor" class="editor"></div> </div> </template> <script> import E from 'wangeditor' export default { name: 'ed

  • 在vue中获取wangeditor的html和text的操作

    目的:vue 中获取 wangeditor 的 html 和 text. 补充知识:vue-cli webpack 引入 wangeditor(轻量级富文本框) 1:使用npm下载: //(注意 wangeditor 全部是小写字母) npm install wangeditor 2: 直接在项目模板中引用 import E from 'wangeditor' 3:HTML <div id="editorElem" style="text-align:left"

  • Vue 中使用富文本编译器wangEditor3的方法

    富文本编译器在vue中的使用 在开发的过程中由于某些特殊需求,被我们使用,今天我就简单讲一讲如何在vue中使用wangEditor3 首先讲一下简单的使用. 1.使用npm安装 npm install wangeditor --save 2.vue页面代码如下 <template> <section> <div id="div5"></div> <div id="div6"></div> <

  • Vue中使用wangeditor富文本编辑的问题

    wangEditor是基于javascript和css开发的 Web富文本编辑器, 轻量.简洁.易用.开源免费. 在我们实际项目上还是比较频繁应用到的,下面出个案例供大家参考学习- wangEditor文档:https://www.wangeditor.com/ 富文本编辑器截图: <!--富文本编辑器.http://www.wangeditor.com/ 使用示例: <AppEditor v-model="content"></AppEditor> --

  • vue中wangEditor的使用及回显数据获取焦点的方法

    在做后台管理项目时常常会用到富文本编辑器,在这里推荐大家使用wangEditor,非常好用 第一步安装 npm i wangeditor --save 第二步在项目中使用 html 页面中的编辑.添加布局在最下面 <div id="div1"> <p>欢迎使用 <b>wangEditor</b> 富文本编辑器</p> </div> <el-button type="primary" @cl

  • vue中wangEditor5编辑器的基本使用

    目录 一.wangEditor5是什么 二.wangEditor5基本使用 (一).安装 (二).编译器引入 (三).css及变量引入 三.wangEditor5工具栏配置 (一).editor.getAllMenuKeys() (二).toolbarConfig中的excludeKeys 四.wangEditor5上传图片 五.wangEditor5的一些问题收集及解决 六.完整代码 总结 一.wangEditor5是什么 wangEditor是一款富文本编译器插件,其他的我就不再过多赘述,因

  • 浅谈vue中使用编辑器vue-quill-editor踩过的坑

    结合vue+element-ui+vue-quill+editor二次封装成组件 1.图片上传 分析原因 项目中使用vue-quill-editor富文本编辑器,在编辑内容的时候,我们往往会编辑图片,而vue-quill-editor默认的处理方式是直接将图片转成base64格式,导致上传的内容十分庞大,且服务器接受post的数据的大小是有限制的,很有可能就提交失败,造成用户体验差. 引入element-ui 编辑editor.vue文件 <template> <div> <

  • vue中使用ueditor富文本编辑器

    最近在做后台管理系统的时候遇到要使用富文本编辑器.最后选择了ueditor,我的项目使用 vue+vuex+vue-router+webpack+elementUI的方案完成框架的搭建, 1.下载UEditor官网最新的jsp版本的包,下载完成解压之后得到一个utf8-jsp的文件夹,里面包含的内容如下: 2.将这个文件夹改名为ueditor,并且移入自己项目中的static文件夹下,修改ueditor.config.js文件夹中的内容,如下图: 3.编写子组件 <template> <

  • 关于在vue 中使用百度ueEditor编辑器的方法实例代码

    1. 安装  npm i vue-ueditor --save-dev 2.从nodemodels  取出ueditor1_4_3_3 这整个目录,放入vue 的 static 目录 3.配置 ueditor.config.js 的  21行代码  更改路径   var URL = '/static/ueditor1_4_3_3/' || getUEBasePath();  (1)     serverUrl: URL + 'php/controller.php',  这里是你配置的上传内容的

  • vue中利用simplemde实现markdown编辑器(增加图片上传功能)

    前言 最近在搭个人博客网站,需要一个 markdown 编辑器,来进行博客的编写 看了网上的教程,决定使用 simplemde 以为可以直接能拿来用的 不过实际运用的时候发现还是有要完善的地方 比如令人头疼的图片上传 最终效果 安装及初始化 npm install simplemde --save 在html中加入一个textarea <textarea id="simplemde"></textarea> 在vue的生命周期函数 mounted 中,添加 si

  • 如何在vue中使用kindeditor富文本编辑器

    第一步,下载依赖 yarn add kindeditor 第二步,建立kindeditor.vue组件 <template> <div class="kindeditor"> <textarea :id="id" name="content" v-model="outContent"></textarea> </div> </template> <s

  • vue中如何创建多个ueditor实例教程

    前言 前一段时间公司Vue.js项目需要使用UEditor富文本编辑器,在百度上搜索一圈没有发现详细的说明,决定自己尝试,忙活了一天终于搞定了. 具体可以参考这篇文章:http://www.jb51.net/article/118413.htm ueditor是百度编辑器,官网地址:http://ueditor.baidu.com/website/ 完整的功能演示,可以参考:http://ueditor.baidu.com/website/onlinedemo.html 最近工作中要求升级,需要

  • vue中typescript装饰器的使用方法超实用教程

    VueConf ,尤大说, Vue 支持 Ts 了,网上关于 Vue + Ts 的资料有点少, 楼主踩了一个星期坑,终于摸明白了 修饰器 的玩法,下面我们就来玩下 Vue 的 decorator 吧 1,data 值的声明 在这里 public 声明的是公有属性, private 声明的是私有属性,私有属性要带 下划线 蓝色框里的内容是声明组件,在每个组件创建时都要带上, Components 中的写法如下 上面是 普通写法 ,下面是 懒加载写法 2.@Prop 父组件传值给子组件 父组件使用

  • vue中实现Monaco Editor自定义提示功能

    这次接到一个需求,要在浏览器的 IDE 中支持自定义提示功能,如下所示: 可以看到,它可以根据用户输入的内容来一项一项排除,只显示完全匹配的那一项. 项目的框架是 Vue ,编辑器用的是 Monaco Editor . 什么是 Monaco Editor vscode 是我们经常在用的编辑器,它的前身是微软的一个叫 Monaco Workbench 的项目,而 Monaco Editor 就是从这个项目中成长出来的一个 web 编辑器,他们很大一部分的代码都是共用的,所以 Monaco Edit

  • 在vue中解决提示警告 for循环报错的方法

    警告 1.出现这个警告问题的时候 我们可以去main.js中在头部添加这句话: Vue.config.productionTip = false 这样即可去除警告! 2.在build文件下的webpack.base.conf.js文件中, 将 ...(config.dev.useEslint ? [createLintingRule()] : []),注释掉, const createLintingRule = () => ({ test: /\.(js|vue)$/, loader: 'esl

随机推荐