文档章节

vue学习笔记5:vue富文本编辑器ueditor的组件封装及问题

Jack088
 Jack088
发布于 09/20 18:44
字数 1906
阅读 9
收藏 0

做一个后台,离不开文本编辑器,百度的ueditor经常用,这次改用vue写后台,需要再次集成一下,遇到很多问题,搞了一下午,整理一下,希望能够帮到后来者。

目标:

希望封装的ueditor组件,尽可能简单,期望是这样的,能够像input一样简单,可以实现v-mode

1

<ueditor v-model="content"></ueditor>

实现

复制ueditor文件

将下载的ueditor放到static/lib路径下面 ,这个位置随意,根据自己情况更改;后台相关的代码可以删除,交由后台同学处理,因为我们现在用vue是前后台分离的,所以不需要后台代码

image.png

更改配置文件

更改ueditor.config.js,

1

2

3

4

5

6

var URL = window.UEDITOR_HOME_URL || getUEBasePath();

改为

var URL ="/static/lib/ueditor/"   

 

也就是我们的ueditor路径,如果不这么改,你可能会看到如下报错

 

Uncaught SyntaxError: Unexpected token <

ZeroClipboard.js:1 Uncaught SyntaxError: Unexpected token <

ueditor.all.js?9bdc:14409 Uncaught ReferenceError: ZeroClipboard is not defined

    at initZeroClipboard (ueditor.all.js?9bdc:14409)

    at eval (ueditor.all.js?9bdc:14456)

    at HTMLScriptElement.element.onload.element.onreadystatechange (ueditor.all.js?9bdc:921)

 

更改服务器接口地址,因为我们是前后台分离,所以之前的接口地址就不对了,要改成自己的真实接口地址

1

2

3

, serverUrl: process.env.API_ROOT + "/ueditor/php/controller.php"

//我的接口地址dev环境和build不一样,当然,你也可以采取绝对地址

, serverUrl: "http://***.com/ueditor/php/controller.php"

没改正确报错

请求后台配置项http错误,上传功能将不能正常使用!

 

组件封装

新建一个Ueditor.vue文件,其中data中的editor为编辑器实例,为了实现v-mode功能,我们需要一个名为value属性,还需要在编辑器内容功能时,触发input事件,编辑器内容变化通过contentChange事件监听

另一个props属性为config,我们可以通过这个修改编辑器的样式等,此处给了一个默认值,高度350px

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

<template>

  <div class="ueditor">

    <script id="editor" type="text/plain"></script>

  </div>

</template>

<script>

 import  '../../../static/lib/ueditor/ueditor.config'

 import  '../../../static/lib/ueditor/ueditor.all'

 import  '../../../static/lib/ueditor/lang/zh-cn/zh-cn'

 import  '../../../static/lib/ueditor/ueditor.parse'

 

 export default {

    name:'Ueditor',

 data:function () {

      return{

        editor:''

 }

    },

 props: {

      config: {

        type: Object,

 default:function () {

          return  {

            initialFrameWidth: null,

 initialFrameHeight: 350

 }

        }

      },

 value:String

 

 },

 mounted:function () {

      this.editor=UE.getEditor("editor",this.config)

      this.editor.addListener("ready", ()=>{

        this.editor.setContent(this.value); // 确保UE加载完成后,放入内容。

 

 this.editor.addListener("contentChange",()=>{

          this.$emit('input',this.editor.getContent())   //内容发生变化,触发input事件,此处是为了实现v-mode功能

        })

      });

 },

 methods: {

      getUEContent:function() {

        return this.editor.getContent()

      }

    },

 destroyed: function() {

      this.editor.destroy();

 },

 }

</script>

<style lang="less">

 

</style>

注意上面的destroyed事件是必须的,如果没有这段代码,你会发现,页面刷新的适合能够看到编辑器,此后如果通过点击返回,或者通过router跳转,再回到编辑器页面,发现编辑器消失了

在编辑页面使用Ueditor组件

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

<template>

  <div>

    <form class="form-horizontal form-edit">

          //其他代码       

          <ueditor v-model="content"></ueditor>

  

          //其他代码      

    </form>

  </div>

</template>

 

<script>

  

 import Ueditor from "../../components/mod/Ueditor"

 

 

 export default {

    name: 'NewsEdit',

 components: {Ueditor},

 

 data:function () {

      return {

content:'测试内容'

         

    },

  

  }

}

</script>

如果不出意外,现在你的编辑器已经可以正常工作了

image.png

 

图片上传

编辑器离不了图片上传,而现在图片上传还是不行的,会发现有错误提示(后台上传接口要先搞好)

提示跨域问题,图片上传这里,百度用的form表单的提交,我们把它改成通过ajax提交就好了

