vue使用froala-editor富文本编辑器

在项目需要用到富文本编辑器时,自己也筛选过不少插件,最终选择了froala-editor,UI简单功能强大,官网也列出了很多国外大佬在使用,自己实战后确实感觉比其他的富文本编辑器好。

官网:https://froala.com/

1、安装

1
2
npm install font-awesome --save //安装font-awesome
npm i vue-froala-wysiwyg -S;//样式失效重新安装

2、引入

main.js 或者写在其他js文件再从main.js引入

1
2
3
4
5
6
7
8
9
10
import Vue from "vue";

import "froala-editor/css/froala_editor.pkgd.min.css";
import "froala-editor/css/froala_style.min.css";
import "froala-editor/js/froala_editor.pkgd.min.js";
import "froala-editor/js/languages/zh_cn.js";
import "froala-editor/js/plugins.pkgd.min.js";
import VueFroala from "vue-froala-wysiwyg";

Vue.use(VueFroala); //样式失效重新安装 npm i vue-froala-wysiwyg -S;

3、使用

1.新建froalaEditor.vue文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
<template>
  <div class="editor-wrap">
    <froala
      id="froala-editor"
      :tag="'textarea'"
      :config="config"
      v-model="body.content"
    />
  </div>
</template>
<script>
const tool = [
  "undo",
  "redo",
  "clearFormatting",
  "bold",
  "italic",
  "underline",
  "strikeThrough",
  "fontFamily",
  "fontSize",
  "textColor",
  "color",
  "backgroundColor",
  "inlineStyle",
  "paragraphFormat",
  "align",
  "formatOL",
  "formatUL",
  "outdent",
  "indent",
  "quote",
  "insertLink",
  "insertImage",
  "insertVideo",
  "embedly",
  "insertFile",
  "insertTable",
  "emoticons",
  "specialCharacters",
  "insertHR",
  "selectAll",
  "print",
  "spellChecker",
  "html",
  "help",
  "fullscreen"
];

export default {
  props: {
    // 显示的工具列表
    placeholder: {
      type: String
      //   required: true
    },
    height: {
      type: Number
    },
    value: {
      type: String,
      default: null
    },
    index: {
      type: Number,
      default: 1
    }
  },
  name: "froala-editor",
  data() {
    const that = this;
    return {
      editor: null,
      uploadImage: {
        loading: false,
        previewVisible: false,
        previewImage: "",
        imgFile: {},
        isSize: false,
        isType: false
      },
      fileList: [],
      body: {
        content: null,
        textLen: 0,
        leftoverLen: 10000,
        sumLen: 10000,
        error_tip: "",
        error_show: false
      },
      config: {
        toolbarButtons: tool,
        // theme: "dark",//主题
        placeholderText: this.placeholder || "编辑课程介绍",
        language: "zh_cn", //国际化
        imageUploadURL: "", //上传url
        imageUploadParams: { token: "", i: "", ak: "", f: 9 },
        fileUploadURL: "",
        fileUploadParams: { token: "", i: "", ak: "", f: 9 },
        videoUploadURL: "",
        videoUploadParams: { token: "", i: "", ak: "", f: 9 },
        quickInsertButtons: ["image", "table", "ul", "ol", "hr"], //快速插入项
        // toolbarVisibleWithoutSelection: true,//是否开启 不选中模式
        // disableRightClick: true,//是否屏蔽右击
        colorsHEXInput: true, //关闭16进制色值
        toolbarSticky: false, //操作栏是否自动吸顶,
        // Colors list.
        colorsBackground: [
          "#15E67F",
          "#E3DE8C",
          "#D8A076",
          "#D83762",
          "#76B6D8",
          "REMOVE",
          "#1C7A90",
          "#249CB8",
          "#4ABED9",
          "#FBD75B",
          "#FBE571",
          "#FFFFFF"
        ],
        colorsStep: 6,
        colorsText: [
          "#15E67F",
          "#E3DE8C",
          "#D8A076",
          "#D83762",
          "#76B6D8",
          "REMOVE",
          "#1C7A90",
          "#249CB8",
          "#4ABED9",
          "#FBD75B",
          "#FBE571",
          "#FFFFFF"
        ],
        zIndex: 2501,
        height: this.height || "250",
        // autofocus: true,
        events: {
          initialized: function() {
            that.editor = this;
            that.body.content = that.value;
            that.EditorChange();
          },
          blur: () => {
            console.log("blur....");
            that.$emit("blur");
          },
          contentChanged: () => {
            that.EditorChange();
          },
          "image.beforeUpload": function(images) {
            //自定义上传图片
            that.beforeUpload(images[0]);
            return false;
          },
          "file.beforeUpload": function() {
            // Image was uploaded to the server.
            return true;
          },
          "video.beforeUpload": function() {
            // Image was uploaded to the server.
            return true;
          }
        }
      }
    };
  },
  watch: {
    value: {
      handler: function(news, old) {
        if (news) {
          this.body.content = this.value;
        }
      },
      deep: true //对象内部的属性监听,也叫深度监听
    },
    "body.content": function(newVal, old) {
      if (old !== newVal) {
        let val = this.getSimpleText(this.editor.html.get(true));
      }
    },
    label: function(newVal, old) {
      if (old !== newVal) {
        this.editor.html.set(newVal);
      }
    }
  },
  mounted() {
    setTimeout(() => {
      this.setIndex(this.index);
    }, 200);
  },
  methods: {
    //更改富文本层级
    setIndex(val) {
      this.$nextTick(() => {
        let dv = document.getElementsByClassName("fr-box");
        for (let i in dv) {
          if (!dv[i].style) {
            return;
          }
          dv[i].style.cssText = "z-index:" + val;
        }
      });
    },
    //富文本中提取纯文本
    getSimpleText: html => {
      var re1 = new RegExp('<p data-f-id="pbf".+?</p>', "g"); //匹配html标签的正则表达式,"g"是搜索匹配多个符合的内容
      var msg = html.replace(re1, ""); //执行替换成空字符
      return msg;
    },
    EditorChange() {
      if (this.editor == null) return;
      console.log(this.editor, "this.editor");
      const editorCount = this.editor.charCounter.count();
      this.body.textLen = editorCount;
      this.body.leftoverLen = this.body.sumLen - editorCount;
      this.$emit("change", this.body);
    },
    beforeUpload(file) {
        const that = this;
        this.uploadImage.loading = true;
        const formData = new FormData();
        formData.append("formFile", file);
        this.$store
          .dispatch("UploadImg", formData)
          .then(res => {
            this.uploadImage.loading = false;
            if (res.code === 200) {
              that.uploadImage.imgFile = JSON.parse(res.data);
              const url = that.uploadImage.imgFile.data;
              //插入图片
              that.editor.html.insert(
                "<img src=" + that.uploadImage.imgFile.data + ">", //HTML
                false //在插入之前是否应清除HTML
              ); //插入图片
            } else {
              this.fileList = [];
              this.$message.error(res.msg);
            }
          })
          .catch(err => {
            this.uploadImage.loading = false;
            this.$message.error("上传失败");
          });
      }

      return false;
    }
  }
};
</script>
<style>

