# Comment 通用评论系统及编辑器 **`version 0.5.14`** ```js import Comment, { Editor, RenderText } from 'comment'; ``` ## 使用 ### 作为组件使用 ``` # npm 安装 $ npm install git+https://git.links123.net/npm/comment.git --save # yarn 安装 $ yarn add git+https://git.links123.net/npm/comment.git ``` 然后在代码里面引入 `comment` 组件: ```jsx import Comment, { Editor } from 'comment' // ... render() { return ( ) } ``` **注意:最后,还需要在 HTML 文件里面引入阿里云 OSS SDK ``** ### 在非 React.js 项目中使用 ~~作为静态文件引入~~ **使用`assets` 分支的 `./assets/static` 目录[https://git.links123.net/npm/comment/src/branch/assets/assets/static](https://git.links123.net/npm/comment/src/branch/assets/assets/static)的静态文件** 1. 引入通用评论的 css 和 js 文件。在 `assets` 分支的 `./assets/static` 目录: [https://git.links123.net/npm/comment/src/branch/assets/assets/static](https://git.links123.net/npm/comment/src/branch/assets/assets/static)。 2. 调用 `window.renderComment` 方法并传入对应参数来渲染通用评论。参数列表: - `id`: string, 必填, 渲染评论的节点的 ID - `type`: number, 必填, 评论的 type - `businessId`: string, 选填, 评论的 businessId,默认 test - `API`: string, 选填, 评论的 businessId,默认 http://api.links123.net/comment/v1 具体可参考 `./assets/example.html`。 例子如下: ```html 通用评论 demo

在非 React.js 项目中使用通用评论

将其渲染到 id 为 `comment` 的节点上

