window系统下 tinymce富文本编辑器在搜狗输入法下placeholder不消失现象

news2024/11/24 15:29:54

window 搜狗输入法下编辑器占位符和内容重叠问题

这种情况是,tinymce插件库存在一些兼容BUG,需要我们自行手写样式或者js替换掉placeholder,代码如下:
在这里插入图片描述

    // 获取富文本框的内容
    const handleChange = (editorContent) => {
      // console.log('>>>>> TinymceEditor handleChange', editorContent);
      // console.log('>>>>> TinymceEditor handleChange', editorContent, editorRef.current);
      window.email____detail__content = editorContent;
      onChange(editorContent);
      if (window.tinymce?.Env.os.isWindows()) {
        if (editorContent) {
          editorRef.current?.getBody().removeAttribute('data-mce-placeholder');
        } else {
          editorRef.current
            ?.getBody()
            .setAttribute('data-mce-placeholder', placeholder || intl.formatMessage({ id: 'email.inputHolder' }));
        }
      }
    };

render区域代码:

<div className={cn(styles.TinymceEditorWrap, language)} style={style}>
        <Editor
          onScriptsLoad={() => {
            // 初始化字间距插件
            PluginManagerLetterSpacing();
          }}
          // tinymceScriptSrc={'./tinymce/tinymce.min.js'} // 本地开发可以采用这个
          tinymceScriptSrc={'https://vv-public-staticresource.vv.cn/tinymce/tinymce.min.js'}
          onInit={(evt, editor) => {
            editorRef.current = editor;
            editor.getBody().style.fontSize = '16px';
            // console.log('>>>>>>>>> onInit editor', editor);
          }}
          ref={ref}
          value={initData}
          style={contentStyle}
          init={{
            icons: 'vv',
            menubar: false, // 菜单栏
            statusbar: false, // 底部状态栏
            branding: false, // 是否显示版权信息
            resize: false,
            language,
            height,
            toolbar,
            // toolbar_mode: 'wrap', // 工具栏展开方式 'floating', 'sliding', 'scrolling', or 'wrap'。 Default 'floating'
            plugins,
            font_size_formats: '8px 10px 12px 14px 16px 18px 24px 36px 48px',
            font_size_input_default_unit: 'px',
            images_file_types: 'png,jpg,jpeg,gif',
            file_picker_types: 'image',
            automatic_uploads: true,
            images_upload_handler: myUploadFn,
            placeholder: placeholder || intl.formatMessage({ id: 'email.inputHolder' }),
            content_style:
              ".mce-content-body{font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;font-size: 16px;color: #49536C;line-height: 28px;font-weight: 400}" +
              '.mce-content-body[data-mce-placeholder]::before {color:#BCC1CD !important;}' +
              'img {max-width: 100%; height: auto;}' +
              ".divider{display:flex;justify-content:space-between;align-items:center;}.divider:before,.divider:after{content:'';width:50px;height:2px;background: #f0f0f0;}" +
              '.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width:0px"],table[style*="border-width:0px"] caption,table[style*="border-width:0px"] td,table[style*="border-width:0px"] th{border:0 !important;}',
            // cache_suffix: '?v=4.1.6',
          }}
          onEditorChange={handleChange}
          onDragOver={onDragOver}
          onClick={handleCloseExpandedDom}
        />
      </div>

完整的富文本组件代码:

import styles from './index.module.less';
import { useIntl } from 'react-intl';
import cn from 'classnames';
import { forwardRef, memo, useEffect, useRef } from 'react';
import { message } from '@/components';
import { Editor } from '@tinymce/tinymce-react';

import { uploadFn } from './utils';
import PluginManagerLetterSpacing from './plugins/letterspacing';
import { useSafeState } from '@vv-desktop-web-core/hooks';
import { jsbridge } from '@vv-desktop-web-core/helpers';

/**
 * 需要返回什么功能按需添加
 * https://www.tiny.cloud/docs/tinymce/6/react-ref/
 * @param height
 * @param initData
 * @param onChange
 * @returns {JSX.Element}
 * @constructor
 */