.editor-wrap > div {
  width: 100%;
}

.fr-wrapper > div[style*="z-index:9999;"],
.fr-wrapper > div[style*="z-index: 9999;"] {
  height: 0;
  overflow: hidden;
  position: absolute;
  top: -1000000px;
  opacity: 0;
}
.fr-view{
  position: absolute;
  top: 0;
}
.fr-placeholder{
  margin-top: 0;
}
.fr-box .second-toolbar {
  display: none;
}

.fr-box .second-toolbar #logo {
  width: 0 !important;
  height: 0 !important;
  overflow: hidden;
}
.fr-box .fr-toolbar {
  border-radius: 4px 4px 0 0;
  border-color: #dcdfe6;
}
.fr-box .second-toolbar {
  border-radius: 0 0 4px 4px;
  border-color: #dcdfe6;
}
.fr-box .fr-wrapper {
  border-color: #dcdfe6 !important;
}
</style>

2.自定义上传图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 config: {
    events: {
        "image.beforeUpload": function(images) {
            //自定义上传图片
            that.beforeUpload(images[0]);
            return false;
         },
     }
 }

  //上传成功后插入图片
  that.editor.html.insert(
       "<img src=" + that.uploadImage.imgFile.data + ">", //HTML
    false //在插入之前是否应清除HTML
  ); //插入图片

3.小坑
该编辑器属于付费使用,不付费默认会带上他的标语,所以保存内容的时候要过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import froalaEditor from "@/components/froalaEditor.vue";
export default {
  components: {
    froalaEditor,
  },
  data() {
    const that = this;
    return {
      editor: {
        p:
          '<p data-f-id="pbf" style="text-align: center; font-size: 14px; margin-top: 30px; opacity: 0.65; font-family: sans-serif;">Powered by <a href="https://www.froala.com/wysiwyg-editor?pb=1" title="Froala Editor">Froala Editor</a></p>',
      }
   }
 }
}

if (newData.seriesDetail.indexOf(this.editor.p) > -1) {
    newData.seriesDetail = newData.seriesDetail.replace(
     this.editor.p,
      ""
      );
 }

4.官网文档
https://froala.com/wysiwyg-editor/docs/framework-plugins/vue/#model

3、效果

富文本编辑器.png

总结

用了这个富文本编辑器后,感觉我很嫌弃以前用过的编辑器,哈哈,还有,我添加了自定义上传图片的案例,小伙伴们可以按照自己的实际情况来修改,上传视频的话也是如此。拜拜

——By kkc_hq