Vue使用Tinymce富文本编辑器使用axios图片上传到服务器以及实时监测文本内容

Vue使用Tinymce富文本编辑器使用axios图片上传到服务器以及实时监测文本内容,第1张

Vue使用Tinymce富文本编辑器使用axios图片上传到服务器以及实时监测文本内容

简介
由于版本更新等问题,如果加载出的富文本为空白,很有可能是引用的问题,可以搜索此类问题在main.js里修改引用就可以了,程序的代码上是完全没有问题的。(2022-05-04更新)
查了好多资料忙了一天一夜,最后在群里靠别人解决了实时监测文本内容,百度太多坑了,资料不完整,说明不详细,没有完整代码,查得那叫一个辛苦,一个问题弄半天才明白,这篇文章我是从一个小白看文章的角度来写的,希望能给使用Tinymce这个富文本的小伙们一些帮助,但是希望看完自行去思考一些问题,不是过来复制粘贴就完了,看完对你有用,有赞点赞,没事评论评论,好歹以后遇到问题还能有个动力继续分享。

正文
下面这些是我使用的各种东西版本
@vue/cli 4.5.15
jdk 1.8
tinymce配置是将文件拷贝到本地使用的,我没有它的api,不知道的请自行百度安装

下面是我的项目结构目录,其实只用到了public/tinymce/langs/zh_CN.js(这个是tinymce富文本的中文包,需要请自己去下),src\components\tinymce\index_1.vue(这是构建tinymce的类),src\App.vue(这是调用进行在页面显示的类),src\main.js(全局配置些乱七八糟的东西),vue.config.js(也是配置的),介绍就到这里了。


如果遇到没有vue.config.js,自己安装cube-ui插件,不懂自己百度

首先,上传图片到自己服务器,需要用到的插件是axios,以及需要跨域,不懂什么是跨域自行百度,
安装好axios插件后,首先解决跨域问题

main.js里加上

import TinymceEditor from './components/tinymce';
import Axios from 'axios'
Vue.prototype.$axios = Axios //axios上传
Axios.defaults.baseURL = '/api' //跨域,将url转成/api

这是我vue.config.js的全部配置