const TinymceEditor = forwardRef(
  (
    {
      height = '100%',
      initData = '',
      onChange,
      onDragOver = () => {},
      style = {},
      contentStyle = {},
      placeholder = '',
    },
    ref,
  ) => {
    const intl = useIntl();
    // 部分被css重置的文案是写在css里的,依据class language区分
    const [language, setLanguage] = useSafeState('zh-CN');
    const editorRef = useRef();
    // eslint-disable-next-line no-param-reassign
    height = typeof height === 'number' ? `${height}px` : height;

    // console.log('>>>>>> TinymceEditor 组件', 'initData', initData);

    // 不允许添加尺寸大于50M的图片
    const myValidateFn = (file) => {
      if (file.size > 1024 * 1024 * 50) {
        message.error('Size is greater than 50M!');
        return false;
      }
      return true;
    };

    const myUploadFn = (blobInfo) => {
      return new Promise((resolve, reject) => {
        const file = blobInfo.blob();
        const { type } = file;
        if (!myValidateFn(file)) {
          // eslint-disable-next-line prefer-promise-reject-errors
          reject('Size is greater than 50M!');
          return;
        }
        // 图片大小 <500k 则走base64方式,>= 则走oos方式
        if (file.size < 1024 * 500) {
          const img = `data:${type};base64,${blobInfo.base64()}`;
          resolve(img);
        } else {
          uploadFn({
            file,
            onChange: (d) => console.log('>>>>>>> onChange', d),
            onSuccess: (d) => {
              resolve(d);
            },
            onError: () => {
              reject('上传失败');
            },
            onProgress: (d) => console.log('>>>>>>> onProgress', d),
          });
        }
      });
    };

    // https://www.tiny.cloud/docs/tinymce/6/plugins/
    const plugins = ['link', 'image', 'code', 'media', 'emoticons', 'lists', 'letterspacing'];

    // https://www.tiny.cloud/docs/tinymce/6/toolbar-configuration-options/#toolbar
    // https://www.tiny.cloud/docs/tinymce/6/available-toolbar-buttons/
    const toolbar =
      'undo redo | fontsize | lineheight | letterspacing | ' +
      'forecolor bold italic underline strikethrough | ' +
      'superscript subscript removeformat emoticons | ' +
      'indent outdent alignleft aligncenter alignright alignjustify | ' +
      'blocks | ' +
      'bullist numlist blockquote code | ' +
      'image link unlink hr | remove';

    // 获取富文本框的内容
    const handleChange = (editorContent) => {
      // console.log('>>>>> TinymceEditor handleChange', editorContent, editorRef.current);
      window.email____detail__content = editorContent;
      onChange(editorContent);
      if (window.tinymce?.Env.os.isWindows()) {
        if (editorContent) {
          editorRef.current?.getBody().removeAttribute('data-mce-placeholder');
        } else {
          editorRef.current
            ?.getBody()
            .setAttribute('data-mce-placeholder', placeholder || intl.formatMessage({ id: 'email.inputHolder' }));
        }
      }
    };

    // 非toolbar区域,需要关闭toolbar浮窗
    const handleCloseExpandedDom = () => {
      const expandedDom = document.querySelector('.tox-tbtn.tox-tbtn--enabled');
      if (expandedDom) {
        expandedDom.click();
      }
    };

    useEffect(() => {
      const language1 = jsbridge?.getLocale();
      if (language1 && language1?.includes('en')) {
        setLanguage('en');
      }
    }, []);

    return (
      <div className={cn(styles.TinymceEditorWrap, language)} style={style}>
        <Editor
          onScriptsLoad={() => {
            // 初始化字间距插件
            PluginManagerLetterSpacing();
          }}
          // tinymceScriptSrc={'./tinymce/tinymce.min.js'} // 本地开发可以采用这个
          tinymceScriptSrc={'https://xx.xx.xx/tinymce/tinymce.min.js'} // cdn资源存放访问地址
          onInit={(evt, editor) => {
            editorRef.current = editor;
            editor.getBody().style.fontSize = '16px';
            // console.log('>>>>>>>>> onInit editor', editor);
          }}
          ref={ref}
          value={initData}
          style={contentStyle}
          init={{
            icons: 'vv',
            menubar: false, // 菜单栏
            statusbar: false, // 底部状态栏
            branding: false, // 是否显示版权信息
            resize: false,
            language,
            height,
            toolbar,
            // toolbar_mode: 'wrap', // 工具栏展开方式 'floating', 'sliding', 'scrolling', or 'wrap'。 Default 'floating'
            plugins,
            font_size_formats: '8px 10px 12px 14px 16px 18px 24px 36px 48px',
            font_size_input_default_unit: 'px',
            images_file_types: 'png,jpg,jpeg,gif',
            file_picker_types: 'image',
            automatic_uploads: true,
            images_upload_handler: myUploadFn,
            placeholder: placeholder || intl.formatMessage({ id: 'email.inputHolder' }),
            content_style:
              ".mce-content-body{font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;font-size: 16px;color: #49536C;line-height: 28px;font-weight: 400}" +
              '.mce-content-body[data-mce-placeholder]::before {color:#BCC1CD !important;}' +
              'img {max-width: 100%; height: auto;}' +
              ".divider{display:flex;justify-content:space-between;align-items:center;}.divider:before,.divider:after{content:'';width:50px;height:2px;background: #f0f0f0;}" +
              '.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width:0px"],table[style*="border-width:0px"] caption,table[style*="border-width:0px"] td,table[style*="border-width:0px"] th{border:0 !important;}',
            // cache_suffix: '?v=4.1.6',
          }}
          onEditorChange={handleChange}
          onDragOver={onDragOver}
          onClick={handleCloseExpandedDom}
        />
      </div>
    );
  },
);