DOMException: Blocked a frame with origin "http://127.0.0.1:8080" from accessing a cross-origin frame.

    at HTMLIFrameElement.callback (webpack-internal:///./static/lib/ueditor/ueditor.all.js:24482:84)

 

此处改动较大,改动ueditor.all.js中 domUtils.on(input, 'change', function(){})中的内容

改动前

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

domUtils.on(input, 'change', function(){

    if(!input.value) return;

    var loadingId = 'loading_' + (+new Date()).toString(36);

    var params = utils.serializeParam(me.queryCommandValue('serverparam')) || '';

 

    var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'));

    var allowFiles = me.getOpt('imageAllowFiles');

 

    me.focus();

    me.execCommand('inserthtml''<img class="loadingclass" id="' + loadingId + '" src="' + me.options.themePath + me.options.theme +'/images/spacer.gif" title="' + (me.getLang('simpleupload.loading') || '') + '" >');

 

    function callback(){

 

        try{

            var link, json, loader,

                body = (iframe.contentDocument || iframe.contentWindow.document).body,

                result = body.innerText || body.textContent || '';

            json = (new Function("return " + result))();

            link = me.options.imageUrlPrefix + json.url;

            if(json.state == 'SUCCESS' && json.url) {

 

              console.log("上传成功了已经")

                loader = me.document.getElementById(loadingId);

                loader.setAttribute('src'link);

                loader.setAttribute('_src'link);

                loader.setAttribute('title', json.title || '');

                loader.setAttribute('alt', json.original || '');

                loader.removeAttribute('id');

                domUtils.removeClasses(loader, 'loadingclass');

            else {

                showErrorLoader && showErrorLoader(json.state);

            }

        }catch(er){

          console.log("上传失败了")

          console.log(er)

            showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError'));

        }

        form.reset();

        domUtils.un(iframe, 'load', callback);

    }

    function showErrorLoader(title){

        if(loadingId) {

            var loader = me.document.getElementById(loadingId);

            loader && domUtils.remove(loader);

            me.fireEvent('showmessage', {

                'id': loadingId,

                'content': title,

                'type''error',

                'timeout': 4000

            });

        }

    }

 

    /* 判断后端配置是否没有加载成功 */

    if (!me.getOpt('imageActionName')) {

        errorHandler(me.getLang('autoupload.errorLoadConfig'));

        return;

    }

    // 判断文件格式是否错误

    var filename = input.value,

        fileext = filename ? filename.substr(filename.lastIndexOf('.')):'';

    if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {

        showErrorLoader(me.getLang('simpleupload.exceedTypeError'));

        return;

    }

 

    domUtils.on(iframe, 'load', callback);

    form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params);

    form.submit();

     

    function showErrorLoader(title){

    if(loadingId) {

      var loader = me.document.getElementById(loadingId);

      loader && domUtils.remove(loader);

      me.fireEvent('showmessage', {

        'id': loadingId,

        'content': title,

        'type''error',

        'timeout': 4000

      });

    }

  }

});

改动后,使用的是原生的ajax上传

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

domUtils.on(input, 'change'function(){

 

  if(!input.value) return;

  var loadingId = 'loading_' + (+new Date()).toString(36);

  var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'));

  var allowFiles = me.getOpt('imageAllowFiles');

 

  me.focus();

  me.execCommand('inserthtml''<img class="loadingclass" id="' + loadingId + '" src="' + me.options.themePath + me.options.theme +'/images/spacer.gif" title="' + (me.getLang('simpleupload.loading') || '') + '" >');

 

  /!* 判断后端配置是否没有加载成功 *!/

  if (!me.getOpt('imageActionName')) {

    errorHandler(me.getLang('autoupload.errorLoadConfig'));

    return;

  }

  // 判断文件格式是否错误

  var filename = input.value,

    fileext = filename ? filename.substr(filename.lastIndexOf('.')):'';

  if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {

    showErrorLoader(me.getLang('simpleupload.exceedTypeError'));

    return;

  }

 

  var params = utils.serializeParam(me.queryCommandValue('serverparam')) || '';

  var action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?' '&') + params);

  var formData = new FormData();

  formData.append("file", form[0].files[0] );

 

 

  var xhr = null//得到xhr对象

  if(XMLHttpRequest){

    xhr = new XMLHttpRequest();

  }else{

    xhr = new ActiveXObject("Microsoft.XMLHTTP");

  }

 

  xhr.open("post", action, true);//设置提交方式,url,异步提交

  xhr.onload = function ()

  {

    var data = xhr.responseText;    //得到返回值

    data=JSON.parse(data)

 

    var link, loader,

      body = (iframe.contentDocument || iframe.contentWindow.document).body,

      result = body.innerText || body.textContent || '';

    link = me.options.imageUrlPrefix + data.url;

 

    if(data.state == 'SUCCESS' && data.url) {

      loader = me.document.getElementById(loadingId);

      loader.setAttribute('src', link);

      loader.setAttribute('_src', link);

      loader.setAttribute('title', data.title || '');

      loader.setAttribute('alt', data.original || '');

      loader.removeAttribute('id');

      domUtils.removeClasses(loader, 'loadingclass');

 

      me.fireEvent('contentchange')

    else {

      showErrorLoader && showErrorLoader(data.state);

    }

    form.reset();

 

 

  }

  xhr.send(formData);

 

 

 

  function showErrorLoader(title){

    if(loadingId) {

      var loader = me.document.getElementById(loadingId);

      loader && domUtils.remove(loader);

      me.fireEvent('showmessage', {

        'id': loadingId,

        'content': title,

        'type''error',

        'timeout': 4000

      });

    }

  }

});

 

最初,我是想用axios进行ajax操作的,在ueditor.all.js开头处加入了

1

import axios from 'axios'

结果发现,再次进入编辑器输入内容时,会有报错,如下,试了很多办法没用解决,搞了很长时间,虽然不影响上传,但是受不了代码有错误提示,最终换成上面的纯js的ajax上传图片,这个问题可能是因为通过import引入文件,强制改为了js严格模式

ueditor.all.js?9bdc:28636 Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them  at HTMLDocument.countFn (ueditor.all.js?9bdc:28636)

 

幸好,问题一个一个都被解决了,学习就是这样,会遇到很多困难,多console.log,找原因,找解决办法,一个一个测试,最终战胜困难

祝好

测试地址:http://cms.github.mooov.cn/

账号:test

密码:123456

github地址:https://github.com/501351981/vue_yii_cms

本文转载自:http://shanhuxueyuan.com/news/detail/65.html

Jack088
粉丝 46
博文 579
码字总数 90270
作品 0
扬州
程序员
私信 提问
Vue 中使用UEditor富文本编辑器-亲测可用-vue-ueditor-wrap

一、Vue中在使用Vue CLI开发中默认没法使用UEditor 其中UEditor中也存在不少错误,再引用过程中。 但是UEditor相对还是比较好用的一个富文本编辑器。 vue-ueditor-wrap说明 Vue + UEditor + ...

tianma3798
02/18
1K
0
Vue2如何配置webpack相关设置

一、Vue如何配置webpack相关 使用方式步骤如下: 1.根目录创建vue.config.js文件 2.修改对应的配置,重新运行项目 更多配置说明参考: https://cli.vuejs.org/zh/guide/webpack.html#审查项目...

tianma3798
02/21
39
0
vue中vuex,echarts,地图,ueditor的使用(一篇就够)

前言 vue-cli生成的template还需要配置axios,vuex,element等插件,该项目中将这些常用插件进行了配置; 项目开发中template可以快速复用,也是可以快速上手vue的一个demo; 1.动态效果图 2.技术栈...

大漠火狼
2018/06/11
0
0
vue2 编译错误"publicPath" is not allowed

一、Vue CLI编译错误 进行配置,npm run build报错: 二、解决方案: 将vuecli3升级至3.3.0即可 处理步骤: 1.修改package.json的插件版本 2.修改生成的相对目录 3.使用 npm install 重新安装...

tianma3798
02/21
390
0
ueditor图片上传方式处理

最近项目里需要用到富文本编辑器,同事选择里百度出的ueditor,但是里面自带的图片上传功能需要后台配合,配置成服务器地址,和我们实际情况不是太符合,于是另想办法,搞定图片上传。 重写配...

rocky191
09/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

常用正则表达式整理

本文转载于:专业的前端网站➩常用正则表达式整理 /*以下为亲自验证过,备用*/   数字,0-100,包含0和100,且小数点后最多有三位: /^(\d{1,2}(\.\d{1,3})?|100)$/ 匹配正整数:^[1-9]*[1-9][...

前端老手
11分钟前
4
0
Java 中可重入锁、不可重入锁的测试

Java 中可重入锁、不可重入锁的测试 可重入锁 指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁。 为了避免死锁的发生,JDK 中基本都是可重入锁。 下面我们来测试一下 sync...

ConstXiong
11分钟前
4
0
怎么给视频变音

怎么让录制视频中的声音变得可爱吗?其实方法非常的简单,只要进行视频变音制作就好了,那怎么给视频变音呢?下面就一起来看看视频变音的具体制作方法吧! 具体步骤如下: 第一步: 打开手机...

白米稀饭2019
15分钟前
3
0
学习记录(ECMAScript 6.0入门_day01重点总结)

课程目标 1、ECMAScript6和JAVAScript关系 ES6是JAVAScript的规格,JavaScript是ES6的一种实现。 变量声明: 局部变量:let 它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内...

庭前云落
27分钟前
3
0
springboot 源码SpringApplication的run方法解析

public ConfigurableApplicationContext run(String... args) {//记录启动应用启动时间StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationCo......

dudu
29分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部