TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有:UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。
配置灵活,界面简洁,支持自定义插件。
TinyMCE中文手册:http://tinymce.ax-z.cn
我使用的是v5版本的,需要搭配tinymce-vue包来使用
npm install tinymce/tinymce-vue@3.2.2
和
npm install tinymce@5.7.1
cp ./node_modules/tinymce ./public/tinymce
打开链接 http://tinymce.ax-z.cn/static/tiny/langs/zh_CN.js ,将zh_CN.js 另存到 public/tinymce/langs下,没有langs文件夹的可以手动创建一下
<template>
<Editor :id="editorId" v-if="reFresh" v-model="newData" :init="init" />
</template>
<script>
// 引入组件
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import 'tinymce/themes/silver/theme'
import "tinymce/skins/ui/oxide/skin.min.css";
// 引入富文本编辑器主题的js和css
export default {
name: "TinymceEditor",
components: { Editor },
data() {
return {
init: { // 配置文件
base_url: '/tinymce',
menubar: false,
external_plugins: { //引入需要的插件
anchor: "/tinymce/plugins/anchor/plugin.min.js",
code: "/tinymce/plugins/code/plugin.min.js",
print: "/tinymce/plugins/print/plugin.min.js",
preview: "/tinymce/plugins/preview/plugin.min.js",
searchreplace: "/tinymce/plugins/searchreplace/plugin.min.js",
autolink: "/tinymce/plugins/autolink/plugin.min.js",
directionality: "/tinymce/plugins/directionality/plugin.min.js",
visualblocks: "/tinymce/plugins/visualblocks/plugin.min.js",
visualchars: "/tinymce/plugins/visualchars/plugin.min.js",
fullscreen: "/tinymce/plugins/fullscreen/plugin.min.js",
image: "/tinymce/plugins/image/plugin.min.js",
link: "/tinymce/plugins/link/plugin.min.js",
media: "/tinymce/plugins/media/plugin.min.js",
template: "/tinymce/plugins/template/plugin.min.js",
codesample: "/tinymce/plugins/codesample/plugin.min.js",
table: "/tinymce/plugins/table/plugin.min.js",
charmap: "/tinymce/plugins/charmap/plugin.min.js",
pagebreak: "/tinymce/plugins/pagebreak/plugin.min.js",
nonbreaking: "/tinymce/plugins/nonbreaking/plugin.min.js",
insertdatetime: "/tinymce/plugins/insertdatetime/plugin.min.js",
advlist: "/tinymce/plugins/advlist/plugin.min.js",
lists: "/tinymce/plugins/lists/plugin.min.js",
wordcount: "/tinymce/plugins/wordcount/plugin.min.js",
imagetools: "/tinymce/plugins/imagetools/plugin.min.js",
textpattern: "/tinymce/plugins/textpattern/plugin.min.js",
help: "/tinymce/plugins/help/plugin.min.js",
emoticons: "/tinymce/plugins/emoticons/plugin.min.js",
autosave: "/tinymce/plugins/autosave/plugin.min.js",
iframe: "/tinymce/plugins/iframe/plugin.min.js",
hr: "/tinymce/plugins/hr/plugin.min.js",
// formatpainter: "/tinymce/plugins/formatpainter/plugin.min.js",
},
language_url:
"/tinymce/langs/zh_CN.js", //语言文件
language: "zh_CN",
font_formats:
"微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",
toolbar: [
"template code undo redo restoredraft cut copy paste pastetext forecolor backcolor bold italic underline strikethrough link unlink anchor alignleft aligncenter alignright alignjustify outdent indent formatselect fontselect fontsizeselect bullist numlist blockquote subscript superscript removeformat table image media charmap emoticons pagebreak insertdatetime print preview fullscreen formatpainter iframe hr",
],
templates: [],
// content_css : ['/layui/css/layui.css','/css/public.css?v=1'],
content_css: [],
height: 800, //编辑器高度
min_height: 200,
max_height: 600,
branding: false,
paste_data_images: true, // 允许粘贴图像
file_picker_types: "file image media",
images_upload_handler: (blobInfo, success) => {
var xhr, formData;
var file = blobInfo.blob();//转化为易于理解的file对象
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open("POST",`${process.env.VUE_APP_API_URL}/file/upload`); //上传文件的地址,需要替换成自己的
xhr.setRequestHeader("Authorization",window.localStorage.escourse_token);
xhr.onload = function () {
var json;
json = JSON.parse(xhr.responseText);
};
formData = new FormData();
formData.append("file", file, file.name);
formData.append("module", "post");
formData.append("file_source", "1");
// formData.append("token",window.localStorage.escourse_token)
xhr.send(formData);
xhr.onload = function () {
let json = JSON.parse(xhr.responseText);
if (json.code == 200) {
success(process.env.VUE_APP_API_URL + json.data.file.path)
return
}
};
},
media_url_resolver: function (data, resolve) {
try {
let videoUri = encodeURI(data.url);
let embedHtml = `<p>
<span
class="mce-object mce-object-video"
data-mce-selected="1"
data-mce-object="video"
data-mce-p-width="100%"
data-mce-p-height="auto"
data-mce-p-controls="controls"
data-mce-p-controlslist="nodownload"
data-mce-p-allowfullscreen="true"
data-mce-p-src=${videoUri} >
<video src=${data.url} width="100%" height="auto" controls="controls" controlslist="nodownload">
</video>
</span>
</p>
<p style="text-align: left;"></p>`;
resolve({ html: embedHtml });
} catch (e) {
resolve({ html: "" });
}
},
file_picker_callback(cb, value, meta) {
//当点击meidia图标上传时,判断meta.filetype == 'media'有必要,因为file_picker_callback是media(媒体)、image(图片)、file(文件)的共同入口
console.log('meta', meta);
//创建一个隐藏的type=file的文件选择input
let input = document.createElement("input");
input.setAttribute("type", "file");
input.onchange = function () {
var xhr, formData;
let file = this.files[0]; //只选取第一个文件。如果要选取全部,后面注意做修改
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open("POST",`${process.env.VUE_APP_API_URL}/file/upload`); //上传文件的地址,需要替换成自己的
xhr.setRequestHeader("Authorization",window.localStorage.escourse_token);
xhr.onload = function () {
var json;
json = JSON.parse(xhr.responseText);
};
formData = new FormData();
formData.append("file", file, file.name);
formData.append("module", "post");
formData.append("file_source", "1");
// formData.append("token",window.localStorage.escourse_token)
xhr.send(formData);
xhr.upload.onprogress = function () {
// 进度(e.loaded / e.total * 100)
// progress(e.loaded / e.total * 100);
};
// xhr.onerror = function () {
// //根据自己的需要添加代码
// console.log(xhr.status);
// return;
// };
xhr.onload = function () {
let json = JSON.parse(xhr.responseText);
if (json.code == 200) {
// if (meta.filetype == "media") {
cb(process.env.VUE_APP_API_URL + json.data.file.path, { text: json.data.file.name })
// }
// if (meta.filetype == "file") {
// cb(json.data.url, { text: json.data.name })
// }
return
}
};
};
//触发点击
input.click();
},
},
editorId: this.id,
newData: this.data,
reFresh:false,
laws:[]
};
},
created(){
this.getBandData();
},
mounted() {
tinymce.init({});
},
props: {
data: String,
onChange: Function // 回调函数,将新修改的内容做为第一个参数返回
},
watch: {
newData: 'updateData',
data: 'uptData',
"init.templates"(newValue) { // 如果配置发生改变,则刷新编辑器
this.reFresh = false;
this.$nextTick(() => {
this.reFresh = true;
});
},
},
methods: {
async getBandData() {
let urlResult = await getTemplates(); //这边我是自己封装了个插件,通过getTemplates接口,从后端读取模板,再显示到编辑器插件上,如果不需要可以删掉
if (urlResult.code == 200) {
let array = urlResult.data;
let arr = [];
for (let index = 0; index < array.length; index++) {
const element = array[index];
let data = {
title: element.name,
content: element.html,
description: element.html,
// description: "<img src='"+this.urlConfig.adminUrl + element.thumbnail+"'/>",
};
arr.push(data);
}
this.laws = arr; //得到的数据赋值给laws
this.init.templates = this.laws;
}
},
addContent(html) {
console.log('html', html)
this.newData = this.newData + html
},
uptData() {
this.newData = JSON.parse(JSON.stringify(this.data))
},
updateData() {
this.onChange(this.newData)
},
clear() {
this.editorValue = "";
},
},
};
</script>
在页面中引用
<template>
<Editor v-bind:data="data" :onChange="onchange"></Editor>
</template>
import Editor from "../../../components/tinymce/editor";
export default {
data() {
return {
data:''
};
},
components: {
Editor
},
methods: {
onchange(e){
this.data = e
}
}
}
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里编辑 3.解析依赖到项目中
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
我有这个代码:context"Visitingtheusers#indexpage."dobefore(:each){visitusers_path}subject{page}pending('iii'){shouldhave_no_css('table#users')}pending{shouldhavecontent('Youhavereachedthispageduetoapermissionic错误')}它会导致几个待处理,例如ManagingUsersGivenapractitionerloggedin.Visitingtheusers#indexpage.#Noreason
我一直在玩一个脚本,它在Chrome中获取选定的文本并在Google中查找它,提供四个最佳选择,然后粘贴相关链接。它以不同的格式粘贴,具体取决于当前在Chrome中打开的页面-DokuWiki打开的DokuWiki格式,普通网站的HTML,我想要我的WordPress所见即所得编辑器的富文本。我尝试使用pbpaste-Preferrtf来查看没有其他样式的富文本链接在粘贴板上的样子,但它仍然输出纯文本。在文本编辑中保存文件并进行试验后,我想出了以下内容text=%q|{\rtf1{\field{\*\fldinst{HYPERLINK"URL"}}{\fldrsltTEXT}}}|te
我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源