export default memo(TinymceEditor);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/841580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++11 新特性 ---- final 和 override

一、final C中增加了final关键字&#xff0c;作用如下&#xff1a; ① 限制某个类不能被继承② 或者某个虚函数不能被重写 ① 限制某个类不能被继承 // ① 限制某个类不能被继承,也就是说这个类不能有派生类 class Base{ public:virtual void print() {cout<<"Ba…

电商数据获取:网络爬虫还是付费数据接口?

随着电商行业的迅速发展&#xff0c;对电商数据的需求也越来越大。在获取电商数据时&#xff0c;常常面临一个选择&#xff1a;是自己编写网络爬虫进行数据爬取&#xff0c;还是使用现有的付费数据接口呢&#xff1f;本文将从成本、可靠性、数据质量等多个角度进行分析&#xf…

【css】组合器

组合器是解释选择器之间关系的某种机制。在简单选择器器之间&#xff0c;可以包含一个组合器&#xff0c;从而实现简单选择器难以达到的效果。 CSS 中有四种组合器&#xff1a; 后代选择器 (空格)&#xff1a;匹配属于指定元素后代的所有元素&#xff0c;示例&#xff1a;div …

element-ui表格数据为空,图片占位提示

当表格的绑定数据为空时常需要显示暂无数据等字样&#xff0c;这时候就用到了empty-text <el-table:data"tableData"stripeborderempty-text"暂无数据"> 但&#xff0c;当数据为空&#xff0c;想用图片展示呢&#xff0c;如下图 方法一&#xff1a…

java.lang.UnsupportedClassVersionError TestCase

JavaFramework-JDK6.jar 放到JDK17运行没有问题 JavaFramework源码放到JDK17环境下编译出来的JavaFramework-JDK17.jar JavaFramework-JDK17.jar 放到JDK17运行没有问题 JavaFramework-JDK17.jar 放到JDK8运行没有问题&#xff0c;这个好像不对啊&#xff0c;可能之前编译设置…

day39反转字符串总结

反转字符串原理其实就是交换位置&#xff0c;以中间为分隔点&#xff1b; 基本套路&#xff1a;遍历前一般字符&#xff0c;互换位置&#xff1b; for循环模板 void reverseString(char* s, int sSize){char temp;for (int i 0, j sSize - 1; i < sSize/2; i, j--) {temp…

【无公网IP】本地电脑搭建个人博客网站(并发布公网访问 )和web服务器

【无公网IP】本地电脑搭建个人博客网站&#xff08;并发布公网访问 &#xff09;和web服务器 文章目录 【无公网IP】本地电脑搭建个人博客网站&#xff08;并发布公网访问 &#xff09;和web服务器前言1. 安装套件软件2. 创建网页运行环境 指定网页输出的端口号3. 让WordPress在…

【Rust】Rust学习第三章常见编程概念

包含第一、二章 文档&#xff1a;Rust 程序设计语言 - Rust 程序设计语言 简体中文版 (bootcss.com) 墙裂推荐这个文档 第一章入门 入门指南 - Rust 程序设计语言 简体中文版 第二章猜猜看游戏 猜猜看游戏教程 - Rust 程序设计语言 简体中文版 (bootcss.com) // 导入库 us…

Stable Diffusion 硬核生存指南:WebUI 中的 GFPGAN