``` #### 一个页面多次渲染评论 有的场景可能需要在一个页面上根据不同 bid 多次渲染评论,可以参考 `./assets/example/rerender.html`。 其方案就是,每次渲染之前,都清空之前渲染的节点内容,再重新渲染。否则 React 会任务两次 render 是同样的内容,就不渲染。 详解: 1. 首先清空父标签的内容 2. 动态创建渲染评论的标签 3. 渲染评论 ```html
``` ```js var RENDER_ELEMENT_WRAPPER = 'RENDER_ELEMENT_WRAPPER'; // 渲染评论的父标签 var RENDER_ELEMENT_COMMENT = 'comment'; // 渲染评论的标签的 id /** * 根据 id 创建节点 * @param {string} id id */ function createElement(id) { var node = document.createElement('div'); node.setAttribute("id", id); document.getElementById(RENDER_ELEMENT_WRAPPER).appendChild(node); } /** * 根据 id 删除子节点 * @param {string} id id */ function removeChild(id) { var myNode = document.getElementById(id); while (myNode.firstChild) { myNode.removeChild(myNode.firstChild); } } function main() { document.getElementById('render').addEventListener('click', function() { // 首先清空父标签的内容 removeChild(RENDER_ELEMENT_WRAPPER); var id = RENDER_ELEMENT_COMMENT; // 动态创建渲染评论的标签 createElement(id); // 渲染评论 window.renderComment({ id: id, type: 1, businessId: 'test', API: 'http://api.links123.net/comment/v1', }) }) document.getElementById('re-render').addEventListener('click', function() { removeChild(RENDER_ELEMENT_WRAPPER) var id = RENDER_ELEMENT_COMMENT; createElement(id) window.renderComment({ id: id, type: 1, businessId: 'test1', API: 'http://api.links123.net/comment/v1', }) }) } main(); ``` #### ~~class 样式冲突~~ > assets 分支已修复。 ~~`master` 分支的图片预览 `container` 样式和 boostrap 有冲突。在 [`fix/classname`](https://git.links123.net/node/npmcomment/src/branch/fix/classname) 分支对评论的样式名称做了修改,改为了 `comment-image-preview-container`。~~ 解决办法就是使用 [`fix/classname`](https://git.links123.net/node/npmcomment/src/branch/fix/classname) 分支中的静态文件: - [https://git.links123.net/node/npmcomment/src/branch/fix/classname](https://git.links123.net/node/npmcomment/src/branch/fix/classname) - static: [https://git.links123.net/node/npmcomment/src/branch/fix/classname/assets/static](https://git.links123.net/node/npmcomment/src/branch/fix/classname/assets/static) > 尝试过使用 CSS Module 进行修改,不过改造量较大,改动的过程中影响了其他样式,所以暂时放弃了。 ## Comment - 标记了`deprecated`的配置项表示不推荐使用,并且可能在将来版本中不再受支持。 | props | type | default | required | description | | |-------------------|----------------|------------------------------------|----------|---------------------------------------------------|--------------------------| | type | number | | true | 评论的 type | | | businessId | string | | true | 评论的 business id | | | API | string | http://api.links123.net/comment/v1 | false | API 前缀 | | | showList | boolean | true | false | 是否显示评论列表 | | | showEditor | boolean | true | false | 是否显示评论输入框 | | | showAlertComment | boolean | false | false | 评论成功之后,是否通过 Antd 的 Message 组件进行提示 | | | showAlertReply | boolean | false | false | 回复成功之后,是否通过 Antd 的 Message 组件进行提示 | | | showAlertFavor | boolean | false | false | 点赞/取消点赞成功之后,是否通过 Antd 的 Message 组件进行提示 | | | showError | boolean | true | false | 是否使用Antd的Message组件提示错误信息 | | | onError | function(msg) | | false | 错误回调, 出错了会被调用 | | | userId | number | | false | 用户id, comment内部不维护用户id, 调用组件时传递过来, 目前用于判断是否显示删除按钮 | | | token | string | | false | [deprecated] token,用于身份认证,非必须。默认使用 cookie | | | pageType | string | more | false | 分页类别, more-加载更多 pagination-页码 | | | page | number | | false | 页码受控模式,如果传递了此参数,则需要通过onPageChange回调手动维护page. | | | limit | number | 10 | false | 一次加载的评论数量 | | | onGetMoreBtnClick | function() | | false | 点击查看更多按钮的回调 | | | onPageChange | function(page) | | false | 页码发生变化时的回调,注意:分页数据获取还是在组件内部处理的 | | | onDelete | function(type) | | false | 评论或回复删除成功后的回调, type: "comment" \ | "reply" , 用于区分删除的是评论还是回复 | | locales | string | 语言 | false | | | | businessUserId | number | | false | 评论目标的用户id, 用于发送通知 | | ## Editor | props | type | default | required | description | |---------------------|---------------------------------|----------|----------|---------------------------------------------------------------------| | rows | number | 5 | false | 编辑器的高度。默认情况下,回复评论/回复回复的编辑器会比评论的编辑器高度小一行 | | placeholder | string | 说点什么吧... | false | 评论的中的提示文字 | | showEmoji | boolean | true | false | 是否显示 Toolbar 中表情工具 | | showUpload | boolean | true | false | 是否显示 Toolbar 中 上传图片工具 | | maxUpload | number | 1 | false | 最大能够上传的图片数量 | | value | string | | false | 编辑器的值。如果设置了该属性,则编辑器变为受控组件,需要父组件来维护 value | | onChange | function(value) | | false | 编辑器内容改变的回调函数 | | onSubmit | function({ text, files }) | | false | 点击提交按钮的回调函数,text 为编辑器的文本,files 为上传的文件列表 | | beforeSubmit | function ({text,files}):Promise | | false | 点击提交按钮后的钩子, 若Promise resolve false则不触发onSubmit函数, 主要用于控制默认的submit行为 | | onCommentSuccess | function() | | false | 提交评论成功后的回调 | | btnSubmitText | string | 发表 | false | 提交按钮的文字 | | btnLoading | boolean | false | false | 按钮是否正在加载中 | | btnDisable | boolean | false | false | 按钮是否禁用 | | button | ReactNode | | false | 按钮组件。如果上面几个 btn 相关的属性都无法满足要求,则可以使用 button 来自定义提交编辑器值的按钮 | | emojiToolIcon | ReactNode | | false | Toolbar 中表情的图标 | | imageToolIcon | ReactNode | | false | Toolbar 中上传文件的图标 | | onRef | function | | false | 传递子组件的引用 | | closeUploadWhenBlur | boolean | | false | 当 upload 失去焦点(鼠标点击非 Upload 的区域)的时候,是否自动关闭 Popover | | showError | boolean | true | false | 是否使用Antd的Message组件提示错误信息, 主要是上传图片出错的情况 | | onError | function(msg,{response}) | | false | 错误回调, 出错了会被调用, 主要是上传图片出错的情况 | | maxLength | number | 140 | false | 限制最大输入字数 | | autoFocus | boolean | false | false | 编辑器自动聚焦 | ### 什么时候不要使用 value/onChange/onSubmit 如果将 `comment` 作为通用评论组件,则不要使用 `value` `onChange` `onSubmit`。因为组件内部,实现了通用评论的业务逻辑。 **可以使用 value/onChange/onSubmit 的情况:** - 单独使用其中的 `Editor`。即 `import { Editor } from 'comment'` - 不需要展示评论列表,即设置 `showList: false` ```jsx // 单独使用 Editor this.setState({ value })} /> // 不需要展示评论列表 this.setState({ value })} /> ``` ### button 如果使用 `button`,则 `btnLoading` `btnDisable` `btnSubmitText` 都会失效。因为这些属性是针对于编辑器默认的提交按钮设置的。 所以如果要提交编辑器的值,需要自己在 `Button` 组件上实现提交功能。编辑器的值,可以通过 `onChange` 方法获取到。 如果使用了 `button` 属性,并且没有为其设置 `onClick` 方法,则 `onClick` 默认为发布评论,即点击按钮会发表评论: ```jsx // 如下代码所示 // 点击“自定义按钮”的时候,会发表评论。这是由 Comment 组件内部实现的业务逻辑 自定义按钮 )} /> ``` 如果使用了 `button` 属性,并且设置了 `onClick` 方法,则会覆盖默认的 `onClick` 方法: ```jsx // 下面的代码,点击的时候,不会提交评论 // 而是会输出 state 的值( // 即编辑器的值,因为 onChange 将编辑器输入的值通过回调函数传递给了父组件) this.setState({ value })} onClick={() => console.log(this.state.value)} > 自定义按钮 )} value={this.state.value} /> ``` ### onRef 如果你需要在父组件里面调用子组件的方法,就可以使用 `onRef`。主要是用于调用 Editor 组件内部的 `resetState` 方法。 如果你需要在父组件里面,手动清空 Editor 里面的数据,则可以使用 `resetState`。因为即使父组件传入了 `value`, Editor 内部也会保存一份 `value` 的值,用于 `onSubmit` 回调将值传递给父组件。所以可能存在,当子组件值没有清除,而父组件的 `value` 为空的情况,导致编辑器中文字和实际预想的不一致。所以当在父组件里面使用了 `value` 并重置 `value` 的时候,最好清空 Editor 的 state。 具体使用方式如下: ```jsx handleChangeSubmit() { // 点击按钮,调用 onSubmit 的时候,清空 Editor 的数据 this.editor.resetState(); } this.editor = ref } onSubmit={() => this.handleChangeSubmit()} /> ``` **注意上面的 `onRef={ref => this.editor = ref }`**,这是实现父组件调用子组件方法的关键。** ## RenderText ```jsx import { RenderText } from 'comment'; render() { return RenderText('test [呲牙]') } ``` ## 开发 ``` $ git clone https://git.links123.net/npm/comment $ cd comment $ yarn $ yarn start ``` - `yarn build` 将项目打包成一个单页应用 - `yarn lib` 将项目打包成一个 es5 组件 - `yarn prettier` 优化代码格式 ## TODO - [x] 前后端统一错误码 - [x] type 和 businessID 的定义 - [x] Editor onSubmit 回调 - [x] 对评论的回复点赞,报错 - [x] oss/sts 接口报错 - [ ] 头像 404 `https://links123-images.oss-cn-hangzhou.aliyuncs.com/avatar/` - [ ] 上传图片的时候偶尔会出现InvalidPart - [ ] 上传图片失败时, 提示并且不显示缩略图