目录

一、wangEditor5是什么

二、wangEditor5基本使用

(一)、安装

(二)、编译器引入

(三)、css及变量引入

三、wangEditor5工具栏配置

(一)、editor.getAllMenuKeys()

(二)、toolbarConfig中的excludeKeys

四、wangEditor5上传图片

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

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

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


一、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及变量引入

这里需要注意,引入的样式写在带有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;  }  }

六、完整代码

                                                                                        为了适应前台展示,应用只能属于二级分类                                                                                                                                                                 handleRemove()"              >                                      建议上传 100*100 比例的Logo                                                                                                        保存  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  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.https://blog.csdn.net/qq_45799465/article/details/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  {        this.https://blog.csdn.net/qq_45799465/article/details/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;        }      });    }  }};.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;  }}.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;}