本篇文章聊聊 Stable Diffusion WebUI 中的核心组件&#xff0c;强壮的人脸图像面部画面修复模型 GFPGAN 相关的事情。 写在前面 本篇文章的主角是开源项目 TencentARC/GFPGAN&#xff0c;和上一篇文章《Stable Diffusion 硬核生存指南&#xff1a;WebUI 中的 CodeFormer》提…

H263压缩码流如何分解为一个一个单元并查询到其宽高?

H263码流尺寸规格有限&#xff0c;只有以下几种&#xff1a; H263码流有四个分层&#xff1a; 1、图像层 2、块组 3、宏块 4、块 下面分别介绍&#xff1a; 具体介绍如下&#xff0c;5.1.3中红色框选部分就是压缩码流的宽高指示&#xff1a; 图像层 上面就是H263的图像层&am…

QT开发学习相关笔记

QT中配置文件读取 QT中使用的config文件为&#xff1a;xxx.ini文件,基本格式如下&#xff1a; 使用 QSetting&#xff08;QT自带类&#xff09;中的相关接口实现设置配置文件数据&#xff0c;或者读取数据。 读取配置文件路径设置如下&#xff0c;其中 iniPath为设置路径 ne…

word2003脚注问题

问题分析&#xff1a; 在题目上插入脚注的时候&#xff0c;脚注放在文件结尾&#xff0c;然后正文拆开了&#xff0c;不能续前节 解决办法&#xff1a; word2003中&#xff0c;工具->选项->兼容性

进程间通讯(IPC机制) 管道 信号量 共性内存 消息队列 详细图解

进程间通讯-IPC机制 常用命令管道有名管道读写编程有名管道示意图 无名管道 信号量信号量的概念信号量接口函数进程 a 和进程 b 模拟访问打印机 用信号量互斥画图分析代码实现测试结果显示和操作 共享内存 信号量 消息队列 的命令 共享内存共享内存定义共享内存函数接口实例编程…

docker镜像push到仓库

镜像可以很方便直接 push 到 docker 的公共仓库或阿里云仓库 一、Dockerpush指定仓库是什么&#xff1f; Dockerpush是Docker的一个命令&#xff0c;用于将本地的Docker镜像推送到Docker官方公共仓库或用户私人仓库。而指定仓库则是将这个Docker镜像推送到指定的仓库中。 通过D…

【独立后台】快递小程序便宜寄快递系统小程序 对接易达

快递代发项目简介&#xff1a; 顾名思义就是帮发快递。原本产业链是客户-快递之间的联系&#xff0c;现在变成了客户-我们-快递&#xff0c;简单来说就是我们把客户聚集到一起团购到了更优惠的价格。很简单就是赚一个差价&#xff0c; 单子多就能和各个快递合作的平台&#x…

C++ 类型兼容规则

类型兼容规则是指在需要基类对象的任何地方&#xff0c;都可以使用公有派生类的对象来替代。 通过公有继承&#xff0c;派生类得到了基类中除构造函数和析构函数之外的所有成员。这样&#xff0c;公有派生类实际就具备了基类的所有功能&#xff0c;凡是基类能解决的问题&#x…

QA | 关于手持式频谱仪,您想了解的那些技术问题(二)

Q1&#xff1a;手持式频谱仪的灵敏度多高&#xff1f;底噪多少&#xff1f; 0.01-3GHz手持频谱仪的底噪/灵敏度为-128dBm RBW10kHz&#xff08;即归一化到Hz为-168dBm/Hz&#xff09;&#xff1b;2-8GHz手持频谱仪的底噪/灵敏度为-119dBm RBW30kHz&#xff08;即归一化到Hz为…

Javascript 数据结构[入门]

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…

JVM之类加载与字节码(一)

1.类文件结构 一个简单的HelloWorld.Java package cn.itcast.jvm.t5; // HelloWorld 示例 public class HelloWorld { public static void main(String[] args) { System.out.println("hello world"); } }编译为 HelloWorld.class 后的样子如下所示&#xff1a; […

最小二乘问题和非线性优化

最小二乘问题和非线性优化 0.引言1.最小二乘问题2.迭代下降法3.最速下降法4.牛顿法5.阻尼法6.高斯牛顿(GN)法7.莱文贝格马夸特(LM)法8.鲁棒核函数 0.引言 转载自此处&#xff0c;修正了一点小错误。 1.最小二乘问题 在求解 SLAM 中的最优状态估计问题时&#xff0c;我们一般…