const webpack = require('webpack')
module.exports = {
  configureWebpack: {
    plugins: [
        //添加jquery的依赖
      new webpack.ProvidePlugin({
        $:"jquery",
        jQuery:"jquery",
        "windows.jQuery":"jquery"
      })
    ]
  },
  devServer: {
    //解决跨越问题配置
    proxy: {
      '/api': {
        // 此处的写法,目的是为了 将 /api 替换成替换成我的服务器地址,地址自己写自己的,本机的也可以
        target: 'http://***.***.***.***:8080/',
        // 允许跨域
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    },
  },
  css: {
    loaderOptions: {
      stylus: {
        'resolve url': true,
        'import': []
      }
    }
  },
  pluginOptions: {
    'cube-ui': {
      postCompile: true,
      theme: false
    }
  }
}

不一定要全部复制,看你自己需要
跨域问题解决后进入index_1.vue里,这里全是关于tinymce富文本的 *** 作了
该有的注释都有了,代码也全部贴出来了,v-model这个可以百度看看他的意思

<template>
    <div>
<!--        当下面配置好直接使用<textarea>标签就能应用tinymce这个富文本了-->
        <textarea :id= "tinymceId" v-model="tinymceHtml"></textarea>
    </div>
</template>
<script>
    import tinymce from 'tinymce'
    import Editor from '@tinymce/tinymce-vue'
    import 'tinymce/themes/silver'
    import 'tinymce/plugins/image'// 插入上传图片插件
    import 'tinymce/plugins/media'// 插入视频插件
    import 'tinymce/plugins/table'// 插入表格插件
    import 'tinymce/plugins/link' //超链接插件
    import 'tinymce/plugins/code' //代码块插件
    import 'tinymce/plugins/lists'// 列表插件
    import 'tinymce/plugins/contextmenu'  //右键菜单插件
    import 'tinymce/plugins/wordcount' // 字数统计插件
    import 'tinymce/plugins/colorpicker' //选择颜色插件
    import 'tinymce/plugins/textcolor'  //文本颜色插件
    import 'tinymce/plugins/fullscreen' //全屏
    import 'tinymce/plugins/help'
    import 'tinymce/plugins/charmap'
    import 'tinymce/plugins/paste'
    import 'tinymce/plugins/hr'
    import 'tinymce/plugins/searchreplace'
    import 'tinymce/plugins/insertdatetime'
    import 'tinymce/plugins/toc'
    import 'tinymce/plugins/codesample'

    export default {
        name: 'tinymce',
        components: {Editor},
        //props:['value'], //下面methods里我配置了value,用来解决一些问题,不明白就不用管
        data () {
            let ide = Date.now()
            return {
                tinymceId: ide,
                tinymceHtml:'',
                DefaultInit: {
                    //这些路径自己放哪就找哪
                    language_url: '/tinymce/langs/zh_CN.js',  //导入语言文件
                    language: "zh_CN",//语言设置
                    skin_url: '/tinymce/skins/ui/oxide',//主题样式
                    content_css: `/tinymce/skins/content/default/content.css`,
                    font_formats: "微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings",
                    plugin_preview_width: 375, // 预览宽度
                    plugin_preview_height: 100,
                    lineheight_val: "1 1.1 1.2 1.3 1.35 1.4 1.5 1.55 1.6 1.75 1.8 1.9 1.95 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 3 3.1 3.2 3.3 3.4 4 5",
                    fontsize_formats: "8pt 10pt 11pt 12pt 13pt 14pt 15pt 16pt 17pt 18pt 24pt 36pt",
                    height: 500, //高度
                    // menubar: false,// 隐藏最上方menu菜单
                    toolbar: true,//false禁用工具栏(隐藏工具栏)
                    browser_spellcheck: true, // 拼写检查
                    branding: false, // 去水印
                    statusbar: false, // 隐藏编辑器底部的状态栏
                    elementpath: false,  //禁用下角的当前标签路径
                    paste_data_images: true, // 允许粘贴图像
                    powerpaste_word_import: 'merge', //从word粘贴过来的插件,也不知道有没有用,毕竟是本地的
                    //设置tinymce各种插件的显示
                    toolbar: 'fontselect | bold italic underline strikethrough | link unlink image | undo redo | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | code | removeformat',
                    // tinymce 富文本编译器的扩展插件
                    plugins:'link lists image code table wordcount media fullscreen preview paste contextmenu textcolor',
                }
            }
        },
        mounted () {
            this.init()
        },
        methods: {
            getTinymecHtml(){
                return this.tinymceHtml
            },

            init () {
                const self = this
                window.tinymce.init({
                    // 默认配置
                    ...this.DefaultInit,
                    // 'value': (editor) => {
                    //     // 在插入位置插入内容, 光标会被移至右侧
                    //     editor.setContent('');
                    //     editor.insertContent(this.value);
                    // },
                    //监听富文本内容
                    setup: function(editor) {
                        editor.on('input change undo redo execCommand KeyUp', function(e) {
                            self.$emit('input', editor.getContent());  //将富文本内容发送到父类App.vue里,这个input一会App.cue是要在控件里@input来使用的
                            console.log(editor.getContent())
                            // if(this.flag){
                            //     editor.setContent(editor.getContent);
                            // }
                            // this.flag=true
                        })
                    },
                    // 图片上传
                    images_upload_handler: function (blobInfo, success, failure){
                        //有图片上传请用这个FormData,当然这个也能添加字符之类的,只需要formData.append(name,object)就可以了,如果有更好的请自己搞去
                        let formData = new FormData()
                        console.log(blobInfo.filename())
                        formData.append('img',blobInfo.blob())  //记住这个 name:'img',一会服务器端代码里需要
                        let configs = { // 上传文件 请求头要设置成下面这样
                            headers:{'Content-Type':'multipart/form-data'} //给我写死,别作死,能复制就复制
                        };
                        self.$axios.post('/fileUpload/uploadImage/',formData,configs)  //因为在vue.config.js和main.js里配置了,所以这里面的路径应该是 我的服务器地址/fileUpload/uploadImage/,其实/fileUpload/uploadImage/这个路径是和服务器里的地址对应,可以随意修改
                            .then(response =>{ //从服务器返回数据的回调
                                console.log(response.data['path'])
                                if(response.data['status']==1){ //这个status是服务器代码里写的名称
                                    success(response.data['path'])
                                    console.log("成功了")
                                }else{
                                    console.log("失败了")
                                    failure('上传失败!')
                                }
                            })
                    },
                    // 挂载的DOM对象
                    selector: `#${this.tinymceId}`,
                })
            }
        }
    }
</script>

接下来要在App.vue里调用

<template>
  <div id="app">
    <div id="nav">
<!--      标签名就是script里impor里自己起的名字,@input就是index里起的那个名字-->
      <TinymceEditor @input="datasss"/>
<!--      我这里用来实时显示文本内容的-->
      <p id="aaa" v-html="this.texts"></p>
    </div>
  </div>

</template>

<style>

</style>
<script>

  import TinymceEditor from "./components/tinymce/index_1.vue"  //导入的路径
  export default {
    components: {TinymceEditor}, //别少这句
    data(){

      return {
        texts:""
      }
    },
    return:{

    },
    methods:{
      //这里实现@input的方法
      datasss(e){
          this.texts=e
      }

    }
  }

</script>

到这里,已经可以显示出我们的tinymce富文本了,然后是上传图片的 *** 作

当选择好自己的图片时,会跳到这个界面

点击保存就可以往服务器发送图片了,但是其实也可以直接拖照片进文本框里,但是不可以选择宽高,还得自己调,可以自己写拖入d出窗口设置宽高的代码,由于现在服务器代码还没写呢,当然传不了,哈哈哈,接下来是服务器的代码,先上成功效果图

服务器端用的是springboot,老样子,先上目录结构

需要的几个类src\main\java\com\example\demo\config\CrosConfig.java(//解决跨域问题),src\main\java\com\example\demo\controller\ImageController.java(接收从客户端发送来的图片并处理),src\main\java\com\example\demo\DemoApplication.java(启动类,配置一些内容),
src\main\java\com\example\demo\FileUploadConfig.java(解决上传图片找不到图片问题),
src\main\resources\application.properties(配置文件)

这是application.properties的配置,自己修改

spring.application.name=image_service
server.port=8080
server.tomcat.uri-encoding=utf-8
#单次上传单个上传文件大小
pring.servlet.multipart.max-file-size = 100MB 
#单次上传总文件大小
spring.servlet.multipart.max-request-size=1000MB
#数据库相关配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/homework
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5

#session生命周期
server.servlet.session.timeout=30m

FileUploadConfig.java(解决上传图片找不到图片问题)

package com.example.demo;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class FileUploadConfig implements WebMvcConfigurer {
	//解决上传图片找不到图片问题
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		//获取文件的真实路径
		String path = System.getProperty("user.dir")+"\src\main\resources\image\";
		registry.addResourceHandler("/image/**").addResourceLocations("file:"+path);
	}
}

CrosConfig.java(//解决跨域问题)

package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//解决跨域问题
@Configuration
public class CrosConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");
    }
}

