使用React版antd的表格table设置宽度width不生效,无法横向滚动,固定列有白色空隙

前段时间接手了一个新的项目,使用的React+antd的技术栈,最近在正式做第一期的需求了,自己也开始使用蚂蚁的antd了,自己之前用Vue的时候是用过饿了么的Element-ui,想着这类用法应该都大同小异的,但是自己还是遇到了坑。。。 主要是宽度不生效,滚动条出不来,左侧列固定后有白色空隙,文末有解决方案。 背景 项目比较老,里面使用的ant版本为3.22.0,现在最新的ant已经是4.x了,自己刚接手不久,暂时不会考虑升级antd版本。 用户选择的对比语言,都会在表格中增加一列,加上表格里面固定的QID列和基准语言列,剩下的就是对比语言的列了(有几个对比语言,就有几列),当用户选择的对比语言过多的时候,就需要横向滚动 需求一:内容过多时支持横向滚动 为了表格整体美观一点,需要设置下列的宽度,QID列的内容都是字母数字,长度波动不大,准备固定为280,所有语言列的宽度准备固定为200,这个表格里面没有常见的最后一列–操作列,也就是没有了可以用来不设置固定宽度供伸缩的列,官方说法是请尝试建议留一列不设宽度以适应弹性布局。 遇到的问题 固定宽度不生效 对比语言列少的场景 这样没什么问题,铺满。 列多语言列多的场景 这里面选择了很多的对比语言,我们会看到列的宽度没有生效,语言列的宽度会不断压缩,以方便所有的语言列显示在table中。本想着固定宽度的总量不断增加,超过整体可视区域,会自动让我横向滚动的,结果没有。 属性是设置上去了的。 看来不会用这个width的不止我一个。 尝试打开官方给的链接,与github的issue上找解决方案 虽然感觉跟我的问题不太一样,还是尝试把上面提到的textWrap, ellipsis,wordBreak都组合设置了下,也没有看到效果。 其它上面的三个属性应该是适用于列里面的文字太多了的场景,我这边目前还没到那一步呢,就截图上的语言列里面的哪个几个汉字是不会超过200的。 横向滚动 尝试设置了scroll = {{x: true}}、scroll = {{x: 'max-content'}}、scroll = {{x: 600}},包括根据当前语言列的多少,动态设置scorll.x的数值也尝试过,直接设置过大或过小值也尝试过,终究出现滚动条。 但是只有上面的需求一,也就是需要横向滚动,但是连滚动条的影子都没有见到。。。 最后决定放弃官方给的属性设置了,尝试用CSS解决。 解决方案(需求一) 把上面尝试的官方设置的width、scroll都拿掉。 给需要尝试设置宽度的列设置上class(通过antd实现),QID列为qid_column,其它语言列均为lang_column 加上css .ant-table-body { overflow-x: auto; // 让table能横向滚动 .ant-table-tbody { .qid_colomn { word-break: break-all; width: 280px; Read more…

上海市2022年事业单位公开招聘及报名数据统计

上海市2022年事业单位公开招聘公告简述如下; 招聘 一、招聘对象和条件 1.具有中华人民共和国国籍,遵守宪法和法律,具有良好品行。 2.具备招聘单位规定的岗位聘用要求、资格条件、工作能力和身体条件。详见附件1《上海市2022年事业单位公开招聘简章》(以下简称《招聘简章》)。 3.外省市社会人员,须持有上海市居住证(在有效期内)一年以上,计算截止时间为2022年12月31日。 二、报名时间和方式 报名时间为2022年3月7日10:00至3月11日16:00 每人限报考一个岗位。报名期间考生可自行更改报名信息,报名截止后成功报考岗位的报考人员可在规定时限下载打印准考证和参加考试。考试不收取报名考务费。 报名相关的具体细节可以见官网的公告,地址上海市2022年事业单位公开招聘公告 今天是3月12日植树节,上海市2022年事业单位公开招聘已经截止。 数据分析 累计招聘岗位3535个,报名人数81149人。 年龄段划分 年龄上限 岗位数 30 1163 35 2057 40 301 45 14 报名要趁早,30岁~35岁(含)以下可以的还有67.1%,35岁以上就只有8.9%,35岁这哪是一道坎,这分明是一条河。 招聘人数划分 招聘人数 岗位数 373 1 10 1 8 1 6 2 5 6 4 15 3 52 2 323 1 3134 招聘人数绝大部分都是一个人,我们看看上面的前三名的招聘大户? 市三支一扶办公室 三支一扶计划招募专项(不选择其他事业岗位) 到农村基层从事支教、支农、支医和乡村振兴工作 Read more…

2021年的一点工作总结(二)富文本编辑器

邮件项目的核心功能就是编辑邮件了,所以文本的编辑特别容易被用户吐槽了。用户报障的时候一个万能的吐槽点“没有xxx功能,不支持xxx,没有Outlook好用”。 其实作为一个web产品,如果需要更加公平的对比的话,应该远程web版网页邮箱对比(如outlook网页版),而不是客服端软件(如Outlook),普通用户不知道也不会这么对比,所以你也只能受着。。。 从原来的wangEditor替换成CKEditor也不是说就万事大吉了,官方什么插件都有,什么功能都不用自己开发了,那你就大错特错了。说去不负责任的话,支持功能越多,开放给用户的就越多,然后被吐槽的就越多。 2021年,因为富文本的缘故我做过几次相关的改造: 第一次改造:Vue -> React 项目从Vue迁移到React,虽然当时并未“动”编辑器,仍用的是老的wangEditor,但是为了邮件的编辑器“插件”签名和快捷回复功能(以下主要以“签名”为例),能跟原来一致的使用体验。 Vue时代 就是图中绿框中的部分。 这两个功能一直是用Vue写的,然后集中在一个名为editorChildren的div中,然后该div作为整体被wangEditor编辑器append到指定的dom结构中使用,大致用法如下: 用Vue中编辑签名相应的功能 在wangEditor的源码中将其整体插入 这里提到的iframe就是在上图中rich-editor.vue给预留的id为editorIframe的iframe,wangEditor之前已经被改造成在iframe中使用了。 按照这种模式可以将签名对应的功能直接用Vue来编写,不用费劲的用原生JS实现了,开发效率更高。 React时代 迁移到React后,发现不能原来这种模式了,这样会导致签名上面绑定的点击事件没有反应,这个应该是跟React对点击事件的响应机制有关。 所以不得不对此做些改动,将上述的editorChildren的那部分直接写成一个React组件ToolBar 然后用render方法生成对应的html,再有wangEditor将其插入对应的dom中 import ReactDom from 'react-dom'; import Toolbar from "../components/editor-widgets/Toolbar"; const children = document.querySelector('#editorChildren'); ReactDom.render(<Toolbar/>, tools); iframe.contentDocument.body.append(children); 至此原来的签名和快捷回复功能算是能在React项目中正常使用了。 第二次改造 wangEditor -> CKEditor 这次算是最大的一次改造了,就是要把wangEditor替换成CKEditor。 CKEditor可不支持之前像wangEditor那样的骚操作了,它是有自己的插件编写规则的,我个人也不想像对带wangEditor那样改源码了。 CKEditor的插件都是用原生JavaScript编写的。 (function () { CKEDITOR.plugins.add( 'mailshortcutreply', { requires: ['mailcontent', Read more…

2021年的一点工作总结(一)迁移React技术栈

2021年全年的工作总结起来很简单,算是做苦力的一年吧。。。 2021年春节后就开始邮件项目从Vue迁移到React的工作以及富文本编辑器由wangEditor替换成CKEditor。 其实自己对这项工作内心是排斥的,这绝对不是自己从Vue因为切换到不熟悉的React技术栈。 我对此工作安排的分析如下: 这是一项时间跨度很长的工作,迁移期间是需要同事兼容两套系统的。 长期性工作很容易存在延期,虽然大家并不是不容忍你延期,但是这会额外增加自己在这项工作中所花费的时间。 自己在时间投入和收益方面不成正比,主要时间都花在原来功能的迁移 业务方面:没有太多时间开发新需求和解决业务痛点上。用户较难发现你到底做了什么新的工作,反而容易问你“以前这个都支持的,现在怎么不支持了”这样的问题。 技术方面:没有太多精力进行技术深度的研究和新型技术的探索 对年底晋升没有任何助力,难有亮点,大家都会认为迁移技术栈没什么不算什么贡献。 所以说这是项对公司有利,但是对我个人而言性价比极低的一件事,唯一的好处也只能是熟悉了React技术栈而已,深度还有限。 如果只是想在公司养老混日子,一直有事做的话,上面的话当我没说。 现状 目前邮件项目主要分查看和编辑两个页面,剩下的主要是websocket消息、编辑切换二次确认之类的业务逻辑控制,其中编辑页使用到了富文本编辑器,相对复杂些。 dom结构 蓝框内:O端控制部分 绿框内:邮件控制部分(iframe内) 黄框内:邮件详情查看(iframe内) iframe无感 右键唤出的功能框(比如翻译框)需要支持自由拖拽,让用户感知不到iframe隔离效果 迁移方案 方案一:开发完所有组件再拼装相应模块 完成组件开发 拼装组件整体上线 优点 整体迁移,无额外兼容成本 缺点 开发、测试进度不好量化。项目整体积压在一起上线,项目整体风险不好控制 方案二:按模块维度开发所需组件后拼装成型 拆分成各个大模块逐步上线、测试 根据业务功能和方便布局考虑,将项目简单分成以下模块 编辑模块 列表模块 主模块(查看模块/编辑模块 + 右侧模块) 优点 可以将整个项目分模块开发、测试,项目风险更容易把控 缺点 增加额外通信成本成本(状态一致、页面跳转) 状态同步成本(邮箱、权限信息等) 过渡阶段的部分开发量后期用不上 出于对项目尽快落地见效等考虑,决定采用方案二——按模块维度开发所需组件拼装成型。 后面就是悲催的搬砖过程,当时较为激进的选择了使用React hooks,同时自己为了加快项目进度,避免更多的占用自己时间,采用的进行进行Vue方法和React方法的一对一“翻译”,迁移过程中发现很多场景并不能这样做,再加上之前Vue版本中是使用事件驱动的,这样的话页面mounted后需要大量的事件回调,回调方法及其嵌套方法会用到state,所以出现了很多因为闭包陷阱而引发的问题。。。

CKEditor富文本编辑器职责分离

背景 CKEditor富文本编辑器(生产版本1.1.1及以前)里面包含富文本基础插件及当前最新的邮件特定的业务插件(签名、快捷回复、邀评、默认样式、选择颜色、插入图片、粘贴模式) O端,作为业务项目,具体使用编辑器。 O端 + 编辑器 组合起来作为完整的项目运行。 图中红框内标注插件为原编辑器不支持而全新开发的 图中蓝框内标注插件为原编辑器还有类似插件但满足业务场景而二次开发的 一般编辑器相关业务改动是通过新增或调整相关业务插件来完成,而编辑器的基础组件极少改动。现在特将可能频繁改动的邮件业务插件转移至O端项目中,以后编辑器项目中仅包含编辑器核心+基础组件,待精简无用插件和多语言数据后固定成稳定版本。 实施方案 O端项目最新版中利用编辑器API控制编辑器优先使用O端内的业务插件 O端老版本继续使用编辑器中的业务插件,待用户更新至O端最新版本后,发布编辑器最新版(即不包含邮件业务插件的版本) 注意事项 编辑器最新版需要最后上线,因为其只能和O端项目最新版配套使用,否则(比如O端老版本 + 编辑器新版本组合)会因无邮件业务插件而出错的情况。

富文本编辑器CKEditor4迁移方案

之前写过《富文本编辑器wangEditor迁移CKEditor前后效果对比》,结合大家的反馈后进行了调整。 增加了具体案例的展示CKEditor插件和事件系统,重新整理成迁移方案。 一、背景 老版本富文本编辑器wangEditor的工具栏如图所示 新版本富文本编辑器CKEditor4工具栏如图所示 老版本编辑器有以下常见业务场景不支持: 先设置字体字号,然后再编辑文字 格式刷 表格粘贴至编辑器后增删表格行、列 新版本富文本编辑器内置插件直接支持上述功能。 二、新版编辑器的优势 我们能够将不同的业务场景写成插件,同时可以通过调整插件监听事件的优先级来干预(或部分借用)内置插件的结果。 场景举例 默认情况下向编辑器内粘贴图片操作会直接插入编辑器内,但是我们需要用户在粘贴图片的时候,显示一个二次确认弹框,提示用户选择是直接将该图片粘贴到编辑器内或者上传为附件使用。 改进方案 我们的自定义插件可以通过设置合适的优先级借用内置插件的准备流程同时避免原处理流程中其它可能干扰结果的处理回调。 三、新版编辑器的特性 可以通过配置项组合成不同的过滤器,对编辑器内容的获取结果进行控制。 案例 灰度期间客服反馈新版编辑器正在编辑的内容显示正常,内容发送出去后存在"增加空行的情况", 原因:调用接口是会调用CKEditor的getData方法获取编辑器内容,该方法中CKEditor会将空标签(例如<div></div>)内加入空行 ,从而导致原来高度为0的空标签有了高度,和编辑时显示的效果不一致,发送的内容在视觉上就感觉是“增加了空行”。 鉴于邮件内容来源不可控,无法避免外部邮件可能存在空标签的情况,在参考官网及网上设置了多种不同的配置项后,仍未达到理想的效果,我们的自定义过滤器暂时直接原样返回innerHTML内容作为输出结果。

CKEditor自动加载内联编辑器引发的故障记录

在一次项目优化过程中,我采取了按需加载的策略,将对CKEditor入口JS文件的加载过程移动到了点击回复邮件之后,这样的话,当用户没有编辑邮件的需求时就不用加载CKEditor相关的JS文件了。但是因为这一个改动,引起了意想不到的问题。 因为我们的项目中IM聊天页面也用到了简易的富文本编辑,使用的也是contenteditable的div来实现的,问题也是因此而出现的。我们先简单介绍下CKEditor的两种模式 CKEditor使用模式 classic模式 邮件里面使用的就是这种模式。 官方的解释是: 经典编辑器是大多数用户传统上学会的与富文本编辑器相关联的东西——一个带有编辑区域的工具栏,放置在页面的特定位置,通常作为表单的一部分,用于向服务器提交一些内容。 有时它也被称为“框架编辑”,因为在这种情况下,编辑器会为自己创建一个临时的 <iframe> 元素。 这个模式是把编辑器的工具栏放到项目中,然后创建一个iframe,在该iframe中新建一个contenteditable的div作为编辑区域。 inline模式 官方的解释是: 内联编辑允许您就地编辑页面上的任何元素。 内联编辑器提供了“开箱即用”的真正所见即所得体验,因为与经典编辑器不同,编辑区域周围没有 </iframe><iframe> 元素。 用于编辑器内容的 CSS 样式与呈现此内容的目标页面上的完全相同! 这个模式是把编辑器的工具栏放到项目中,编辑器的编辑区域还是在项目主体中,或者这样说更好一点,就是编辑区域还是在项目主体中,但是给它附加了一个CKEditor的工具栏,让这个编辑区域的编辑功能更加强大了。 邮件项目不适合使用inline模式,所以在阅读CKEditor相关源码的时候,我是不关注inline模式相关的代码的,都是直接跳过。 报障 前几天突然有人报障了,给的截图如下 这是用户在使用IM的时候发现的 ,截图中不是CKEditor编辑器吗,但是这又不是邮件里面使用的那种啊。怎么回事? 排障过程 鉴于CKEditor编辑器会在项目的window下面挂载变量CKEDITOR,通过在console下面查看CKEDITOR.instances发现里面还有一个实例xxx。通过CKEDITOR.instances是可以看出一些端倪的。 以官网的demo为例 我们可以看到smapleTitle的是某个contenteditable的div的id,并以此作为对应的实例名,而editor1~editor6是一些没有id的contenteditable的div,CKEditor自行递增创建的实例名。 然后就找到了IM的输入框,它是有id的,果然和CKEDITOR.instances下的匹配上了,也就确定上图中显示的工具栏是CKEditor作用在IM的输入框的结果了。 在我们没有明确配置的情况下,CKEditor为什么会自作聪明的作用在我们IM的输入框上呢? 在源码中找到答案 // src/core/creators/inline.js CKEDITOR.inlineAll = function() { var el, data; for ( var name in CKEDITOR.dtd.$editable ) { Read more…

CKEditor系列(六)改造原编辑器默认样式dom结构效果对比

熟悉的朋友应该知道之前是用的wangEditor,近期才迁移到CKEditor,很早的时候项目就支持一个叫“默认样式”的功能,需求就是部分BU希望能够统一邮件对外发送的样式,比如统一使用“宋体,黑色,18px”。 之前在wangEditor上是这么实现的 <p class="default-email-style" style="margin: 0px;font-size: 18px;font-family: 宋体;color: #000000;"> 关于这份预订,我们的客人希望获取酒店的确认号以确保后续入住,我司会在2小时后询问此事件的处理情况,若有任何进展,直接回复本邮件即可,谢谢。 </p> 也就是用了一个名为default-CtripEmail-style的class标记,然后将后台配置的样式全部赋值给这个class的行内样式。 为什么用行内样式 邮件项目为确保发送出去的邮件样式和编写时一致,最好的方案就是写行内样式 改成符合CKEditor的规则的是这样的 <div class="new-default-email-style"> <span class="new-default-fontFamily-style" style="font-family:宋体;"> <span class="new-default-color-style" style="color:#002060;"> <span class="new-default-fontSize-style" style="font-size:18px;"> 关于这份预订,我们的客人希望获取酒店的确认号以确保后续入住,我司会在2小时后询问此事件的处理情况,若有任何进展,直接回复本邮件即可,谢谢。 </span> </span> </span> </div> 还是用一个名为new-default-email-style的class包裹住容器,具体的每一个样式都需要单独使用一个span。 这样改动后CKEditor的功能就在默认样式区域(即new-default-email-style的区域),完全生效了。 效果图与wangEditor上面的一样。 为什么需要改变默认样式的dom结构呢? 这样因为和CKEditor及其它主流的编辑的使用规则不一致,导致编辑器的部分功能(格式刷、清除样式等)无法正确生效。 产生此问题的原因 因为编辑器认为样式是在span上的,不会识别其它标签(比如p、div)上的样式,无视上面的style样式,或者认为它上面没有样式。 改造前后效果对比 下面以清除样式为例来对比改造的效果对比 默认样式的dom结构改造前 A 选中下面的内容,进行清除样式。(老版dom结构) <p class="default-email-style" style="margin: 0px;font-size: 18px;font-family: 宋体;color: #000000;"> Read more…

CKEditor系列(五)编辑器内容的设置和获取过程

我们看一下CKEditor4的编辑器内容的设置和获取过程,也就是setData和getData过程。 我们在调用editor.setData的时候,调用的就是core/editor.js里面的setData方法。 // src/core/editor.js setData: function( data, options, internal ) { var fireSnapshot = true, // Backward compatibility. callback = options, eventData; if ( options && typeof options == 'object' ) { internal = options.internal; callback = options.callback; fireSnapshot = !options.noSnapshot; } if ( !internal && fireSnapshot ) this.fire( 'saveSnapshot' Read more…

docker容器配置文件出错后重启容器失败解决方案

最近经常修改docker容器里面的东西,无意中重启发现容器立即就挂了。。。慌的一批,总不能直接重新新建吧,虽然是没什么,但是数据呢? 想直接使用docker exec -it container-name /bin/bash进入容器是不行,docker exec只能进入到启动中的容器,那怎么办? 既然是修改某个配置重启后就失败的,那代表我们的此次修改有问题,我们删掉我们的改动点就好了,我们应该怎么才能找到刚才修改的文件了呢。 我们修改文件自己一般是能记住当时修改的文件的大致路径或者文件名的吧 我们有下面两种方案来实现,下面以修改nginx.conf为例 方法一:直接在主机上修改容器内文件 在当前主机中存放了docker容器中的配置信息(一般默认目录是:/var/lib/docker/overlay/或者/var/lib/docker/overlay2/),那只要找到这个配置文件,修改后就可以重新启动了啊 cd /var/lib/docker/overlay2 find ./ -name nginx.conf // 搜索刚才改动的配置文件 vim ./193410bff207ea4dfbadca74ffde3d8ce4b0195c1966659a607858e4b34e975c/diff/etc/nginx/nginx.conf docker start container-name 已经搜索到了,路径就是./193410bff207ea4dfbadca74ffde3d8ce4b0195c1966659a607858e4b34e975c/diff/etc/nginx/nginx.conf,我们直接修改该文件,把之前错误的改动还原就好了。 然后再启动容器就好了。 方法二:将容器内文件复制出来修改正确后再复制回去 容器虽然启动不了,但是我们仍然能用命令将里面的文件复制出来,或者复制进去的。 我们可以先把改动错误的文件复制出来 docker cp container-name:/etc/nginx/nginx.conf ./n.conf vim ./n.conf // 改成正确的配置 docker cp ./n.conf container-name:/etc/nginx/nginx.conf docker start container-name 大功告成了。