ImageController.java(接收从客户端发送来的图片并处理)

package com.example.demo.controller;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;

@RestController
@Configuration
@RequestMapping("/fileUpload")  //客户端里的/fileUpload/uploadImage/就是这么来的
public class ImageController {

	private static final String imagePath = System.getProperty("user.dir")+"/src/main/resources/image/"; //图片保存路径,就是本项目下的image文件夹

	@RequestMapping(value = "/uploadImage",method = RequestMethod.POST) //客户端里的/fileUpload/uploadImage/就是这么来的
	public void uploadImage(@RequestParam("img") MultipartFile file,HttpServletRequest request,  //这里的img对应客户端的名称
			HttpServletResponse response) {
		Map result = new HashMap();
		try {

			String fileName = file.getOriginalFilename(); //文件名
			String path = imagePath + fileName;
			System.out.println(fileName);
			System.out.println(path);
			File storeImage = new File(path);
			if (!storeImage.exists()) {
				storeImage.mkdirs(); //如果没有文件夹就创建文件夹
			}
			file.transferTo(storeImage); //保存文件到指定的文件夹
			String url = "http://***.***.***.***:8080/image/"+fileName; //*这里填自己的服务器地址,返回文件夹下的图片路径
			System.out.println(url);
			result.put("status", "1");
			result.put("msg", "上传成功");
			result.put("fileName", fileName);
			result.put("path", url);
		} catch (Exception e) {
			result.put("status", "0");
			result.put("msg", "上传失败");
		}
		String json = JSON.toJSONString(result);
		PrintWriter writer = null;
		try {
			response.setHeader("Content-type", "application/json;charset=UTF-8");
			writer = response.getWriter();
			writer.write(json);  //将指定的文本json发送回客户端
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != writer) {
				writer.close();
			}
		}
	}

}

DemoApplication.java(启动类,配置一些内容)

package com.example.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.MultipartConfigElement;

@SpringBootApplication
@Configuration
@MapperScan(basePackages = "com.example.demo.mapper")
public class DemoApplication extends SpringBootServletInitializer{

	/*public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
		System.out.println(" ===项目启动成功===");
	}*/
	public static void main(String[] args) {
		new SpringApplicationBuilder(DemoApplication.class).run(args);
		System.out.println(" ===项目启动成功===");
	}

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		// TODO Auto-generated method stub
		return builder.sources(DemoApplication.class);
	}

	@Bean
	public MultipartConfigElement multipartConfigElement() {
		//配置单个和总文件单次上传大小
		MultipartConfigFactory factory = new MultipartConfigFactory();
		//  单个数据大小
		factory.setMaxFileSize(DataSize.parse("100000KB")); // KB,MB
		/// 总上传数据大小
		factory.setMaxRequestSize(DataSize.parse("1000000KB"));
		return factory.createMultipartConfig();
	}


}



写累了,实在是写不动了,但是这里只是解决了图片上传的问题,还有文本实时获取其实已经在index_1.vue代码里了

//监听富文本内容
                    setup: function(editor) {
                        editor.on('input change undo redo execCommand KeyUp', function(e) {
                            self.$emit('input', editor.getContent());  //将富文本内容发送到父类App.vue里,这个input一会App.cue是要在控件里@input来使用的
                            console.log(editor.getContent())
                            // if(this.flag){
                            //     editor.setContent(editor.getContent);
                            // }
                            // this.flag=true
                        })
                    },

就是那么一段,够简单吧,但是百度上资料少得苦逼,我吃了不少亏,这篇文章就到这了,真怕突然断电,白写那么多。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1321687.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存