├── .browserslistrc ├── .editorconfig ├── .gitignore ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── _config.yml ├── dist ├── css │ ├── litewebchat.css │ ├── litewebchat.min.css │ ├── litewebchat_input.css │ ├── litewebchat_input.min.css │ └── map │ │ ├── litewebchat.css.map │ │ ├── litewebchat.min.css.map │ │ ├── litewebchat_input.css.map │ │ └── litewebchat_input.min.css.map ├── html │ ├── chat_example.html │ ├── chat_with_inputarea_example.html │ └── chat_with_inputarea_module_example.html ├── images │ ├── A.jpg │ ├── B.jpg │ ├── H.jpg │ ├── O.jpg │ ├── img.png │ └── img2.png └── js │ ├── litewebchat_input.js │ ├── litewebchat_input.min.js │ ├── litewebchat_render.js │ ├── litewebchat_render.min.js │ └── map │ ├── litewebchat_input.js.map │ ├── litewebchat_input.min.js.map │ ├── litewebchat_render.js.map │ └── litewebchat_render.min.js.map ├── gulpfile.js ├── lite-chatbox.min.js ├── litewebchat.min.css ├── litewebchatinput.min.css ├── litewebchatinput.min.js ├── package.json ├── pnpm-lock.yaml └── src ├── css ├── _variable.scss ├── chatinput.scss ├── components │ ├── color-htitle │ │ └── _index.scss │ ├── color-scrollbar │ │ └── _index.scss │ ├── color-tips │ │ └── _index.scss │ ├── htitle │ │ └── _index.scss │ └── tips │ │ └── _index.scss ├── index.scss ├── mixin │ ├── _helper.scss │ └── _theme.scss └── variable │ ├── _colors.scss │ └── color │ ├── _htitle.scss │ └── _tips.scss ├── images ├── A.jpg ├── B.jpg ├── H.jpg ├── O.jpg ├── img.png └── img2.png ├── js ├── .babelrc.json ├── input.js └── render.js └── pug ├── chat_example.pug ├── chat_with_inputarea_example.pug └── chat_with_inputarea_module_example.pug /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 5% 2 | last 3 versions 3 | ie >= 11 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.history/ 2 | /.idea/ 3 | 4 | # Created by https://www.toptal.com/developers/gitignore/api/node 5 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 6 | 7 | ### Node ### 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | lerna-debug.log* 15 | .pnpm-debug.log* 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 19 | 20 | # Runtime data 21 | pids 22 | *.pid 23 | *.seed 24 | *.pid.lock 25 | 26 | # Directory for instrumented libs generated by jscoverage/JSCover 27 | lib-cov 28 | 29 | # Coverage directory used by tools like istanbul 30 | coverage 31 | *.lcov 32 | 33 | # nyc test coverage 34 | .nyc_output 35 | 36 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 37 | .grunt 38 | 39 | # Bower dependency directory (https://bower.io/) 40 | bower_components 41 | 42 | # node-waf configuration 43 | .lock-wscript 44 | 45 | # Compiled binary addons (https://nodejs.org/api/addons.html) 46 | build/Release 47 | 48 | # Dependency directories 49 | node_modules/ 50 | jspm_packages/ 51 | 52 | # Snowpack dependency directory (https://snowpack.dev/) 53 | web_modules/ 54 | 55 | # TypeScript cache 56 | *.tsbuildinfo 57 | 58 | # Optional npm cache directory 59 | .npm 60 | 61 | # Optional eslint cache 62 | .eslintcache 63 | 64 | # Optional stylelint cache 65 | .stylelintcache 66 | 67 | # Microbundle cache 68 | .rpt2_cache/ 69 | .rts2_cache_cjs/ 70 | .rts2_cache_es/ 71 | .rts2_cache_umd/ 72 | 73 | # Optional REPL history 74 | .node_repl_history 75 | 76 | # Output of 'npm pack' 77 | *.tgz 78 | 79 | # Yarn Integrity file 80 | .yarn-integrity 81 | 82 | # dotenv environment variable files 83 | .env 84 | .env.development.local 85 | .env.test.local 86 | .env.production.local 87 | .env.local 88 | 89 | # parcel-bundler cache (https://parceljs.org/) 90 | .cache 91 | .parcel-cache 92 | 93 | # Next.js build output 94 | .next 95 | out 96 | 97 | # Nuxt.js build / generate output 98 | .nuxt 99 | 100 | # Gatsby files 101 | .cache/ 102 | # Comment in the public line in if your project uses Gatsby and not Next.js 103 | # https://nextjs.org/blog/next-9-1#public-directory-support 104 | # public 105 | 106 | # vuepress build output 107 | .vuepress/dist 108 | 109 | # vuepress v2.x temp and cache directory 110 | .temp 111 | 112 | # Docusaurus cache and generated files 113 | .docusaurus 114 | 115 | # Serverless directories 116 | .serverless/ 117 | 118 | # FuseBox cache 119 | .fusebox/ 120 | 121 | # DynamoDB Local files 122 | .dynamodb/ 123 | 124 | # TernJS port file 125 | .tern-port 126 | 127 | # Stores VSCode versions used for testing VSCode extensions 128 | .vscode-test 129 | 130 | # yarn v2 131 | .yarn/cache 132 | .yarn/unplugged 133 | .yarn/build-state.yml 134 | .yarn/install-state.gz 135 | .pnp.* 136 | 137 | ### Node Patch ### 138 | # Serverless Webpack directories 139 | .webpack/ 140 | 141 | # Optional stylelint cache 142 | 143 | # SvelteKit build / generate output 144 | .svelte-kit 145 | 146 | # End of https://www.toptal.com/developers/gitignore/api/node 147 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "editorconfig.editorconfig" 4 | ] 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 轻网页聊天框架 2 | 3 | ![演示](https://i.loli.net/2018/12/08/5c0bba10d25da.png) 4 | 5 | 在线演示: 6 | 7 | - [~~性感聊天在线观看~~](https://lab.morfans.cn/LiteWebChat_Frame/dist/html/chat_example.html) 8 | - [带输入框表情选取](https://lab.morfans.cn/LiteWebChat_Frame/dist/html/chat_with_inputarea_example.html) 9 | - [带输入框表情选取简单 JS 渲染](https://lab.morfans.cn/LiteWebChat_Frame/dist/html/chat_with_inputarea_module_example.html) 10 | 11 | [本框架](https://github.com/MorFansLab/LiteWebChat_Frame) 大部分聊天对话所要求的样式特性已完成,能够助你快速开发聊天类对话界面 12 | 13 | ## 使用~~指南~~ (指北) 14 | 15 | ### 获取 LiteWebChat 16 | 17 | 我们提供了多种方式来获取 LiteWebChat_Frame, ~~你也可以通过各种奇淫技巧获取使用。~~ 18 | 19 | #### 1.下载文件 20 | 21 | 你可以直接从 GitHub 项目 [官网](https://github.com/MorFansLab/LiteWebChat_Frame) 直接克隆下载,其中 dist 目录包含了压缩过的和未压缩过的 CSS、JS 、示例以及图片文件。 22 | 23 | #### 2.直接引用 24 | 25 | ##### 对话框 26 | 27 | ```html 28 | 29 | 34 | 35 | 36 | 41 | ``` 42 | 43 | ##### 输入框 44 | 45 | > **注意:对话框可以单独被使用,输入框必须和对话框配合使用。** 46 | 47 | ```html 48 | 53 | 54 | 55 | 56 | 57 | 58 | ``` 59 | 60 | ## 使用 LiteWebChat 61 | 62 | ### 仅对话框 63 | 64 | 所需文件: 65 | 66 | - 样式:`litewebchat(.min).css` 67 | 68 | ```html 69 |
...
70 | ``` 71 | 72 | ### 对话框和输入框 73 | 74 | 所需文件: 75 | 76 | - 样式 77 | - 对话框:`litewebchat(.min).css` 78 | - 输入框:`litewebchat_input(.min).css` 79 | - 脚本 80 | - 输入框:`litewebchat_input(.min).js` 81 | - 消息渲染:`litewebchat_render(.min).js` 82 | 83 | ```html 84 | 85 |
86 | 87 |
...
88 | 89 | 90 |
...
91 | 92 | 93 |
...
94 |
95 | ``` 96 | 97 | **注意:使用输入框时需要手动指定其父容器大小。** 98 | 99 | Example: 100 | 101 | ```css 102 | /* 全局,当整个HTML页面都是聊天窗口的时候取消body的margin 和 padding,这样比较好看 */ 103 | 104 | html, 105 | body { 106 | height: 100%; 107 | margin: 0; 108 | padding: 0; 109 | overflow: hidden; 110 | } 111 | 112 | /* 手动指定其父容器大小 */ 113 | .lite-chatmaster { 114 | height: 100%; 115 | width: 100%; 116 | } 117 | ``` 118 | 119 | 可以参考配合一下简易的 JS 消息渲染: 120 | 121 | - 效果和使用参考:[带输入框表情选取简单 JS 渲染](https://lab.morfans.cn/LiteWebChat_Frame/dist/html/chat_with_inputarea_module_example.html) 122 | 123 | 参数字段: 124 | 125 | - messageType:消息类型 126 | - 可选值: 127 | - 系统提示 128 | - tipsNormal 129 | - tipsPrimary 130 | - tipsSuccess 131 | - tipsInfo 132 | - tipsWarning 133 | - tipsDanger 134 | - 消息 135 | - text:普通消息类型 136 | - raw:不会转义消息类型 137 | - html:object 内容 138 | - headIcon:头像图片地址 139 | - diamond:是否使用方块头像样式 140 | - bool 141 | - name:用户名 142 | - position:消息位置 143 | - left 144 | - right 145 | - htitleType: 头衔类型 146 | - admin 147 | - owner 148 | - 不写则是默认 149 | - htitle:头衔标题 150 | 151 | 使用示例: 152 | 153 | ```html 154 | 155 | 156 | 179 | 192 | ``` 193 | 194 | ## 组件 195 | 196 | ### 主题 197 | 198 | LiteWebChat 目前有 `light` 和 `dark` 两款主题。 199 | 200 | 切换主题方式非常简单,只需添加 html 的属性 `itewebchat-theme`: 201 | 202 | ```html 203 | 204 | .... 205 | 206 | ``` 207 | 208 | ### 聊天气泡 209 | 210 | ![气泡](https://i.loli.net/2018/12/08/5c0bc50bd0674.png) 211 | 212 | | 组件(类名) | Class 附加类名 / 备注 | 213 | | -------------------- | ---------------------------------------------------- | 214 | | 聊天气泡组件(cmsg) | cleft(左边) / cright(右边) | 215 | | 头像 (headIcon) | 默认方形 / radius(圆形头像) | 216 | | 头衔 (htitle) | 默认成员头衔 / admin(管理头衔) / owner(群主头衔) | 217 | | 名称(name) | 为空使用 ‘ ’ | 218 | | 聊天内容(content) | - | 219 | 220 | Example: 221 | 222 | ```html 223 |
224 | 230 | SuperPaxxs 231 | LiteChat_Frame(轻聊天气泡框架),一个贼简洁 233 | (简单) 、美观、易用的 HTML 聊天界面框架 235 |
236 | ``` 237 | 238 | ### 系统提示 239 | 240 | ![提示](https://i.loli.net/2018/12/08/5c0bcfbbbce7b.png) 241 | 242 | | 类名 | 效果 | 243 | | ------------ | ------------- | 244 | | tips | 正常 | 245 | | tips-primary | 首要的提示 | 246 | | tips-success | 成功提示 | 247 | | tips-info | 信息提示 | 248 | | tips-warning | 警告提示 | 249 | | tips-danger | 错误/危险提示 | 250 | 251 | Example: 252 | 253 | ```html 254 |
255 | 系统消息:左/右边长消息被管理员批判一番…… 256 |
257 | 258 |
259 | 系统消息:normal 260 |
261 | ``` 262 | 263 | ### 输入框 264 | 265 | ![输入框](https://i.postimg.cc/t4G1Crj6/input.png) 266 | 267 | | 组件(HTML 标签) | 是否必备 | 类名 | 备注 | 268 | | --------------------------- | -------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------- | 269 | | 文字输入框(<textarea>) | 是 | chatinput | Class:lite-chatinput 内只能存在一个 textarea 标签 | 270 | | 发送按钮(<button>) | 是 | send | Class:lite-chatinput 内只能存在一个发送按钮 | 271 | | 分界线(<hr>) | 是 | boundary | 充当输入框和对话框之间的分界线 | 272 | | 工具栏按钮(<button>) | 否 | tool-button(必选)、float-right/float-left(二选一) | 用于充当表情按钮等工具栏控件,类名 float-left 和 类名 float-right 决定其对齐方式(左对齐/右对齐)。 | 273 | 274 | Example: 275 | 276 | ```html 277 | 278 |
279 | 280 |
281 | 282 | 283 | 298 | 299 | 312 | 313 | 326 | 327 | 339 | 340 | 353 | 354 |
360 | 361 | 362 |
363 | ``` 364 | 365 | **注意:使用发送文件按钮时需要手动设置用于发送文件的函数。** 366 | 367 | Example: 368 | 369 | ```html 370 | 371 | 387 | ``` 388 | 389 | ### 输入框使用的工具栏 390 | 391 | 输入框使用的工具栏会在点击工具栏按钮后弹出。 392 | 393 | Example(最简): 394 | 395 | ```html 396 |
397 | 398 | 399 |
400 | ``` 401 | 402 | ## 兼容性 403 | 404 | 兼容 Firefox 和其他主流浏览器的最新版本。 405 | 406 | ## 开发 407 | 408 | 使用 pnpm 或 npm 或 yarn,以 pnpm 为例: 409 | 410 | ``` 411 | pnpm i 412 | 413 | pnpm run build 414 | ``` 415 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /dist/css/litewebchat.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | */@charset "UTF-8"; 6 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 7 | /* Document 8 | ========================================================================== */ 9 | /** 10 | * 1. Correct the line height in all browsers. 11 | * 2. Prevent adjustments of font size after orientation changes in iOS. 12 | */ 13 | html { 14 | line-height: 1.15; /* 1 */ 15 | -webkit-text-size-adjust: 100%; /* 2 */ 16 | } 17 | 18 | /* Sections 19 | ========================================================================== */ 20 | /** 21 | * Remove the margin in all browsers. 22 | */ 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | main { 31 | display: block; 32 | } 33 | 34 | /** 35 | * Correct the font size and margin on `h1` elements within `section` and 36 | * `article` contexts in Chrome, Firefox, and Safari. 37 | */ 38 | h1 { 39 | font-size: 2em; 40 | margin: 0.67em 0; 41 | } 42 | 43 | /* Grouping content 44 | ========================================================================== */ 45 | /** 46 | * 1. Add the correct box sizing in Firefox. 47 | * 2. Show the overflow in Edge and IE. 48 | */ 49 | hr { 50 | -webkit-box-sizing: content-box; 51 | box-sizing: content-box; /* 1 */ 52 | height: 0; /* 1 */ 53 | overflow: visible; /* 2 */ 54 | } 55 | 56 | /** 57 | * 1. Correct the inheritance and scaling of font size in all browsers. 58 | * 2. Correct the odd `em` font sizing in all browsers. 59 | */ 60 | pre { 61 | font-family: monospace, monospace; /* 1 */ 62 | font-size: 1em; /* 2 */ 63 | } 64 | 65 | /* Text-level semantics 66 | ========================================================================== */ 67 | /** 68 | * Remove the gray background on active links in IE 10. 69 | */ 70 | a { 71 | background-color: transparent; 72 | } 73 | 74 | /** 75 | * 1. Remove the bottom border in Chrome 57- 76 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 77 | */ 78 | abbr[title] { 79 | border-bottom: none; /* 1 */ 80 | text-decoration: underline; /* 2 */ 81 | -webkit-text-decoration: underline dotted; 82 | text-decoration: underline dotted; /* 2 */ 83 | } 84 | 85 | /** 86 | * Add the correct font weight in Chrome, Edge, and Safari. 87 | */ 88 | b, 89 | strong { 90 | font-weight: bolder; 91 | } 92 | 93 | /** 94 | * 1. Correct the inheritance and scaling of font size in all browsers. 95 | * 2. Correct the odd `em` font sizing in all browsers. 96 | */ 97 | code, 98 | kbd, 99 | samp { 100 | font-family: monospace, monospace; /* 1 */ 101 | font-size: 1em; /* 2 */ 102 | } 103 | 104 | /** 105 | * Add the correct font size in all browsers. 106 | */ 107 | small { 108 | font-size: 80%; 109 | } 110 | 111 | /** 112 | * Prevent `sub` and `sup` elements from affecting the line height in 113 | * all browsers. 114 | */ 115 | sub, 116 | sup { 117 | font-size: 75%; 118 | line-height: 0; 119 | position: relative; 120 | vertical-align: baseline; 121 | } 122 | 123 | sub { 124 | bottom: -0.25em; 125 | } 126 | 127 | sup { 128 | top: -0.5em; 129 | } 130 | 131 | /* Embedded content 132 | ========================================================================== */ 133 | /** 134 | * Remove the border on images inside links in IE 10. 135 | */ 136 | img { 137 | border-style: none; 138 | } 139 | 140 | /* Forms 141 | ========================================================================== */ 142 | /** 143 | * 1. Change the font styles in all browsers. 144 | * 2. Remove the margin in Firefox and Safari. 145 | */ 146 | button, 147 | input, 148 | optgroup, 149 | select, 150 | textarea { 151 | font-family: inherit; /* 1 */ 152 | font-size: 100%; /* 1 */ 153 | line-height: 1.15; /* 1 */ 154 | margin: 0; /* 2 */ 155 | } 156 | 157 | /** 158 | * Show the overflow in IE. 159 | * 1. Show the overflow in Edge. 160 | */ 161 | button, 162 | input { /* 1 */ 163 | overflow: visible; 164 | } 165 | 166 | /** 167 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 168 | * 1. Remove the inheritance of text transform in Firefox. 169 | */ 170 | button, 171 | select { /* 1 */ 172 | text-transform: none; 173 | } 174 | 175 | /** 176 | * Correct the inability to style clickable types in iOS and Safari. 177 | */ 178 | button, 179 | [type=button], 180 | [type=reset], 181 | [type=submit] { 182 | -webkit-appearance: button; 183 | } 184 | 185 | /** 186 | * Remove the inner border and padding in Firefox. 187 | */ 188 | button::-moz-focus-inner, 189 | [type=button]::-moz-focus-inner, 190 | [type=reset]::-moz-focus-inner, 191 | [type=submit]::-moz-focus-inner { 192 | border-style: none; 193 | padding: 0; 194 | } 195 | 196 | /** 197 | * Restore the focus styles unset by the previous rule. 198 | */ 199 | button:-moz-focusring, 200 | [type=button]:-moz-focusring, 201 | [type=reset]:-moz-focusring, 202 | [type=submit]:-moz-focusring { 203 | outline: 1px dotted ButtonText; 204 | } 205 | 206 | /** 207 | * Correct the padding in Firefox. 208 | */ 209 | fieldset { 210 | padding: 0.35em 0.75em 0.625em; 211 | } 212 | 213 | /** 214 | * 1. Correct the text wrapping in Edge and IE. 215 | * 2. Correct the color inheritance from `fieldset` elements in IE. 216 | * 3. Remove the padding so developers are not caught out when they zero out 217 | * `fieldset` elements in all browsers. 218 | */ 219 | legend { 220 | -webkit-box-sizing: border-box; 221 | box-sizing: border-box; /* 1 */ 222 | color: inherit; /* 2 */ 223 | display: table; /* 1 */ 224 | max-width: 100%; /* 1 */ 225 | padding: 0; /* 3 */ 226 | white-space: normal; /* 1 */ 227 | } 228 | 229 | /** 230 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 231 | */ 232 | progress { 233 | vertical-align: baseline; 234 | } 235 | 236 | /** 237 | * Remove the default vertical scrollbar in IE 10+. 238 | */ 239 | textarea { 240 | overflow: auto; 241 | } 242 | 243 | /** 244 | * 1. Add the correct box sizing in IE 10. 245 | * 2. Remove the padding in IE 10. 246 | */ 247 | [type=checkbox], 248 | [type=radio] { 249 | -webkit-box-sizing: border-box; 250 | box-sizing: border-box; /* 1 */ 251 | padding: 0; /* 2 */ 252 | } 253 | 254 | /** 255 | * Correct the cursor style of increment and decrement buttons in Chrome. 256 | */ 257 | [type=number]::-webkit-inner-spin-button, 258 | [type=number]::-webkit-outer-spin-button { 259 | height: auto; 260 | } 261 | 262 | /** 263 | * 1. Correct the odd appearance in Chrome and Safari. 264 | * 2. Correct the outline style in Safari. 265 | */ 266 | [type=search] { 267 | -webkit-appearance: textfield; /* 1 */ 268 | outline-offset: -2px; /* 2 */ 269 | } 270 | 271 | /** 272 | * Remove the inner padding in Chrome and Safari on macOS. 273 | */ 274 | [type=search]::-webkit-search-decoration { 275 | -webkit-appearance: none; 276 | } 277 | 278 | /** 279 | * 1. Correct the inability to style clickable types in iOS and Safari. 280 | * 2. Change font properties to `inherit` in Safari. 281 | */ 282 | ::-webkit-file-upload-button { 283 | -webkit-appearance: button; /* 1 */ 284 | font: inherit; /* 2 */ 285 | } 286 | 287 | /* Interactive 288 | ========================================================================== */ 289 | /* 290 | * Add the correct display in Edge, IE 10+, and Firefox. 291 | */ 292 | details { 293 | display: block; 294 | } 295 | 296 | /* 297 | * Add the correct display in all browsers. 298 | */ 299 | summary { 300 | display: list-item; 301 | } 302 | 303 | /* Misc 304 | ========================================================================== */ 305 | /** 306 | * Add the correct display in IE 10+. 307 | */ 308 | template { 309 | display: none; 310 | } 311 | 312 | /** 313 | * Add the correct display in IE 10. 314 | */ 315 | [hidden] { 316 | display: none; 317 | } 318 | 319 | * { 320 | scrollbar-color: #5c6163 rgba(56, 59, 60, 0.031372549); 321 | } 322 | 323 | /* else broswer */ 324 | ::-webkit-scrollbar { 325 | /* 滚动条整体样式 */ 326 | width: 7px; 327 | /* 高宽分别对应横竖滚动条的尺寸 */ 328 | height: 1px; 329 | } 330 | 331 | ::-webkit-scrollbar-thumb { 332 | /*滚动条里面小方块*/ 333 | border-radius: 10px; 334 | background-color: rgba(144, 147, 153, 0.5); 335 | border: 0; 336 | } 337 | [litewebchat-theme=dark] ::-webkit-scrollbar-thumb { 338 | background-color: rgba(84, 91, 95, 0.5); 339 | } 340 | 341 | ::-webkit-scrollbar-track { 342 | /*滚动条里面轨道*/ 343 | background: #fff; 344 | min-height: 50%; 345 | min-height: 20px; 346 | } 347 | [litewebchat-theme=dark] ::-webkit-scrollbar-track { 348 | background: rgb(24, 26, 27); 349 | } 350 | 351 | ::-webkit-scrollbar-corner { 352 | background-color: transparent; 353 | } 354 | 355 | ::-moz-selection { 356 | background-color: #1963bd !important; 357 | color: #f8f6f3 !important; 358 | } 359 | 360 | ::selection { 361 | background-color: #1963bd !important; 362 | color: #f8f6f3 !important; 363 | } 364 | 365 | body { 366 | font-family: Helvetica, "PingFang SC", "Microsoft YaHei", sans-serif; 367 | } 368 | 369 | .lite-chatbox { 370 | scroll-behavior: smooth; 371 | padding: 0px; 372 | width: 100%; 373 | position: relative; 374 | font-size: 18px; 375 | background-color: #f8f9fa; 376 | overflow-y: auto; 377 | overflow-x: hidden; 378 | } 379 | .lite-chatbox .tips { 380 | margin: 12px; 381 | text-align: center; 382 | font-size: 12px; 383 | } 384 | .lite-chatbox .tips span { 385 | display: inline-block; 386 | padding: 4px; 387 | background-color: #ccc; 388 | color: #fff; 389 | border-radius: 6px; 390 | } 391 | [litewebchat-theme=dark] .lite-chatbox .tips span { 392 | background-color: rgba(0, 0, 0, 0.3); 393 | } 394 | [litewebchat-theme=dark] .lite-chatbox .tips span { 395 | color: #bec5cc; 396 | } 397 | .lite-chatbox .tips .tips-primary { 398 | background-color: #3986c8; 399 | } 400 | [litewebchat-theme=dark] .lite-chatbox .tips .tips-primary { 401 | background-color: rgb(68, 127, 178); 402 | } 403 | .lite-chatbox .tips .tips-success { 404 | background-color: #49b649; 405 | } 406 | [litewebchat-theme=dark] .lite-chatbox .tips .tips-success { 407 | background-color: rgb(102, 166, 81); 408 | } 409 | .lite-chatbox .tips .tips-info { 410 | background-color: #5bb6d1; 411 | } 412 | [litewebchat-theme=dark] .lite-chatbox .tips .tips-info { 413 | background-color: rgb(63, 136, 158); 414 | } 415 | .lite-chatbox .tips .tips-warning { 416 | background-color: #eea948; 417 | } 418 | [litewebchat-theme=dark] .lite-chatbox .tips .tips-warning { 419 | background-color: rgb(175, 119, 40); 420 | } 421 | .lite-chatbox .tips .tips-danger { 422 | background-color: #e24d48; 423 | } 424 | [litewebchat-theme=dark] .lite-chatbox .tips .tips-danger { 425 | background-color: rgb(173, 53, 49); 426 | } 427 | [litewebchat-theme=dark] .lite-chatbox { 428 | background-color: #131415; 429 | } 430 | .lite-chatbox .cmsg { 431 | position: relative; 432 | margin: 4px 7px; 433 | min-height: 50px; 434 | border: 0; 435 | } 436 | .lite-chatbox .cright { 437 | text-align: right; 438 | margin-left: 64px; 439 | } 440 | .lite-chatbox .cright img.headIcon { 441 | right: 0; 442 | } 443 | .lite-chatbox .cright .name { 444 | margin: 0 48px 2px 0; 445 | } 446 | .lite-chatbox .cright .content { 447 | margin: 0 48px 0 0; 448 | border-radius: 20px 0 20px 20px; 449 | color: white; 450 | background: -o-linear-gradient(70deg, rgba(63, 143, 225, 0.8) 0%, #44d7c9 100%); 451 | background: linear-gradient(20deg, rgba(63, 143, 225, 0.8) 0%, #44d7c9 100%); 452 | -webkit-box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.15); 453 | box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.15); 454 | } 455 | [litewebchat-theme=dark] .lite-chatbox .cright .content { 456 | background: -o-linear-gradient(70deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%); 457 | background: linear-gradient(20deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%); 458 | } 459 | .lite-chatbox .cright .content::after { 460 | left: -12px; 461 | top: 8px; 462 | } 463 | .lite-chatbox .cleft { 464 | text-align: left; 465 | margin-right: 64px; 466 | } 467 | .lite-chatbox .cleft img.headIcon { 468 | left: 0; 469 | } 470 | .lite-chatbox .cleft .name { 471 | margin: 0 0 2px 48px; 472 | } 473 | .lite-chatbox .cleft .content { 474 | margin: 0 0 0 48px; 475 | border-radius: 0 20px 20px 20px; 476 | background: #fff; 477 | color: #373737; 478 | border: 1px solid rgba(0, 0, 0, 0.05); 479 | -webkit-box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1); 480 | box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1); 481 | } 482 | [litewebchat-theme=dark] .lite-chatbox .cleft .content { 483 | background: #22242a; 484 | } 485 | [litewebchat-theme=dark] .lite-chatbox .cleft .content { 486 | color: #d4d4d4; 487 | } 488 | .lite-chatbox .cleft .content::after { 489 | left: -12px; 490 | top: 8px; 491 | } 492 | .lite-chatbox img.headIcon { 493 | width: 34px; 494 | height: 34px; 495 | top: 9px; 496 | position: absolute; 497 | } 498 | .lite-chatbox img.radius { 499 | border-radius: 50%; 500 | } 501 | .lite-chatbox .name { 502 | color: #8b8b8b; 503 | font-size: 12px; 504 | display: block; 505 | line-height: 18px; 506 | } 507 | .lite-chatbox .name > span { 508 | vertical-align: middle; 509 | } 510 | .lite-chatbox .name .htitle { 511 | display: inline-block; 512 | padding: 0 3px 0 3px; 513 | background-color: #cccccc; 514 | color: #ffffff; 515 | border-radius: 4px; 516 | margin-right: 4px; 517 | font-size: 11px; 518 | overflow: hidden; 519 | -o-text-overflow: ellipsis; 520 | text-overflow: ellipsis; 521 | white-space: nowrap; 522 | vertical-align: middle; 523 | max-width: 50px; 524 | } 525 | [litewebchat-theme=dark] .lite-chatbox .name .htitle { 526 | background-color: rgb(76, 80, 82); 527 | } 528 | .lite-chatbox .name .htitle.admin { 529 | background-color: #72D6A0; 530 | } 531 | [litewebchat-theme=dark] .lite-chatbox .name .htitle.admin { 532 | background-color: rgb(60, 145, 110); 533 | } 534 | .lite-chatbox .name .htitle.owner { 535 | background-color: #F2BF25; 536 | } 537 | [litewebchat-theme=dark] .lite-chatbox .name .htitle.owner { 538 | background-color: rgb(154, 124, 33); 539 | } 540 | .lite-chatbox .content { 541 | word-break: break-all; 542 | word-wrap: break-word; 543 | text-align: left; 544 | position: relative; 545 | display: inline-block; 546 | font-size: 15px; 547 | padding: 10px 15px; 548 | line-height: 20px; 549 | white-space: pre-wrap; 550 | min-width: 9px; 551 | min-height: 18px; 552 | } 553 | .lite-chatbox .content img { 554 | width: 100%; 555 | height: auto; 556 | } 557 | .lite-chatbox .content a { 558 | color: #0072C1; 559 | margin: 0 5px; 560 | cursor: hand; 561 | } 562 | [litewebchat-theme=dark] .lite-chatbox .content a { 563 | color: #00c3ff; 564 | } 565 | /*# sourceMappingURL=map/litewebchat.css.map */ 566 | -------------------------------------------------------------------------------- /dist/css/litewebchat.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | *//*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}*{scrollbar-color:#5c6163 rgba(56,59,60,.031372549)}::-webkit-scrollbar{width:7px;height:1px}::-webkit-scrollbar-thumb{border-radius:10px;background-color:rgba(144,147,153,.5);border:0}[litewebchat-theme=dark] ::-webkit-scrollbar-thumb{background-color:rgba(84,91,95,.5)}::-webkit-scrollbar-track{background:#fff;min-height:50%;min-height:20px}[litewebchat-theme=dark] ::-webkit-scrollbar-track{background:#181a1b}::-webkit-scrollbar-corner{background-color:transparent}::-moz-selection{background-color:#1963bd!important;color:#f8f6f3!important}::selection{background-color:#1963bd!important;color:#f8f6f3!important}body{font-family:Helvetica,"PingFang SC","Microsoft YaHei",sans-serif}.lite-chatbox{scroll-behavior:smooth;padding:0;width:100%;position:relative;font-size:18px;background-color:#f8f9fa;overflow-y:auto;overflow-x:hidden}.lite-chatbox .tips{margin:12px;text-align:center;font-size:12px}.lite-chatbox .tips span{display:inline-block;padding:4px;background-color:#ccc;color:#fff;border-radius:6px}[litewebchat-theme=dark] .lite-chatbox .tips span{background-color:rgba(0,0,0,.3)}[litewebchat-theme=dark] .lite-chatbox .tips span{color:#bec5cc}.lite-chatbox .tips .tips-primary{background-color:#3986c8}[litewebchat-theme=dark] .lite-chatbox .tips .tips-primary{background-color:#447fb2}.lite-chatbox .tips .tips-success{background-color:#49b649}[litewebchat-theme=dark] .lite-chatbox .tips .tips-success{background-color:#66a651}.lite-chatbox .tips .tips-info{background-color:#5bb6d1}[litewebchat-theme=dark] .lite-chatbox .tips .tips-info{background-color:#3f889e}.lite-chatbox .tips .tips-warning{background-color:#eea948}[litewebchat-theme=dark] .lite-chatbox .tips .tips-warning{background-color:#af7728}.lite-chatbox .tips .tips-danger{background-color:#e24d48}[litewebchat-theme=dark] .lite-chatbox .tips .tips-danger{background-color:#ad3531}[litewebchat-theme=dark] .lite-chatbox{background-color:#131415}.lite-chatbox .cmsg{position:relative;margin:4px 7px;min-height:50px;border:0}.lite-chatbox .cright{text-align:right;margin-left:64px}.lite-chatbox .cright img.headIcon{right:0}.lite-chatbox .cright .name{margin:0 48px 2px 0}.lite-chatbox .cright .content{margin:0 48px 0 0;border-radius:20px 0 20px 20px;color:#fff;background:-o-linear-gradient(70deg,rgba(63,143,225,.8) 0,#44d7c9 100%);background:linear-gradient(20deg,rgba(63,143,225,.8) 0,#44d7c9 100%);-webkit-box-shadow:5px 5px 15px 0 rgba(102,102,102,.15);box-shadow:5px 5px 15px 0 rgba(102,102,102,.15)}[litewebchat-theme=dark] .lite-chatbox .cright .content{background:-o-linear-gradient(70deg,rgba(25,91,159,.8) 0,#219a92 100%);background:linear-gradient(20deg,rgba(25,91,159,.8) 0,#219a92 100%)}.lite-chatbox .cright .content::after{left:-12px;top:8px}.lite-chatbox .cleft{text-align:left;margin-right:64px}.lite-chatbox .cleft img.headIcon{left:0}.lite-chatbox .cleft .name{margin:0 0 2px 48px}.lite-chatbox .cleft .content{margin:0 0 0 48px;border-radius:0 20px 20px 20px;background:#fff;color:#373737;border:1px solid rgba(0,0,0,.05);-webkit-box-shadow:5px 5px 15px 0 rgba(102,102,102,.1);box-shadow:5px 5px 15px 0 rgba(102,102,102,.1)}[litewebchat-theme=dark] .lite-chatbox .cleft .content{background:#22242a}[litewebchat-theme=dark] .lite-chatbox .cleft .content{color:#d4d4d4}.lite-chatbox .cleft .content::after{left:-12px;top:8px}.lite-chatbox img.headIcon{width:34px;height:34px;top:9px;position:absolute}.lite-chatbox img.radius{border-radius:50%}.lite-chatbox .name{color:#8b8b8b;font-size:12px;display:block;line-height:18px}.lite-chatbox .name>span{vertical-align:middle}.lite-chatbox .name .htitle{display:inline-block;padding:0 3px 0 3px;background-color:#ccc;color:#fff;border-radius:4px;margin-right:4px;font-size:11px;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;max-width:50px}[litewebchat-theme=dark] .lite-chatbox .name .htitle{background-color:#4c5052}.lite-chatbox .name .htitle.admin{background-color:#72d6a0}[litewebchat-theme=dark] .lite-chatbox .name .htitle.admin{background-color:#3c916e}.lite-chatbox .name .htitle.owner{background-color:#f2bf25}[litewebchat-theme=dark] .lite-chatbox .name .htitle.owner{background-color:#9a7c21}.lite-chatbox .content{word-break:break-all;word-wrap:break-word;text-align:left;position:relative;display:inline-block;font-size:15px;padding:10px 15px;line-height:20px;white-space:pre-wrap;min-width:9px;min-height:18px}.lite-chatbox .content img{width:100%;height:auto}.lite-chatbox .content a{color:#0072c1;margin:0 5px;cursor:hand}[litewebchat-theme=dark] .lite-chatbox .content a{color:#00c3ff} 6 | /*# sourceMappingURL=map/litewebchat.min.css.map */ 7 | -------------------------------------------------------------------------------- /dist/css/litewebchat_input.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | */@charset "UTF-8"; 6 | .lite-chatbox { 7 | height: calc(100% - 150px); 8 | } 9 | .lite-chatbox > div:last-child { 10 | margin-bottom: 20px; 11 | } 12 | 13 | .lite-chatinput { 14 | width: 100%; 15 | height: 150px; 16 | position: relative; 17 | bottom: 0px; 18 | background-color: #fff; 19 | } 20 | [litewebchat-theme=dark] .lite-chatinput { 21 | background-color: #202223; 22 | } 23 | .lite-chatinput img { 24 | max-width: 150px; 25 | max-height: 150px; 26 | -o-object-fit: contain; 27 | object-fit: contain; 28 | } 29 | .lite-chatinput .boundary { 30 | cursor: s-resize; 31 | margin: 0 auto; 32 | border-width: 1px 0px 0px 0px; 33 | border-color: rgba(0, 0, 0, 0.2); 34 | height: 5px; 35 | background: #fff; 36 | } 37 | [litewebchat-theme=dark] .lite-chatinput .boundary { 38 | background: #202223; 39 | } 40 | .lite-chatinput > .chatinput { 41 | position: relative; 42 | overflow-y: scroll; 43 | /* margin: 0px 3px 0px 3px; */ 44 | width: calc(100% - 6px); 45 | margin: auto; 46 | /* width: 100%; */ 47 | height: calc(100% - 75px); 48 | /* height: 100%; */ 49 | border: none; 50 | outline: none; 51 | resize: none; 52 | font-size: 18px; 53 | color: #373737; 54 | word-break: break-all; 55 | overflow-wrap: break-word; 56 | padding: 5px; 57 | outline: none; 58 | } 59 | [litewebchat-theme=dark] .lite-chatinput > .chatinput { 60 | color: #d4d4d4; 61 | } 62 | .lite-chatinput .send { 63 | float: right; 64 | padding: 4px 20px 4px 20px; 65 | margin-right: 12px; 66 | margin-top: -2px; 67 | color: white; 68 | background: -o-linear-gradient(70deg, rgba(63, 143, 225, 0.8) 0%, #44d7c9 100%); 69 | background: linear-gradient(20deg, rgba(63, 143, 225, 0.8) 0%, #44d7c9 100%); 70 | -webkit-box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1); 71 | box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1); 72 | border: none; 73 | border-radius: 4px; 74 | -webkit-transition: all 0.2s; 75 | -o-transition: all 0.2s; 76 | transition: all 0.2s; 77 | } 78 | [litewebchat-theme=dark] .lite-chatinput .send { 79 | background: -o-linear-gradient(70deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%); 80 | background: linear-gradient(20deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%); 81 | } 82 | .lite-chatinput .send:hover { 83 | -webkit-transform: scale(1.1); 84 | -ms-transform: scale(1.1); 85 | transform: scale(1.1); 86 | opacity: 0.7; 87 | } 88 | .lite-chatinput .send:active { 89 | -webkit-transform: scale(0.9); 90 | -ms-transform: scale(0.9); 91 | transform: scale(0.9); 92 | opacity: 1; 93 | } 94 | .lite-chatinput .tool-button { 95 | padding: 0px 3px 0px 3px; 96 | background: none; 97 | border: none; 98 | margin: 5px; 99 | margin-bottom: 0px; 100 | -webkit-transition: all 0.2s; 101 | -o-transition: all 0.2s; 102 | transition: all 0.2s; 103 | } 104 | .lite-chatinput .tool-button:hover { 105 | -webkit-transform: scale(1.1); 106 | -ms-transform: scale(1.1); 107 | transform: scale(1.1); 108 | opacity: 0.7; 109 | } 110 | .lite-chatinput .tool-button:active { 111 | -webkit-transform: scale(0.9); 112 | -ms-transform: scale(0.9); 113 | transform: scale(0.9); 114 | opacity: 1; 115 | } 116 | .lite-chatinput .tool-button path { 117 | fill: rgb(139, 135, 153); 118 | } 119 | .lite-chatinput .tool-button svg { 120 | width: 18px; 121 | } 122 | 123 | /* 由功能按钮唤起的功能页面 */ 124 | .lite-chatbox-tool { 125 | /* border: 5px solid red; */ 126 | position: absolute; 127 | /* bottom: 20px; */ 128 | margin-left: 3px; 129 | z-index: 3; 130 | } 131 | 132 | /* 部分功能页面需要用到的遮罩 */ 133 | #toolMusk { 134 | /* border: 3px solid red; */ 135 | position: absolute; 136 | width: 100vw; 137 | height: 100vh; 138 | top: 0; 139 | left: 0; 140 | z-index: 2; 141 | } 142 | 143 | .float-left { 144 | float: left; 145 | } 146 | 147 | .float-right { 148 | float: right; 149 | } 150 | /*# sourceMappingURL=map/litewebchat_input.css.map */ 151 | -------------------------------------------------------------------------------- /dist/css/litewebchat_input.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | */.lite-chatbox{height:calc(100% - 150px)}.lite-chatbox>div:last-child{margin-bottom:20px}.lite-chatinput{width:100%;height:150px;position:relative;bottom:0;background-color:#fff}[litewebchat-theme=dark] .lite-chatinput{background-color:#202223}.lite-chatinput img{max-width:150px;max-height:150px;-o-object-fit:contain;object-fit:contain}.lite-chatinput .boundary{cursor:s-resize;margin:0 auto;border-width:1px 0 0 0;border-color:rgba(0,0,0,.2);height:5px;background:#fff}[litewebchat-theme=dark] .lite-chatinput .boundary{background:#202223}.lite-chatinput>.chatinput{position:relative;overflow-y:scroll;width:calc(100% - 6px);margin:auto;height:calc(100% - 75px);border:none;outline:0;resize:none;font-size:18px;color:#373737;word-break:break-all;overflow-wrap:break-word;padding:5px;outline:0}[litewebchat-theme=dark] .lite-chatinput>.chatinput{color:#d4d4d4}.lite-chatinput .send{float:right;padding:4px 20px 4px 20px;margin-right:12px;margin-top:-2px;color:#fff;background:-o-linear-gradient(70deg,rgba(63,143,225,.8) 0,#44d7c9 100%);background:linear-gradient(20deg,rgba(63,143,225,.8) 0,#44d7c9 100%);-webkit-box-shadow:5px 5px 15px 0 rgba(102,102,102,.1);box-shadow:5px 5px 15px 0 rgba(102,102,102,.1);border:none;border-radius:4px;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s}[litewebchat-theme=dark] .lite-chatinput .send{background:-o-linear-gradient(70deg,rgba(25,91,159,.8) 0,#219a92 100%);background:linear-gradient(20deg,rgba(25,91,159,.8) 0,#219a92 100%)}.lite-chatinput .send:hover{-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1);opacity:.7}.lite-chatinput .send:active{-webkit-transform:scale(.9);-ms-transform:scale(.9);transform:scale(.9);opacity:1}.lite-chatinput .tool-button{padding:0 3px 0 3px;background:0 0;border:none;margin:5px;margin-bottom:0;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s}.lite-chatinput .tool-button:hover{-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1);opacity:.7}.lite-chatinput .tool-button:active{-webkit-transform:scale(.9);-ms-transform:scale(.9);transform:scale(.9);opacity:1}.lite-chatinput .tool-button path{fill:#8b8799}.lite-chatinput .tool-button svg{width:18px}.lite-chatbox-tool{position:absolute;margin-left:3px;z-index:3}#toolMusk{position:absolute;width:100vw;height:100vh;top:0;left:0;z-index:2}.float-left{float:left}.float-right{float:right} 6 | /*# sourceMappingURL=map/litewebchat_input.min.css.map */ 7 | -------------------------------------------------------------------------------- /dist/css/map/litewebchat_input.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["chatinput.css","chatinput.scss","mixin/_theme.scss","mixin/_helper.scss"],"names":[],"mappings":"AAAA;;;;EAIE,CAAC,gBAAgB;ACEnB;EACE,0BAAA;ADAF;ACGE;EACE,mBAAA;ADDJ;;ACMA;EACE,WAAA;EACA,aAAA;EACA,kBAAA;EACA,WAAA;ECZI,sBAAA;AFUN;AEJM;EACE,yBAAA;AFMR;ACGE;EACE,gBAAA;EACA,iBAAA;EACA,sBAAA;KAAA,mBAAA;ADDJ;ACKE;EACE,gBAAA;EACA,cAAA;EACA,6BAAA;EACA,gCAAA;EACA,WAAA;EC5BE,gBAAA;AF0BN;AEpBM;EACE,mBAAA;AFsBR;ACIE;EACE,kBAAA;EACA,kBAAA;EACA,6BAAA;EACA,uBAAA;EACA,YAAA;EACA,iBAAA;EACA,yBAAA;EACA,kBAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EC7CE,cAAA;ED+CF,qBAAA;EACA,yBAAA;EACA,YAAA;EACA,aAAA;ADFJ;AE1CM;EACE,cAAA;AF4CR;ACGE;EACE,YAAA;EACA,0BAAA;EAGE,kBAAA;EACA,gBAAA;EAGF,YAAA;EC/DE,+EAAA;EAAA,4EAAA;EDiEF,2DAAA;UAAA,mDAAA;EACA,YAAA;EACA,kBAAA;EElEF,4BAAA;EAAA,uBAAA;EAAA,oBAAA;AH8DF;AEzDM;EACE,yFAAA;EAAA,sFAAA;AF2DR;AG/DE;EACE,6BAAA;MAAA,yBAAA;UAAA,qBAAA;EACA,YAAA;AHiEJ;AG9DE;EACE,6BAAA;MAAA,yBAAA;UAAA,qBAAA;EACA,UAAA;AHgEJ;ACFE;EACE,wBAAA;EACA,gBAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EE5EF,4BAAA;EAAA,uBAAA;EAAA,oBAAA;AHiFF;AG/EE;EACE,6BAAA;MAAA,yBAAA;UAAA,qBAAA;EACA,YAAA;AHiFJ;AG9EE;EACE,6BAAA;MAAA,yBAAA;UAAA,qBAAA;EACA,UAAA;AHgFJ;ACVI;EACE,wBAAA;ADYN;ACTI;EACE,WAAA;ADWN;;ACJA,iBAAA;AACA;EACE,2BAAA;EACA,kBAAA;EACA,kBAAA;EACA,gBAAA;EACA,UAAA;ADOF;;ACJA,kBAAA;AACA;EACE,2BAAA;EACA,kBAAA;EACA,YAAA;EACA,aAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;ADOF;;ACJA;EACE,WAAA;ADOF;;ACJA;EACE,YAAA;ADOF","file":"../litewebchat_input.css","sourcesContent":["/*!\n * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame)\n * MorFans Lab(c) 2017-2023\n * Licensed under LGPL\n */@charset \"UTF-8\";\n.lite-chatbox {\n height: calc(100% - 150px);\n}\n.lite-chatbox > div:last-child {\n margin-bottom: 20px;\n}\n\n.lite-chatinput {\n width: 100%;\n height: 150px;\n position: relative;\n bottom: 0px;\n background-color: #fff;\n}\n[litewebchat-theme=dark] .lite-chatinput {\n background-color: #202223;\n}\n.lite-chatinput img {\n max-width: 150px;\n max-height: 150px;\n object-fit: contain;\n}\n.lite-chatinput .boundary {\n cursor: s-resize;\n margin: 0 auto;\n border-width: 1px 0px 0px 0px;\n border-color: rgba(0, 0, 0, 0.2);\n height: 5px;\n background: #fff;\n}\n[litewebchat-theme=dark] .lite-chatinput .boundary {\n background: #202223;\n}\n.lite-chatinput > .chatinput {\n position: relative;\n overflow-y: scroll;\n /* margin: 0px 3px 0px 3px; */\n width: calc(100% - 6px);\n margin: auto;\n /* width: 100%; */\n height: calc(100% - 75px);\n /* height: 100%; */\n border: none;\n outline: none;\n resize: none;\n font-size: 18px;\n color: #373737;\n word-break: break-all;\n overflow-wrap: break-word;\n padding: 5px;\n outline: none;\n}\n[litewebchat-theme=dark] .lite-chatinput > .chatinput {\n color: #d4d4d4;\n}\n.lite-chatinput .send {\n float: right;\n padding: 4px 20px 4px 20px;\n margin-right: 12px;\n margin-top: -2px;\n color: white;\n background: linear-gradient(20deg, rgba(63, 143, 225, 0.8) 0%, #44d7c9 100%);\n box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1);\n border: none;\n border-radius: 4px;\n transition: all 0.2s;\n}\n[litewebchat-theme=dark] .lite-chatinput .send {\n background: linear-gradient(20deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%);\n}\n.lite-chatinput .send:hover {\n transform: scale(1.1);\n opacity: 0.7;\n}\n.lite-chatinput .send:active {\n transform: scale(0.9);\n opacity: 1;\n}\n.lite-chatinput .tool-button {\n padding: 0px 3px 0px 3px;\n background: none;\n border: none;\n margin: 5px;\n margin-bottom: 0px;\n transition: all 0.2s;\n}\n.lite-chatinput .tool-button:hover {\n transform: scale(1.1);\n opacity: 0.7;\n}\n.lite-chatinput .tool-button:active {\n transform: scale(0.9);\n opacity: 1;\n}\n.lite-chatinput .tool-button path {\n fill: rgb(139, 135, 153);\n}\n.lite-chatinput .tool-button svg {\n width: 18px;\n}\n\n/* 由功能按钮唤起的功能页面 */\n.lite-chatbox-tool {\n /* border: 5px solid red; */\n position: absolute;\n /* bottom: 20px; */\n margin-left: 3px;\n z-index: 3;\n}\n\n/* 部分功能页面需要用到的遮罩 */\n#toolMusk {\n /* border: 3px solid red; */\n position: absolute;\n width: 100vw;\n height: 100vh;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.float-left {\n float: left;\n}\n\n.float-right {\n float: right;\n}","@import './mixin/theme';\n@import './mixin/helper';\n\n@import './variable';\n\n// 聊天区域\n.lite-chatbox {\n height: calc(100% - 150px);\n\n //.lite-chatbox内的最后一条消息的margin-bottom设置为20px,离下面远一点\n >div:last-child {\n margin-bottom: 20px;\n }\n}\n\n// 输入框\n.lite-chatinput {\n width: 100%;\n height: 150px;\n position: relative;\n bottom: 0px;\n @include theme('background-color', $chat-bg-color-input);\n\n // 缩小输入框内的图片,方便编辑\n img {\n max-width: 150px;\n max-height: 150px;\n object-fit: contain;\n }\n\n // 聊天区域和输入框的分界线\n .boundary {\n cursor: s-resize;\n margin: 0 auto;\n border-width: 1px 0px 0px 0px;\n border-color: rgba(0, 0, 0, 0.2);\n height: 5px;\n @include theme('background', $chat-bg-color-input);\n }\n\n // 输入框\n >.chatinput {\n position: relative;\n overflow-y: scroll;\n /* margin: 0px 3px 0px 3px; */\n width: calc(100% - 6px);\n margin: auto;\n /* width: 100%; */\n height: calc(100% - 75px);\n /* height: 100%; */\n border: none;\n outline: none;\n resize: none;\n font-size: 18px;\n @include theme('color', $chat-color-input);\n word-break: break-all;\n overflow-wrap: break-word;\n padding: 5px;\n outline: none;\n }\n\n // 发送按钮\n .send {\n float: right;\n padding: 4px 20px 4px 20px;\n\n margin: {\n right: 12px;\n top: -2px;\n }\n\n color: white;\n @include theme('background', $chat-message-bg-color-me);\n box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1);\n border: none;\n border-radius: 4px;\n @include push-animate;\n }\n\n // 输入框上方的输入表情等功能按钮\n .tool-button {\n padding: 0px 3px 0px 3px;\n background: none;\n border: none;\n margin: 5px;\n margin-bottom: 0px;\n @include push-animate;\n\n path {\n fill: rgb(139, 135, 153);\n }\n\n svg {\n width: 18px;\n }\n }\n\n // end of.tool-button\n}\n\n/* 由功能按钮唤起的功能页面 */\n.lite-chatbox-tool {\n /* border: 5px solid red; */\n position: absolute;\n /* bottom: 20px; */\n margin-left: 3px;\n z-index: 3;\n}\n\n/* 部分功能页面需要用到的遮罩 */\n#toolMusk {\n /* border: 3px solid red; */\n position: absolute;\n width: 100vw;\n height: 100vh;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.float-left {\n float: left;\n}\n\n.float-right {\n float: right;\n}\n","@mixin theme($key, $map_key) {\n $theme_colors: light,\n dark;\n\n @each $theme in $theme_colors {\n\n @if $theme ==light {\n // default light\n #{$key}: map-get($map: $map_key, $key: $theme);\n }\n\n @else {\n\n // 生成其他\n [litewebchat-theme=#{$theme}] & {\n #{$key}: map-get($map: $map_key, $key: $theme);\n }\n }\n }\n}\n","@use \"sass:selector\";\n\n@mixin unify-parent($child) {\n @at-root #{selector.unify(&, $child)} {\n @content;\n }\n}\n\n@mixin push-animate($time: .2, $scaleHover: 1.1, $scalePush: 0.9) {\n transition: all #{$time}s; // 让按下有呼吸感\n\n &:hover {\n transform: scale($scaleHover);\n opacity: .7;\n }\n\n &:active {\n transform: scale($scalePush);\n opacity: 1;\n }\n}\n"]} -------------------------------------------------------------------------------- /dist/css/map/litewebchat_input.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["chatinput.css","chatinput.scss","mixin/_theme.scss","mixin/_helper.scss"],"names":[],"mappings":"iBAAA;;;;ACMA,cACE,OAAA,mBAGA,6BACE,cAAA,KAKJ,gBACE,MAAA,KACA,OAAA,MACA,SAAA,SACA,OAAA,ECZI,iBAAA,KAMA,yCACE,iBAAA,QDSN,oBACE,UAAA,MACA,WAAA,MACA,cAAA,QAAA,WAAA,QAIF,0BACE,OAAA,SACA,OAAA,EAAA,KACA,aAAA,IAAA,EAAA,EAAA,EACA,aAAA,eACA,OAAA,IC5BE,WAAA,KAMA,mDACE,WAAA,QD0BN,2BACE,SAAA,SACA,WAAA,OAEA,MAAA,iBACA,OAAA,KAEA,OAAA,kBAEA,OAAA,KACA,QAAA,EACA,OAAA,KACA,UAAA,KC7CE,MAAA,QD+CF,WAAA,UACA,cAAA,WACA,QAAA,IACA,QAAA,EC5CE,oDACE,MAAA,QD+CN,sBACE,MAAA,MACA,QAAA,IAAA,KAAA,IAAA,KAGE,aAAA,KACA,WAAA,KAGF,MAAA,KC/DE,WAAA,6DAAA,WAAA,0DDiEF,mBAAA,IAAA,IAAA,KAAA,EAAA,qBAAA,WAAA,IAAA,IAAA,KAAA,EAAA,qBACA,OAAA,KACA,cAAA,IElEF,mBAAA,IAAA,IAAA,cAAA,IAAA,IAAA,WAAA,IAAA,IDKI,+CACE,WAAA,4DAAA,WAAA,yDCJN,4BACE,kBAAA,WAAA,cAAA,WAAA,UAAA,WACA,QAAA,GAGF,6BACE,kBAAA,UAAA,cAAA,UAAA,UAAA,UACA,QAAA,EF8DF,6BACE,QAAA,EAAA,IAAA,EAAA,IACA,WAAA,IACA,OAAA,KACA,OAAA,IACA,cAAA,EE5EF,mBAAA,IAAA,IAAA,cAAA,IAAA,IAAA,WAAA,IAAA,IAEA,mCACE,kBAAA,WAAA,cAAA,WAAA,UAAA,WACA,QAAA,GAGF,oCACE,kBAAA,UAAA,cAAA,UAAA,UAAA,UACA,QAAA,EFsEA,kCACE,KAAA,QAGF,iCACE,MAAA,KAQN,mBAEE,SAAA,SAEA,YAAA,IACA,QAAA,EAIF,UAEE,SAAA,SACA,MAAA,MACA,OAAA,MACA,IAAA,EACA,KAAA,EACA,QAAA,EAGF,YACE,MAAA,KAGF,aACE,MAAA","file":"../litewebchat_input.min.css","sourcesContent":["/*!\n * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame)\n * MorFans Lab(c) 2017-2023\n * Licensed under LGPL\n */@charset \"UTF-8\";\n.lite-chatbox {\n height: calc(100% - 150px);\n}\n.lite-chatbox > div:last-child {\n margin-bottom: 20px;\n}\n\n.lite-chatinput {\n width: 100%;\n height: 150px;\n position: relative;\n bottom: 0px;\n background-color: #fff;\n}\n[litewebchat-theme=dark] .lite-chatinput {\n background-color: #202223;\n}\n.lite-chatinput img {\n max-width: 150px;\n max-height: 150px;\n object-fit: contain;\n}\n.lite-chatinput .boundary {\n cursor: s-resize;\n margin: 0 auto;\n border-width: 1px 0px 0px 0px;\n border-color: rgba(0, 0, 0, 0.2);\n height: 5px;\n background: #fff;\n}\n[litewebchat-theme=dark] .lite-chatinput .boundary {\n background: #202223;\n}\n.lite-chatinput > .chatinput {\n position: relative;\n overflow-y: scroll;\n /* margin: 0px 3px 0px 3px; */\n width: calc(100% - 6px);\n margin: auto;\n /* width: 100%; */\n height: calc(100% - 75px);\n /* height: 100%; */\n border: none;\n outline: none;\n resize: none;\n font-size: 18px;\n color: #373737;\n word-break: break-all;\n overflow-wrap: break-word;\n padding: 5px;\n outline: none;\n}\n[litewebchat-theme=dark] .lite-chatinput > .chatinput {\n color: #d4d4d4;\n}\n.lite-chatinput .send {\n float: right;\n padding: 4px 20px 4px 20px;\n margin-right: 12px;\n margin-top: -2px;\n color: white;\n background: linear-gradient(20deg, rgba(63, 143, 225, 0.8) 0%, #44d7c9 100%);\n box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1);\n border: none;\n border-radius: 4px;\n transition: all 0.2s;\n}\n[litewebchat-theme=dark] .lite-chatinput .send {\n background: linear-gradient(20deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%);\n}\n.lite-chatinput .send:hover {\n transform: scale(1.1);\n opacity: 0.7;\n}\n.lite-chatinput .send:active {\n transform: scale(0.9);\n opacity: 1;\n}\n.lite-chatinput .tool-button {\n padding: 0px 3px 0px 3px;\n background: none;\n border: none;\n margin: 5px;\n margin-bottom: 0px;\n transition: all 0.2s;\n}\n.lite-chatinput .tool-button:hover {\n transform: scale(1.1);\n opacity: 0.7;\n}\n.lite-chatinput .tool-button:active {\n transform: scale(0.9);\n opacity: 1;\n}\n.lite-chatinput .tool-button path {\n fill: rgb(139, 135, 153);\n}\n.lite-chatinput .tool-button svg {\n width: 18px;\n}\n\n/* 由功能按钮唤起的功能页面 */\n.lite-chatbox-tool {\n /* border: 5px solid red; */\n position: absolute;\n /* bottom: 20px; */\n margin-left: 3px;\n z-index: 3;\n}\n\n/* 部分功能页面需要用到的遮罩 */\n#toolMusk {\n /* border: 3px solid red; */\n position: absolute;\n width: 100vw;\n height: 100vh;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.float-left {\n float: left;\n}\n\n.float-right {\n float: right;\n}","@import './mixin/theme';\n@import './mixin/helper';\n\n@import './variable';\n\n// 聊天区域\n.lite-chatbox {\n height: calc(100% - 150px);\n\n //.lite-chatbox内的最后一条消息的margin-bottom设置为20px,离下面远一点\n >div:last-child {\n margin-bottom: 20px;\n }\n}\n\n// 输入框\n.lite-chatinput {\n width: 100%;\n height: 150px;\n position: relative;\n bottom: 0px;\n @include theme('background-color', $chat-bg-color-input);\n\n // 缩小输入框内的图片,方便编辑\n img {\n max-width: 150px;\n max-height: 150px;\n object-fit: contain;\n }\n\n // 聊天区域和输入框的分界线\n .boundary {\n cursor: s-resize;\n margin: 0 auto;\n border-width: 1px 0px 0px 0px;\n border-color: rgba(0, 0, 0, 0.2);\n height: 5px;\n @include theme('background', $chat-bg-color-input);\n }\n\n // 输入框\n >.chatinput {\n position: relative;\n overflow-y: scroll;\n /* margin: 0px 3px 0px 3px; */\n width: calc(100% - 6px);\n margin: auto;\n /* width: 100%; */\n height: calc(100% - 75px);\n /* height: 100%; */\n border: none;\n outline: none;\n resize: none;\n font-size: 18px;\n @include theme('color', $chat-color-input);\n word-break: break-all;\n overflow-wrap: break-word;\n padding: 5px;\n outline: none;\n }\n\n // 发送按钮\n .send {\n float: right;\n padding: 4px 20px 4px 20px;\n\n margin: {\n right: 12px;\n top: -2px;\n }\n\n color: white;\n @include theme('background', $chat-message-bg-color-me);\n box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1);\n border: none;\n border-radius: 4px;\n @include push-animate;\n }\n\n // 输入框上方的输入表情等功能按钮\n .tool-button {\n padding: 0px 3px 0px 3px;\n background: none;\n border: none;\n margin: 5px;\n margin-bottom: 0px;\n @include push-animate;\n\n path {\n fill: rgb(139, 135, 153);\n }\n\n svg {\n width: 18px;\n }\n }\n\n // end of.tool-button\n}\n\n/* 由功能按钮唤起的功能页面 */\n.lite-chatbox-tool {\n /* border: 5px solid red; */\n position: absolute;\n /* bottom: 20px; */\n margin-left: 3px;\n z-index: 3;\n}\n\n/* 部分功能页面需要用到的遮罩 */\n#toolMusk {\n /* border: 3px solid red; */\n position: absolute;\n width: 100vw;\n height: 100vh;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.float-left {\n float: left;\n}\n\n.float-right {\n float: right;\n}\n","@mixin theme($key, $map_key) {\n $theme_colors: light,\n dark;\n\n @each $theme in $theme_colors {\n\n @if $theme ==light {\n // default light\n #{$key}: map-get($map: $map_key, $key: $theme);\n }\n\n @else {\n\n // 生成其他\n [litewebchat-theme=#{$theme}] & {\n #{$key}: map-get($map: $map_key, $key: $theme);\n }\n }\n }\n}\n","@use \"sass:selector\";\n\n@mixin unify-parent($child) {\n @at-root #{selector.unify(&, $child)} {\n @content;\n }\n}\n\n@mixin push-animate($time: .2, $scaleHover: 1.1, $scalePush: 0.9) {\n transition: all #{$time}s; // 让按下有呼吸感\n\n &:hover {\n transform: scale($scaleHover);\n opacity: .7;\n }\n\n &:active {\n transform: scale($scalePush);\n opacity: 1;\n }\n}\n"]} -------------------------------------------------------------------------------- /dist/html/chat_example.html: -------------------------------------------------------------------------------- 1 | LiteChat_Frame(轻聊天气泡框架)
chenjunyu19这是什么什么鬼?
SuperPaxxsLiteChat_Frame(轻聊天气泡框架),一个贼简洁 (简单)、美观、易用的 HTML 聊天界面框架
SuperPaxxs 它简洁而不简单,能使你开发聊天界面更快速
NEWSuperPaxxsLiteChat_Frame 拥有暗色模式, 快来试试吧:

chenjunyu19 直接说,气泡是谁的?
SuperPaxxs 好吧,气泡 css 来自 Haswikr 的 Blog 的机器人气泡 😝
adminHaswikr当初调色煞费苦心
ownerSonui 这设计真棒
menber123456789789chenjunyu19 那咋用啊?
SuperPaxxs诶哟少年你找对人了

如果只是使用,那非常简单。

使用指北


1. 引用 css: litechat.css

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.css" rel="stylesheet" />

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.min.css" rel="stylesheet" />

2. 创建一个 DIV ,用来容纳聊天对话,目的是不让 css 干扰页面其他内容:

<div class="lite-chatbox">
...
</div>

话说你就不会看下源码吗...楼下是特性演示
Chenjunyu19 退出了聊天室并撩了你一把
空消息测试 1
空消息测试 2 
chenjunyu19注意,上面两条空消息的消息内容代码不一样
SuperPaxxs 头像换成方形请去掉 radius
chenjunyu19我是左边的方形头像
图片消息
图片消息 2
图片带文字是可以的 (废话)
右边长消息 我的消息真的超级长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长欸
左边长消息 这么巧鸭,我的也超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超级长的欸
系统消息:左 / 右边长消息被管理员批判一番……
系统消息:normal
系统消息:primary
系统消息:success
系统消息:info
系统消息:warning
系统消息:danger
带有超链接的消息测试 当然是可以有超链接的。例子在这里:
你敢点我吗 ← 戳这里
全符号测试 。,;?:!‘’“”@ˆ.,;?:!'"〝〞﹫ˇ
全 emoji 测试 😀😝🐂🍺
  当无昵时候需要 &nbsp; 填充
SuperPaxxs 换行用 <br>,HTML 你懂的..
chenjunyu19以上就是全部的特性,以后有空再更
-------------------------------------------------------------------------------- /dist/html/chat_with_inputarea_example.html: -------------------------------------------------------------------------------- 1 | LiteChat_Frame(轻聊天气泡框架)
chenjunyu19这是什么什么鬼?
SuperPaxxsLiteChat_Frame(轻聊天气泡框架),一个贼简洁 (简单)、美观、易用的 HTML 聊天界面框架
SuperPaxxs 它简洁而不简单,能使你开发聊天界面更快速
NEWSuperPaxxsLiteChat_Frame 拥有暗色模式, 快来试试吧:

chenjunyu19 直接说,气泡是谁的?
SuperPaxxs 好吧,气泡 css 来自 Haswikr 的 Blog 的机器人气泡 😝
adminHaswikr当初调色煞费苦心
ownerSonui 这设计真棒
menber123456789789chenjunyu19 那咋用啊?
SuperPaxxs诶哟少年你找对人了

如果只是使用,那非常简单。

使用指北


1. 引用 css: litechat.css

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.css" rel="stylesheet" />

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.min.css" rel="stylesheet" />

2. 创建一个 DIV ,用来容纳聊天对话,目的是不让 css 干扰页面其他内容:

<div class="lite-chatbox">
...
</div>

话说你就不会看下源码吗...楼下是特性演示
Chenjunyu19 退出了聊天室并撩了你一把
空消息测试 1
空消息测试 2 
chenjunyu19注意,上面两条空消息的消息内容代码不一样
SuperPaxxs 头像换成方形请去掉 radius
chenjunyu19我是左边的方形头像
图片消息
图片消息 2
图片带文字是可以的 (废话)
右边长消息 我的消息真的超级长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长欸
左边长消息 这么巧鸭,我的也超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超级长的欸
系统消息:左 / 右边长消息被管理员批判一番……
系统消息:normal
系统消息:primary
系统消息:success
系统消息:info
系统消息:warning
系统消息:danger
带有超链接的消息测试 当然是可以有超链接的。例子在这里:
你敢点我吗 ← 戳这里
全符号测试 。,;?:!‘’“”@ˆ.,;?:!'"〝〞﹫ˇ
全 emoji 测试 😀😝🐂🍺
  当无昵时候需要 &nbsp; 填充
SuperPaxxs 换行用 <br>,HTML 你懂的..
chenjunyu19以上就是全部的特性,以后有空再更

-------------------------------------------------------------------------------- /dist/html/chat_with_inputarea_module_example.html: -------------------------------------------------------------------------------- 1 | LiteChat_Frame(轻聊天气泡框架)

-------------------------------------------------------------------------------- /dist/images/A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/dist/images/A.jpg -------------------------------------------------------------------------------- /dist/images/B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/dist/images/B.jpg -------------------------------------------------------------------------------- /dist/images/H.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/dist/images/H.jpg -------------------------------------------------------------------------------- /dist/images/O.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/dist/images/O.jpg -------------------------------------------------------------------------------- /dist/images/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/dist/images/img.png -------------------------------------------------------------------------------- /dist/images/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/dist/images/img2.png -------------------------------------------------------------------------------- /dist/js/litewebchat_input.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | */"use strict"; 6 | 7 | // !参考资料来源: 8 | // !https://blog.csdn.net/weixin_40629244/article/details/104642683 9 | // !https://github.com/jrainlau/chat-input-box 10 | // !https://www.zhihu.com/question/20893119/answer/19452676 11 | // !致谢:感谢@jrainlau提供的思路和代码,我在他的富文本编辑器基础上进行了修改,使其能够在聊天输入框中使用 12 | // ————YubaC 2023.1.23 13 | 14 | // -------------------------------- 15 | // 上半部分的聊天区域 16 | var upperChild = document.querySelector('.lite-chatbox'); 17 | // 分界线 18 | var oLine = document.querySelector('.lite-chatinput hr'); 19 | // 下半部分的输入框区域 20 | var downChild = document.querySelector('.lite-chatinput'); 21 | var downHeight = downChild.clientHeight; 22 | var upperHeight = upperChild.clientHeight; 23 | 24 | // 以下为输入框区域的按钮 25 | var emojiBtn = document.getElementById("emojiBtn"); // 表情按钮 26 | var imageBtn = document.getElementById("imageBtn"); // 图片按钮 27 | var fileBtn = document.getElementById("fileBtn"); // 文件按钮 28 | var editFullScreen = document.getElementById("editFullScreen"); // 全屏按钮 29 | var exitFullScreen = document.getElementById("exitFullScreen"); // 退出全屏按钮 30 | var emojiMart = document.getElementById("emojiMart"); // 表情面板 31 | var toolMusk = document.getElementById("toolMusk"); // 表情面板遮罩 32 | var sendBtn = document.getElementById("sendBtn"); // 发送按钮 33 | var chatInput = document.querySelector('.lite-chatinput>.chatinput'); // 输入框 34 | // -------------------------------- 35 | 36 | // Emoji Mart(表情面板)设置及唤起 37 | var pickerOptions = { 38 | "locale": "zh", 39 | onEmojiSelect: function onEmojiSelect(e) { 40 | // console.log(e.native); 41 | emojiMart.style.display = "none"; 42 | toolMusk.style.display = "none"; 43 | insertAtCursor(chatInput, e.native); 44 | // insertEmoji(e.native); 45 | } 46 | }; 47 | 48 | var picker = new EmojiMart.Picker(pickerOptions); 49 | emojiMart.appendChild(picker); 50 | 51 | // 负责在光标处插入文字的函数 52 | function insertAtCursor(myField, myValue) { 53 | var editor = myField; 54 | var html = myValue; 55 | editor.focus(); 56 | if (window.getSelection) { 57 | var selection = window.getSelection(); 58 | if (selection.getRangeAt && selection.rangeCount) { 59 | var range = selection.getRangeAt(0); 60 | range.deleteContents(); 61 | var element = document.createElement('div'); 62 | element.innerHTML = html; 63 | var node; 64 | var lastNode; 65 | var fragment = document.createDocumentFragment(); 66 | while (node = element.firstChild) { 67 | lastNode = fragment.appendChild(node); 68 | } 69 | ; 70 | range.insertNode(fragment); 71 | if (lastNode) { 72 | range = range.cloneRange(); 73 | range.setStartAfter(lastNode); 74 | range.collapse(true); 75 | selection.removeAllRanges(); 76 | selection.addRange(range); 77 | } 78 | ; 79 | } 80 | } else if (document.selection && document.selection.type != 'Control') { 81 | editor.focus(); 82 | var range = document.selection.createRange(); 83 | range.pasteHTML(html); 84 | editor.focus(); 85 | } 86 | } 87 | 88 | // 调整聊天区域和输入框区域比例的函数 89 | oLine.onmousedown = function (ev) { 90 | // 更改oLine颜色为蓝色,方便查看分界线 91 | var olineOriBgColor = oLine.style.backgroundColor; 92 | oLine.style.backgroundColor = "#1E90FF"; 93 | var iEvent = ev || event; 94 | var dy = iEvent.clientY; //当你第一次单击的时候,存储y轴的坐标。//相对于浏览器窗口 95 | upperHeight = upperChild.offsetHeight; 96 | downHeight = downChild.offsetHeight; 97 | document.onmousemove = function (ev) { 98 | var iEvent = ev || event; 99 | var diff = iEvent.clientY - dy; //移动的距离(向上滑时为负数,下滑时为正数) 100 | if (100 < upperHeight + diff && 100 < downHeight - diff) { 101 | //两个div的最小高度均为100px 102 | upperChild.style.height = "calc(100% - ".concat(downHeight - diff, "px)"); 103 | downChild.style.height = downHeight - diff + 'px'; 104 | } 105 | }; 106 | document.onmouseup = function () { 107 | // 更改oLine颜色为原色 108 | oLine.style.backgroundColor = olineOriBgColor; 109 | document.onmousedown = null; 110 | document.onmousemove = null; 111 | }; 112 | return false; 113 | }; 114 | 115 | // 显示表情输入框 116 | emojiBtn.onclick = function () { 117 | emojiMart.style.display = "block"; 118 | toolMusk.style.display = "block"; 119 | var emojiHeight = emojiMart.offsetHeight; 120 | downHeight = downChild.clientHeight; 121 | upperHeight = upperChild.clientHeight; 122 | if (emojiHeight < upperHeight) { 123 | emojiMart.style.bottom = "".concat(downHeight + 3, "px"); 124 | emojiMart.style.top = ''; 125 | } else { 126 | emojiMart.style.bottom = ''; 127 | emojiMart.style.top = '10px'; 128 | } 129 | }; 130 | 131 | // 全屏编辑文字 132 | editFullScreen.onclick = function () { 133 | downHeight = downChild.clientHeight; 134 | upperHeight = upperChild.clientHeight; 135 | downChild.style.height = "100%"; 136 | upperChild.style.height = "0px"; 137 | editFullScreen.style.display = "none"; 138 | exitFullScreen.style.display = "block"; 139 | oLine.style.display = "none"; 140 | }; 141 | 142 | // 退出全屏编辑文字 143 | exitFullScreen.onclick = function () { 144 | // 防呆不防傻,用于避免上部聊天窗口被压到没有高度后出现异常 145 | if (upperHeight != 0) { 146 | downChild.style.height = "".concat(downHeight, "px"); 147 | upperChild.style.height = "calc(100% - ".concat(downHeight, "px)"); 148 | } else { 149 | upperChild.style.height = "calc(100% - 150px)"; 150 | downChild.style.height = "150px"; 151 | } 152 | exitFullScreen.style.display = "none"; 153 | editFullScreen.style.display = "block"; 154 | oLine.style.display = "block"; 155 | }; 156 | 157 | // 隐藏musk和表情输入框 158 | toolMusk.onclick = function () { 159 | emojiMart.style.display = "none"; 160 | toolMusk.style.display = "none"; 161 | }; 162 | 163 | // 将图片插入到输入框中 164 | function addImage(file) { 165 | new Promise(function (resolve, reject) { 166 | // console.log(file); 167 | // 获取file的src 168 | var reader = new FileReader(); 169 | reader.onload = function (e) { 170 | var src = e.target.result; 171 | var img = new Image(); 172 | img.src = src; 173 | 174 | // *这里的方法已经转移到了css里,暂时弃用 175 | // // 为了防止图片在输入框内显示过大不好编辑 176 | // img.style.width = "100px"; 177 | // 将img从HEMLElement转化为字符串 178 | // 例如,转化结束后为'' 179 | var imgStr = img.outerHTML; 180 | // 将img字符串插入到输入框中 181 | insertAtCursor(chatInput, imgStr); 182 | }; 183 | reader.readAsDataURL(file); 184 | }); 185 | } 186 | 187 | // 上传图片、文件 188 | function inputFile(settings) { 189 | console.log(settings); 190 | // -----------------设置最大图片大小及数量----------------- 191 | if (settings.maxImageSize != undefined) { 192 | var maxImageSize = settings.maxImageSize; 193 | } else { 194 | var maxImageSize = -1; 195 | } 196 | if (settings.maxImageNumber != undefined) { 197 | var maxImageNumber = settings.maxImageNumber; 198 | } else { 199 | var maxImageNumber = -1; 200 | } 201 | if (settings.enable) { 202 | // -----------------上传图片的按钮----------------- 203 | imageBtn.onclick = function () { 204 | var imageInput = document.createElement('input'); 205 | imageInput.type = 'file'; 206 | imageInput.accept = 'image/*'; 207 | imageInput.multiple = true; 208 | imageInput.style.display = 'none'; 209 | imageInput.onchange = function () { 210 | // 获取输入框内图片数量 211 | // 获取文件 212 | var imgNum = chatInput.getElementsByTagName('img').length; 213 | for (var i = 0; i < this.files.length; i++) { 214 | if (maxImageNumber == -1 || imgNum < maxImageNumber) { 215 | // 如果大小超过限制,改用文件上传 216 | if (maxImageSize == -1 || this.files[i].size <= maxImageSize) { 217 | imgNum++; 218 | addImage(this.files[i]); 219 | } else { 220 | sendFile(this.files[i]); 221 | } 222 | } 223 | } 224 | }; 225 | // 触发点击事件 226 | imageInput.click(); 227 | }; 228 | // -----------------上传文件的按钮----------------- 229 | var sendFile = settings.sendFileFunc; 230 | // 上传文件按钮 231 | fileBtn.onclick = function () { 232 | // 创建一个隐藏的上传文件的input,再借助点击这个input来上传文件 233 | var fileInput = document.createElement('input'); 234 | fileInput.type = 'file'; 235 | fileInput.multiple = true; 236 | fileInput.style.display = 'none'; 237 | fileInput.onchange = function () { 238 | // 获取文件 239 | for (var i = 0; i < this.files.length; i++) { 240 | var file = this.files[i]; 241 | sendFile(file); 242 | } 243 | }; 244 | // 触发点击事件 245 | fileInput.click(); 246 | }; 247 | 248 | // -----------------拖拽上传----------------- 249 | if (settings.enableDrop) { 250 | // 当downChild有文件被拖入时,也调用上传文件的函数 251 | downChild.ondrop = function (e) { 252 | e.preventDefault(); 253 | // 阻止火狐浏览器默认打开文件的行为 254 | e.stopPropagation(); 255 | downChild.style.border = "none"; 256 | // 获取被拖拽的文件并上传 257 | var imgNum = chatInput.getElementsByTagName('img').length; 258 | for (var i = 0; i < e.dataTransfer.files.length; i++) { 259 | var file = e.dataTransfer.files[i]; 260 | // 如果是图片,直接插入到输入框中 261 | if (file.type.indexOf("image") == 0) { 262 | if (maxImageNumber == -1 || imgNum < maxImageNumber) { 263 | // 如果大小超过限制,改用文件上传 264 | if (maxImageSize == -1 || file.size <= maxImageSize) { 265 | addImage(file); 266 | imgNum++; 267 | } else { 268 | sendFile(file); 269 | } 270 | } 271 | } else { 272 | sendFile(file); 273 | } 274 | } 275 | }; 276 | 277 | // 当downChild有文件被拖入时,改变downChild的边框颜色 278 | downChild.ondragover = function (e) { 279 | e.preventDefault(); 280 | downChild.style.border = "3px solid #1E90FF"; 281 | }; 282 | 283 | // 当downChild有文件被拖入后离开时,改回downChild的边框颜色 284 | downChild.ondragleave = function (e) { 285 | e.preventDefault(); 286 | downChild.style.border = "none"; 287 | }; 288 | } 289 | } else { 290 | // 如果不允许上传,那么删除事件 291 | imageBtn.onclick = null; 292 | fileBtn.onclick = null; 293 | // 删除拖拽事件 294 | downChild.ondrop = null; 295 | downChild.ondragover = null; 296 | downChild.ondragleave = null; 297 | } 298 | } 299 | 300 | // TODO:可能富文本输入框的粘贴部分需要对Chrome浏览器做部分额外适配,以优化体验 301 | // 无格式粘贴 302 | chatInput.addEventListener('paste', function (e) { 303 | onPaste(e); 304 | }); 305 | 306 | //格式化粘贴文本方法 307 | function onPaste(event) { 308 | // 如果粘贴的是文本,就清除格式后粘贴 309 | if (event.clipboardData && event.clipboardData.getData) { 310 | var text = event.clipboardData.getData('text/plain'); 311 | if (text) { 312 | event.preventDefault(); 313 | document.execCommand('insertText', false, text); 314 | } 315 | } 316 | } 317 | window.addEventListener('DOMContentLoaded', function () { 318 | chatInput.focus(); 319 | }); 320 | //# sourceMappingURL=map/litewebchat_input.js.map 321 | -------------------------------------------------------------------------------- /dist/js/litewebchat_input.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | */"use strict";var upperChild=document.querySelector(".lite-chatbox"),oLine=document.querySelector(".lite-chatinput hr"),downChild=document.querySelector(".lite-chatinput"),downHeight=downChild.clientHeight,upperHeight=upperChild.clientHeight,emojiBtn=document.getElementById("emojiBtn"),imageBtn=document.getElementById("imageBtn"),fileBtn=document.getElementById("fileBtn"),editFullScreen=document.getElementById("editFullScreen"),exitFullScreen=document.getElementById("exitFullScreen"),emojiMart=document.getElementById("emojiMart"),toolMusk=document.getElementById("toolMusk"),sendBtn=document.getElementById("sendBtn"),chatInput=document.querySelector(".lite-chatinput>.chatinput"),pickerOptions={locale:"zh",onEmojiSelect:function(e){emojiMart.style.display="none",toolMusk.style.display="none",insertAtCursor(chatInput,e.native)}},picker=new EmojiMart.Picker(pickerOptions);function insertAtCursor(e,t){var n=e,o=t;if(n.focus(),window.getSelection){var i=window.getSelection();if(i.getRangeAt&&i.rangeCount){(r=i.getRangeAt(0)).deleteContents();var l,a,c=document.createElement("div");c.innerHTML=o;for(var d=document.createDocumentFragment();l=c.firstChild;)a=d.appendChild(l);r.insertNode(d),a&&((r=r.cloneRange()).setStartAfter(a),r.collapse(!0),i.removeAllRanges(),i.addRange(r))}}else if(document.selection&&"Control"!=document.selection.type){var r;n.focus(),(r=document.selection.createRange()).pasteHTML(o),n.focus()}}function addImage(e){new Promise((function(t,n){var o=new FileReader;o.onload=function(e){var t=e.target.result,n=new Image;n.src=t;var o=n.outerHTML;insertAtCursor(chatInput,o)},o.readAsDataURL(e)}))}function inputFile(e){if(console.log(e),null!=e.maxImageSize)var t=e.maxImageSize;else t=-1;if(null!=e.maxImageNumber)var n=e.maxImageNumber;else n=-1;if(e.enable){imageBtn.onclick=function(){var e=document.createElement("input");e.type="file",e.accept="image/*",e.multiple=!0,e.style.display="none",e.onchange=function(){for(var e=chatInput.getElementsByTagName("img").length,i=0;i chatBox.clientHeight) { 36 | chatBox.scrollTop = chatBox.scrollHeight; 37 | chatBox = ''; 38 | htmlStr = ''; 39 | } 40 | }, 300); 41 | } 42 | function renderMessageHtml(data) { 43 | return "
\n \n \n ").concat(renderTitleHtml(data.htitle, TitleType[data.htitleType] || ''), "\n ").concat(escapeHtml(data.name) || ' ', "\n \n ").concat(data.messageType === 'raw' ? data.html : escapeHtml(data.html), "\n
"); 44 | } 45 | function renderTitleHtml(content, css) { 46 | if (!content) return ''; 47 | return "").concat(content, ""); 48 | } 49 | function renderTipHtml(content, css) { 50 | if (!content) return ''; 51 | return "
").concat(escapeHtml(content), "
"); 52 | } 53 | 54 | // 转义 C0 Controls and Basic Latin 中非数字和字母,C1 Controls and Latin-1 Supplement 全部 55 | // https://www.w3schools.com/charsets/ref_html_utf8.asp 56 | function escapeHtml(unsafe) { 57 | return unsafe === null || unsafe === void 0 ? void 0 : unsafe.replace(/[\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00FF]/g, function (c) { 58 | return '&#' + ('000' + c.charCodeAt(0)).slice(-4) + ';'; 59 | }); 60 | } 61 | //# sourceMappingURL=map/litewebchat_render.js.map 62 | -------------------------------------------------------------------------------- /dist/js/litewebchat_render.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * LiteWebChat_Frame 2.2.1 (https://lab.morfans.cn/LiteWebChat_Frame) 3 | * MorFans Lab(c) 2017-2023 4 | * Licensed under LGPL 5 | */"use strict";var TipsType={tipsNormal:"tips",tipsPrimary:"tips-primary",tipsSuccess:"tips-success",tipsInfo:"tips-info",tipsWarning:"tips-warning",tipsDanger:"tips-danger"},TitleType={admin:"admin",owner:"owner"};function beforeRenderingHTML(e,n){for(var t="",s=document.querySelector(n),i=0;is.clientHeight&&(s.scrollTop=s.scrollHeight,s="",t="")}),300)}function renderMessageHtml(e){return'
\n \n \n ').concat(renderTitleHtml(e.htitle,TitleType[e.htitleType]||""),"\n ").concat(escapeHtml(e.name)||" ",'\n \n ').concat("raw"===e.messageType?e.html:escapeHtml(e.html),"\n
")}function renderTitleHtml(e,n){return e?'').concat(e,""):""}function renderTipHtml(e,n){return e?'
').concat(escapeHtml(e),"
"):""}function escapeHtml(e){return null==e?void 0:e.replace(/[\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00FF]/g,(function(e){return"&#"+("000"+e.charCodeAt(0)).slice(-4)+";"}))} 6 | //# sourceMappingURL=map/litewebchat_render.min.js.map 7 | -------------------------------------------------------------------------------- /dist/js/map/litewebchat_input.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["input.js"],"names":["upperChild","document","querySelector","oLine","downChild","downHeight","clientHeight","upperHeight","emojiBtn","getElementById","imageBtn","fileBtn","editFullScreen","exitFullScreen","emojiMart","toolMusk","sendBtn","chatInput","pickerOptions","locale","onEmojiSelect","e","style","display","insertAtCursor","native","picker","EmojiMart","Picker","myField","myValue","editor","html","focus","window","getSelection","selection","getRangeAt","rangeCount","range","deleteContents","node","lastNode","element","createElement","innerHTML","fragment","createDocumentFragment","firstChild","appendChild","insertNode","cloneRange","setStartAfter","collapse","removeAllRanges","addRange","type","createRange","pasteHTML","addImage","file","Promise","resolve","reject","reader","FileReader","onload","src","target","result","img","Image","imgStr","outerHTML","readAsDataURL","inputFile","settings","console","log","undefined","maxImageSize","maxImageNumber","enable","onclick","imageInput","accept","multiple","onchange","imgNum","getElementsByTagName","length","i","this","files","size","sendFile","click","sendFileFunc","fileInput","enableDrop","ondrop","preventDefault","stopPropagation","border","dataTransfer","indexOf","ondragover","ondragleave","onPaste","event","clipboardData","getData","text","execCommand","onmousedown","ev","olineOriBgColor","backgroundColor","dy","clientY","offsetHeight","onmousemove","diff","height","concat","onmouseup","emojiHeight","bottom","top","addEventListener"],"mappings":";;;;GAAA,aASA,IAAIA,WAAaC,SAASC,cAAc,iBAEpCC,MAAQF,SAASC,cAAc,sBAE/BE,UAAYH,SAASC,cAAc,mBAEnCG,WAAaD,UAAUE,aACvBC,YAAcP,WAAWM,aAGzBE,SAAWP,SAASQ,eAAe,YACnCC,SAAWT,SAASQ,eAAe,YACnCE,QAAUV,SAASQ,eAAe,WAClCG,eAAiBX,SAASQ,eAAe,kBACzCI,eAAiBZ,SAASQ,eAAe,kBACzCK,UAAYb,SAASQ,eAAe,aACpCM,SAAWd,SAASQ,eAAe,YACnCO,QAAUf,SAASQ,eAAe,WAClCQ,UAAYhB,SAASC,cAAc,8BAInCgB,cAAgB,CAClBC,OAAU,KACVC,cAAe,SAAUC,GAEvBP,UAAUQ,MAAMC,QAAU,OAC1BR,SAASO,MAAMC,QAAU,OACzBC,eAAeP,UAAWI,EAAEI,OAE9B,GAEEC,OAAS,IAAIC,UAAUC,OAAOV,eAIlC,SAASM,eAAeK,EAASC,GAC/B,IAAIC,EAASF,EACTG,EAAOF,EAGX,GAFAC,EAAOE,QAEHC,OAAOC,aAAc,CACvB,IAAIC,EAAYF,OAAOC,eACvB,GAAIC,EAAUC,YAAcD,EAAUE,WAAY,EAC5CC,EAAQH,EAAUC,WAAW,IAC3BG,iBACN,IAGIC,EACAC,EAJAC,EAAU1C,SAAS2C,cAAc,OACrCD,EAAQE,UAAYb,EAMpB,IAFA,IAAIc,EAAW7C,SAAS8C,yBAEhBN,EAAOE,EAAQK,YACrBN,EAAWI,EAASG,YAAYR,GAGlCF,EAAMW,WAAWJ,GACbJ,KACFH,EAAQA,EAAMY,cACRC,cAAcV,GACpBH,EAAMc,UAAS,GACfjB,EAAUkB,kBACVlB,EAAUmB,SAAShB,GAEvB,CAEF,MAAO,GAAItC,SAASmC,WAAwC,WAA3BnC,SAASmC,UAAUoB,KAAmB,CAErE,IAAIjB,EADJR,EAAOE,SACHM,EAAQtC,SAASmC,UAAUqB,eACzBC,UAAU1B,GAChBD,EAAOE,OACT,CACF,CAkFA,SAAS0B,SAASC,GAChB,IAAIC,SAAQ,SAACC,EAASC,GAGpB,IAAIC,EAAS,IAAIC,WACjBD,EAAOE,OAAS,SAAU7C,GACxB,IAAI8C,EAAM9C,EAAE+C,OAAOC,OACfC,EAAM,IAAIC,MACdD,EAAIH,IAAMA,EAOV,IAAIK,EAASF,EAAIG,UAEjBjD,eAAeP,UAAWuD,EAC5B,EACAR,EAAOU,cAAcd,EACvB,GACF,CAGA,SAASe,UAAUC,GAGjB,GAFAC,QAAQC,IAAIF,GAEiBG,MAAzBH,EAASI,aACX,IAAIA,EAAeJ,EAASI,kBAExBA,GAAgB,EAGtB,GAA+BD,MAA3BH,EAASK,eACX,IAAIA,EAAiBL,EAASK,oBAE1BA,GAAkB,EAGxB,GAAIL,EAASM,OAAQ,CAEnBxE,SAASyE,QAAU,WACjB,IAAIC,EAAanF,SAAS2C,cAAc,SACxCwC,EAAW5B,KAAO,OAClB4B,EAAWC,OAAS,UACpBD,EAAWE,UAAW,EACtBF,EAAW9D,MAAMC,QAAU,OAC3B6D,EAAWG,SAAW,WAIpB,IADA,IAAIC,EAASvE,UAAUwE,qBAAqB,OAAOC,OAC1CC,EAAI,EAAGA,EAAIC,KAAKC,MAAMH,OAAQC,MACd,GAAnBV,GAAwBO,EAASP,MAEb,GAAjBD,GAAsBY,KAAKC,MAAMF,GAAGG,MAAQd,GAC/CQ,IACA7B,SAASiC,KAAKC,MAAMF,KAEpBI,EAASH,KAAKC,MAAMF,IAI5B,EAEAP,EAAWY,OACb,EAEA,IAAID,EAAWnB,EAASqB,aAExBtF,QAAQwE,QAAU,WAEhB,IAAIe,EAAYjG,SAAS2C,cAAc,SACvCsD,EAAU1C,KAAO,OACjB0C,EAAUZ,UAAW,EACrBY,EAAU5E,MAAMC,QAAU,OAC1B2E,EAAUX,SAAW,WAEnB,IAAK,IAAII,EAAI,EAAGA,EAAIC,KAAKC,MAAMH,OAAQC,IAAK,CAC1C,IAAI/B,EAAOgC,KAAKC,MAAMF,GACtBI,EAASnC,EACX,CACF,EAEAsC,EAAUF,OACZ,EAGIpB,EAASuB,aAEX/F,UAAUgG,OAAS,SAAU/E,GAC3BA,EAAEgF,iBAEFhF,EAAEiF,kBACFlG,UAAUkB,MAAMiF,OAAS,OAGzB,IADA,IAAIf,EAASvE,UAAUwE,qBAAqB,OAAOC,OAC1CC,EAAI,EAAGA,EAAItE,EAAEmF,aAAaX,MAAMH,OAAQC,IAAK,CACpD,IAAI/B,EAAOvC,EAAEmF,aAAaX,MAAMF,GAEE,GAA9B/B,EAAKJ,KAAKiD,QAAQ,WACG,GAAnBxB,GAAwBO,EAASP,MAEb,GAAjBD,GAAsBpB,EAAKkC,MAAQd,GACtCrB,SAASC,GACT4B,KAEAO,EAASnC,IAIbmC,EAASnC,EAEb,CACF,EAGAxD,UAAUsG,WAAa,SAAUrF,GAC/BA,EAAEgF,iBACFjG,UAAUkB,MAAMiF,OAAS,mBAC3B,EAGAnG,UAAUuG,YAAc,SAAUtF,GAChCA,EAAEgF,iBACFjG,UAAUkB,MAAMiF,OAAS,MAC3B,EAEJ,MAEE7F,SAASyE,QAAU,KACnBxE,QAAQwE,QAAU,KAElB/E,UAAUgG,OAAS,KACnBhG,UAAUsG,WAAa,KACvBtG,UAAUuG,YAAc,IAE5B,CASA,SAASC,QAAQC,GAEf,GAAIA,EAAMC,eAAiBD,EAAMC,cAAcC,QAAS,CACtD,IAAIC,EAAOH,EAAMC,cAAcC,QAAQ,cACnCC,IACFH,EAAMR,iBACNpG,SAASgH,YAAY,cAAc,EAAOD,GAE9C,CACF,CApRAlG,UAAUmC,YAAYvB,QA2CtBvB,MAAM+G,YAAc,SAAUC,GAE5B,IAAMC,EAAkBjH,MAAMmB,MAAM+F,gBACpClH,MAAMmB,MAAM+F,gBAAkB,UAC9B,IACIC,GADSH,GAAMN,OACHU,QAkBhB,OAjBAhH,YAAcP,WAAWwH,aACzBnH,WAAaD,UAAUoH,aACvBvH,SAASwH,YAAc,SAAUN,GAC/B,IACIO,GADSP,GAAMN,OACDU,QAAUD,EACxB,IAAO/G,YAAcmH,GAAS,IAAOrH,WAAaqH,IAEpD1H,WAAWsB,MAAMqG,OAAM,eAAAC,OAAkBvH,WAAaqH,EAAI,OAC1DtH,UAAUkB,MAAMqG,OAAUtH,WAAaqH,EAAQ,KAEnD,EACAzH,SAAS4H,UAAY,WAEnB1H,MAAMmB,MAAM+F,gBAAkBD,EAC9BnH,SAASiH,YAAc,KACvBjH,SAASwH,YAAc,IACzB,GACO,CACT,EAGAjH,SAAS2E,QAAU,WACjBrE,UAAUQ,MAAMC,QAAU,QAC1BR,SAASO,MAAMC,QAAU,QAEzB,IAAIuG,EAAchH,UAAU0G,aAC3BnH,WAAaD,UAAUE,aAGpBwH,GAFHvH,YAAcP,WAAWM,eAGxBQ,UAAUQ,MAAMyG,OAAM,GAAAH,OAAMvH,WAAa,EAAC,MAC1CS,UAAUQ,MAAM0G,IAAM,KAEtBlH,UAAUQ,MAAMyG,OAAS,GACzBjH,UAAUQ,MAAM0G,IAAM,OAG1B,EAGApH,eAAeuE,QAAU,WACvB9E,WAAaD,UAAUE,aACvBC,YAAcP,WAAWM,aACzBF,UAAUkB,MAAMqG,OAAM,OACtB3H,WAAWsB,MAAMqG,OAAS,MAC1B/G,eAAeU,MAAMC,QAAU,OAC/BV,eAAeS,MAAMC,QAAU,QAC/BpB,MAAMmB,MAAMC,QAAU,MACxB,EAGAV,eAAesE,QAAU,WAEJ,GAAf5E,aACFH,UAAUkB,MAAMqG,OAAM,GAAAC,OAAMvH,WAAU,MACtCL,WAAWsB,MAAMqG,OAAM,eAAAC,OAAkBvH,WAAU,SAEnDL,WAAWsB,MAAMqG,OAAS,qBAC1BvH,UAAUkB,MAAMqG,OAAS,SAG3B9G,eAAeS,MAAMC,QAAU,OAC/BX,eAAeU,MAAMC,QAAU,QAC/BpB,MAAMmB,MAAMC,QAAU,OACxB,EAGAR,SAASoE,QAAU,WACjBrE,UAAUQ,MAAMC,QAAU,OAC1BR,SAASO,MAAMC,QAAU,MAC3B,EA+IAN,UAAUgH,iBAAiB,SAAS,SAAU5G,GAC5CuF,QAAQvF,EACV,IAcAa,OAAO+F,iBAAiB,oBAAoB,WAC1ChH,UAAUgB,OACZ","file":"../litewebchat_input.min.js","sourcesContent":["// !参考资料来源:\n// !https://blog.csdn.net/weixin_40629244/article/details/104642683\n// !https://github.com/jrainlau/chat-input-box\n// !https://www.zhihu.com/question/20893119/answer/19452676\n// !致谢:感谢@jrainlau提供的思路和代码,我在他的富文本编辑器基础上进行了修改,使其能够在聊天输入框中使用\n// ————YubaC 2023.1.23\n\n// --------------------------------\n// 上半部分的聊天区域\nlet upperChild = document.querySelector('.lite-chatbox');\n// 分界线\nlet oLine = document.querySelector('.lite-chatinput hr');\n// 下半部分的输入框区域\nlet downChild = document.querySelector('.lite-chatinput');\n\nvar downHeight = downChild.clientHeight;\nvar upperHeight = upperChild.clientHeight;\n\n// 以下为输入框区域的按钮\nvar emojiBtn = document.getElementById(\"emojiBtn\"); // 表情按钮\nvar imageBtn = document.getElementById(\"imageBtn\"); // 图片按钮\nvar fileBtn = document.getElementById(\"fileBtn\"); // 文件按钮\nvar editFullScreen = document.getElementById(\"editFullScreen\"); // 全屏按钮\nvar exitFullScreen = document.getElementById(\"exitFullScreen\"); // 退出全屏按钮\nvar emojiMart = document.getElementById(\"emojiMart\"); // 表情面板\nvar toolMusk = document.getElementById(\"toolMusk\"); // 表情面板遮罩\nvar sendBtn = document.getElementById(\"sendBtn\"); // 发送按钮\nvar chatInput = document.querySelector('.lite-chatinput>.chatinput'); // 输入框\n// --------------------------------\n\n// Emoji Mart(表情面板)设置及唤起\nvar pickerOptions = {\n \"locale\": \"zh\",\n onEmojiSelect: function (e) {\n // console.log(e.native);\n emojiMart.style.display = \"none\";\n toolMusk.style.display = \"none\";\n insertAtCursor(chatInput, e.native);\n // insertEmoji(e.native);\n }\n}\nvar picker = new EmojiMart.Picker(pickerOptions);\nemojiMart.appendChild(picker);\n\n// 负责在光标处插入文字的函数\nfunction insertAtCursor(myField, myValue) {\n var editor = myField;\n var html = myValue;\n editor.focus();\n\n if (window.getSelection) {\n var selection = window.getSelection();\n if (selection.getRangeAt && selection.rangeCount) {\n var range = selection.getRangeAt(0);\n range.deleteContents();\n var element = document.createElement('div');\n element.innerHTML = html;\n\n var node;\n var lastNode;\n var fragment = document.createDocumentFragment();\n\n while ((node = element.firstChild)) {\n lastNode = fragment.appendChild(node);\n };\n\n range.insertNode(fragment);\n if (lastNode) {\n range = range.cloneRange();\n range.setStartAfter(lastNode);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n };\n }\n\n } else if (document.selection && document.selection.type != 'Control') {\n editor.focus();\n var range = document.selection.createRange();\n range.pasteHTML(html);\n editor.focus();\n }\n}\n\n// 调整聊天区域和输入框区域比例的函数\noLine.onmousedown = function (ev) {\n // 更改oLine颜色为蓝色,方便查看分界线\n const olineOriBgColor = oLine.style.backgroundColor;\n oLine.style.backgroundColor = \"#1E90FF\";\n var iEvent = ev || event;\n var dy = iEvent.clientY; //当你第一次单击的时候,存储y轴的坐标。//相对于浏览器窗口\n upperHeight = upperChild.offsetHeight;\n downHeight = downChild.offsetHeight;\n document.onmousemove = function (ev) {\n var iEvent = ev || event;\n var diff = iEvent.clientY - dy; //移动的距离(向上滑时为负数,下滑时为正数)\n if (100 < (upperHeight + diff) && 100 < (downHeight - diff)) {\n //两个div的最小高度均为100px\n upperChild.style.height = `calc(100% - ${downHeight - diff}px)`;\n downChild.style.height = (downHeight - diff) + 'px';\n }\n };\n document.onmouseup = function () {\n // 更改oLine颜色为原色\n oLine.style.backgroundColor = olineOriBgColor;\n document.onmousedown = null;\n document.onmousemove = null;\n };\n return false;\n}\n\n// 显示表情输入框\nemojiBtn.onclick = function () {\n emojiMart.style.display = \"block\";\n toolMusk.style.display = \"block\";\n\n let emojiHeight = emojiMart.offsetHeight;\n downHeight = downChild.clientHeight;\n upperHeight = upperChild.clientHeight;\n\n if (emojiHeight < upperHeight) {\n emojiMart.style.bottom = `${downHeight + 3}px`\n emojiMart.style.top = '';\n } else {\n emojiMart.style.bottom = ''\n emojiMart.style.top = '10px';\n }\n\n}\n\n// 全屏编辑文字\neditFullScreen.onclick = function () {\n downHeight = downChild.clientHeight;\n upperHeight = upperChild.clientHeight;\n downChild.style.height = `100%`;\n upperChild.style.height = \"0px\";\n editFullScreen.style.display = \"none\";\n exitFullScreen.style.display = \"block\";\n oLine.style.display = \"none\";\n}\n\n// 退出全屏编辑文字\nexitFullScreen.onclick = function () {\n // 防呆不防傻,用于避免上部聊天窗口被压到没有高度后出现异常\n if (upperHeight != 0) {\n downChild.style.height = `${downHeight}px`;\n upperChild.style.height = `calc(100% - ${downHeight}px)`;\n } else {\n upperChild.style.height = \"calc(100% - 150px)\";\n downChild.style.height = \"150px\";\n }\n\n exitFullScreen.style.display = \"none\";\n editFullScreen.style.display = \"block\";\n oLine.style.display = \"block\";\n}\n\n// 隐藏musk和表情输入框\ntoolMusk.onclick = function () {\n emojiMart.style.display = \"none\";\n toolMusk.style.display = \"none\";\n}\n\n// 将图片插入到输入框中\nfunction addImage(file) {\n new Promise((resolve, reject) => {\n // console.log(file);\n // 获取file的src\n var reader = new FileReader();\n reader.onload = function (e) {\n var src = e.target.result;\n var img = new Image();\n img.src = src;\n\n // *这里的方法已经转移到了css里,暂时弃用\n // // 为了防止图片在输入框内显示过大不好编辑\n // img.style.width = \"100px\";\n // 将img从HEMLElement转化为字符串\n // 例如,转化结束后为''\n var imgStr = img.outerHTML;\n // 将img字符串插入到输入框中\n insertAtCursor(chatInput, imgStr);\n }\n reader.readAsDataURL(file);\n })\n}\n\n// 上传图片、文件\nfunction inputFile(settings) {\n console.log(settings);\n // -----------------设置最大图片大小及数量-----------------\n if (settings.maxImageSize != undefined) {\n var maxImageSize = settings.maxImageSize;\n } else {\n var maxImageSize = -1;\n }\n\n if (settings.maxImageNumber != undefined) {\n var maxImageNumber = settings.maxImageNumber;\n } else {\n var maxImageNumber = -1;\n }\n\n if (settings.enable) {\n // -----------------上传图片的按钮-----------------\n imageBtn.onclick = function () {\n var imageInput = document.createElement('input');\n imageInput.type = 'file';\n imageInput.accept = 'image/*';\n imageInput.multiple = true;\n imageInput.style.display = 'none';\n imageInput.onchange = function () {\n // 获取输入框内图片数量\n // 获取文件\n var imgNum = chatInput.getElementsByTagName('img').length;\n for (var i = 0; i < this.files.length; i++) {\n if (maxImageNumber == -1 || imgNum < maxImageNumber) {\n // 如果大小超过限制,改用文件上传\n if ((maxImageSize == -1 || this.files[i].size <= maxImageSize)) {\n imgNum++;\n addImage(this.files[i]);\n } else {\n sendFile(this.files[i]);\n }\n }\n }\n }\n // 触发点击事件\n imageInput.click();\n }\n // -----------------上传文件的按钮-----------------\n let sendFile = settings.sendFileFunc;\n // 上传文件按钮\n fileBtn.onclick = function () {\n // 创建一个隐藏的上传文件的input,再借助点击这个input来上传文件\n var fileInput = document.createElement('input');\n fileInput.type = 'file';\n fileInput.multiple = true;\n fileInput.style.display = 'none';\n fileInput.onchange = function () {\n // 获取文件\n for (var i = 0; i < this.files.length; i++) {\n var file = this.files[i];\n sendFile(file);\n }\n }\n // 触发点击事件\n fileInput.click();\n }\n\n // -----------------拖拽上传-----------------\n if (settings.enableDrop) {\n // 当downChild有文件被拖入时,也调用上传文件的函数\n downChild.ondrop = function (e) {\n e.preventDefault();\n // 阻止火狐浏览器默认打开文件的行为\n e.stopPropagation();\n downChild.style.border = \"none\";\n // 获取被拖拽的文件并上传\n var imgNum = chatInput.getElementsByTagName('img').length;\n for (var i = 0; i < e.dataTransfer.files.length; i++) {\n var file = e.dataTransfer.files[i];\n // 如果是图片,直接插入到输入框中\n if (file.type.indexOf(\"image\") == 0) {\n if (maxImageNumber == -1 || imgNum < maxImageNumber) {\n // 如果大小超过限制,改用文件上传\n if ((maxImageSize == -1 || file.size <= maxImageSize)) {\n addImage(file);\n imgNum++;\n } else {\n sendFile(file);\n }\n }\n } else {\n sendFile(file);\n }\n }\n }\n\n // 当downChild有文件被拖入时,改变downChild的边框颜色\n downChild.ondragover = function (e) {\n e.preventDefault();\n downChild.style.border = \"3px solid #1E90FF\";\n }\n\n // 当downChild有文件被拖入后离开时,改回downChild的边框颜色\n downChild.ondragleave = function (e) {\n e.preventDefault();\n downChild.style.border = \"none\";\n }\n }\n } else {\n // 如果不允许上传,那么删除事件\n imageBtn.onclick = null;\n fileBtn.onclick = null;\n // 删除拖拽事件\n downChild.ondrop = null;\n downChild.ondragover = null;\n downChild.ondragleave = null;\n }\n}\n\n// TODO:可能富文本输入框的粘贴部分需要对Chrome浏览器做部分额外适配,以优化体验\n// 无格式粘贴\nchatInput.addEventListener('paste', function (e) {\n onPaste(e);\n})\n\n//格式化粘贴文本方法\nfunction onPaste(event) {\n // 如果粘贴的是文本,就清除格式后粘贴\n if (event.clipboardData && event.clipboardData.getData) {\n var text = event.clipboardData.getData('text/plain');\n if (text) {\n event.preventDefault();\n document.execCommand('insertText', false, text);\n }\n }\n}\n\nwindow.addEventListener('DOMContentLoaded', function () {\n chatInput.focus();\n});\n"]} -------------------------------------------------------------------------------- /dist/js/map/litewebchat_render.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["render.js"],"names":["TipsType","tipsNormal","tipsPrimary","tipsSuccess","tipsInfo","tipsWarning","tipsDanger","TitleType","admin","owner","beforeRenderingHTML","data","chatboxClass","htmlStr","chatBox","document","querySelector","i","length","isRender","messageType","indexOf","renderTipHtml","html","renderMessageHtml","insertAdjacentHTML","setTimeout","scrollHeight","clientHeight","scrollTop","position","diamond","headIcon","renderTitleHtml","htitle","htitleType","escapeHtml","name","content","css","unsafe","replace","c","charCodeAt","slice"],"mappings":";;;;;;AAAA,IAAMA,QAAQ,GAAG;EACfC,UAAU,EAAE,MAAM;EAClBC,WAAW,EAAE,cAAc;EAC3BC,WAAW,EAAE,cAAc;EAC3BC,QAAQ,EAAE,WAAW;EACrBC,WAAW,EAAE,cAAc;EAC3BC,UAAU,EAAE;AACd,CAAC;AACD,IAAMC,SAAS,GAAG;EAChBC,KAAK,EAAE,OAAO;EACdC,KAAK,EAAE;AACT,CAAC;AAED,SAASC,mBAAmB,CAACC,IAAI,EAAEC,YAAY,EAAE;EAC/C,IAAIC,OAAO,GAAG,EAAE;EAChB,IAAIC,OAAO,GAAGC,QAAQ,CAACC,aAAa,CAACJ,YAAY,CAAC;EAClD,KAAK,IAAIK,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGN,IAAI,CAACO,MAAM,EAAED,CAAC,EAAE,EAAE;IACpC,IAAIN,IAAI,CAACM,CAAC,CAAC,CAACE,QAAQ,EAAE;MACpB;IACF;IACA,IAAIR,IAAI,CAACM,CAAC,CAAC,CAACG,WAAW,CAACC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;MAC9CR,OAAO,IAAIS,aAAa,CAACX,IAAI,CAACM,CAAC,CAAC,CAACM,IAAI,EAAEvB,QAAQ,CAACW,IAAI,CAACM,CAAC,CAAC,CAACG,WAAW,CAAC,IAAI,MAAM,CAAC;IACjF,CAAC,MAAM;MACLP,OAAO,IAAIW,iBAAiB,CAACb,IAAI,CAACM,CAAC,CAAC,CAAC;IACvC;IACAN,IAAI,CAACM,CAAC,CAAC,CAACE,QAAQ,GAAG,IAAI;EACzB;EAEAL,OAAO,CAACW,kBAAkB,CAAC,WAAW,EAACZ,OAAO,CAAC;EAC/Ca,UAAU,CAAC,YAAM;IACf,IAAIZ,OAAO,CAACa,YAAY,GAAGb,OAAO,CAACc,YAAY,EAAE;MAC/Cd,OAAO,CAACe,SAAS,GAAGf,OAAO,CAACa,YAAY;MACxCb,OAAO,GAAG,EAAE;MACZD,OAAO,GAAG,EAAE;IACd;EACF,CAAC,EAAE,GAAG,CAAC;AACT;AAEA,SAASW,iBAAiB,CAACb,IAAI,EAAE;EAC/B,+BAAuBA,IAAI,CAACmB,QAAQ,qDACPnB,IAAI,CAACoB,OAAO,GAAG,EAAE,GAAG,QAAQ,sBAAUpB,IAAI,CAACqB,QAAQ,4HAEpEC,eAAe,CAACtB,IAAI,CAACuB,MAAM,EAAE3B,SAAS,CAACI,IAAI,CAACwB,UAAU,CAAC,IAAI,EAAE,CAAC,iCACxDC,UAAU,CAACzB,IAAI,CAAC0B,IAAI,CAAC,IAAI,QAAQ,uEAErB1B,IAAI,CAACS,WAAW,KAAK,KAAK,GAAGT,IAAI,CAACY,IAAI,GAAGa,UAAU,CAACzB,IAAI,CAACY,IAAI,CAAC;AAE9F;AAEA,SAASU,eAAe,CAACK,OAAO,EAAEC,GAAG,EAAE;EACrC,IAAI,CAACD,OAAO,EAAE,OAAO,EAAE;EACvB,sCAA8BC,GAAG,6CAAgCD,OAAO;AAC1E;AAEA,SAAShB,aAAa,CAACgB,OAAO,EAAEC,GAAG,EAAE;EACnC,IAAI,CAACD,OAAO,EAAE,OAAO,EAAE;EACvB,mDAAyCC,GAAG,+CAAkCH,UAAU,CAACE,OAAO,CAAC;AACnG;;AAEA;AACA;AACA,SAASF,UAAU,CAACI,MAAM,EAAE;EAC1B,OAAOA,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEC,OAAO,CACpB,yDAAyD,EACzD,UAAAC,CAAC;IAAA,OAAI,IAAI,GAAG,CAAC,KAAK,GAAGA,CAAC,CAACC,UAAU,CAAC,CAAC,CAAC,EAAEC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;EAAA,EACtD;AACH","file":"../litewebchat_render.js","sourcesContent":["const TipsType = {\n tipsNormal: 'tips',\n tipsPrimary: 'tips-primary',\n tipsSuccess: 'tips-success',\n tipsInfo: 'tips-info',\n tipsWarning: 'tips-warning',\n tipsDanger: 'tips-danger',\n};\nconst TitleType = {\n admin: 'admin',\n owner: 'owner',\n};\n\nfunction beforeRenderingHTML(data, chatboxClass) {\n let htmlStr = '';\n let chatBox = document.querySelector(chatboxClass);\n for (let i = 0; i < data.length; i++) {\n if (data[i].isRender) {\n continue;\n }\n if (data[i].messageType.indexOf('tips') !== -1) {\n htmlStr += renderTipHtml(data[i].html, TipsType[data[i].messageType] || 'tips');\n } else {\n htmlStr += renderMessageHtml(data[i]);\n }\n data[i].isRender = true;\n }\n\n chatBox.insertAdjacentHTML('beforeend',htmlStr);\n setTimeout(() => {\n if (chatBox.scrollHeight > chatBox.clientHeight) {\n chatBox.scrollTop = chatBox.scrollHeight;\n chatBox = '';\n htmlStr = '';\n }\n }, 300);\n}\n\nfunction renderMessageHtml(data) {\n return `
\n \n \n ${renderTitleHtml(data.htitle, TitleType[data.htitleType] || '')}\n ${escapeHtml(data.name) || ' '}\n \n ${data.messageType === 'raw' ? data.html : escapeHtml(data.html)}\n
`;\n}\n\nfunction renderTitleHtml(content, css) {\n if (!content) return '';\n return `${content}`;\n}\n\nfunction renderTipHtml(content, css) {\n if (!content) return '';\n return `
${escapeHtml(content)}
`;\n}\n\n// 转义 C0 Controls and Basic Latin 中非数字和字母,C1 Controls and Latin-1 Supplement 全部\n// https://www.w3schools.com/charsets/ref_html_utf8.asp\nfunction escapeHtml(unsafe) {\n return unsafe?.replace(\n /[\\u0000-\\u002F\\u003A-\\u0040\\u005B-\\u0060\\u007B-\\u00FF]/g,\n c => '&#' + ('000' + c.charCodeAt(0)).slice(-4) + ';'\n )\n}\n"]} -------------------------------------------------------------------------------- /dist/js/map/litewebchat_render.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["render.js"],"names":["TipsType","tipsNormal","tipsPrimary","tipsSuccess","tipsInfo","tipsWarning","tipsDanger","TitleType","admin","owner","beforeRenderingHTML","data","chatboxClass","htmlStr","chatBox","document","querySelector","i","length","isRender","messageType","indexOf","renderTipHtml","html","renderMessageHtml","insertAdjacentHTML","setTimeout","scrollHeight","clientHeight","scrollTop","concat","position","diamond","headIcon","renderTitleHtml","htitle","htitleType","escapeHtml","name","content","css","unsafe","replace","c","charCodeAt","slice"],"mappings":";;;;GAAA,aAAA,IAAMA,SAAW,CACfC,WAAY,OACZC,YAAa,eACbC,YAAa,eACbC,SAAU,YACVC,YAAa,eACbC,WAAY,eAERC,UAAY,CAChBC,MAAO,QACPC,MAAO,SAGT,SAASC,oBAAoBC,EAAMC,GAGjC,IAFA,IAAIC,EAAU,GACVC,EAAUC,SAASC,cAAcJ,GAC5BK,EAAI,EAAGA,EAAIN,EAAKO,OAAQD,IAC3BN,EAAKM,GAAGE,YAGiC,IAAzCR,EAAKM,GAAGG,YAAYC,QAAQ,QAC9BR,GAAWS,cAAcX,EAAKM,GAAGM,KAAMvB,SAASW,EAAKM,GAAGG,cAAgB,QAExEP,GAAWW,kBAAkBb,EAAKM,IAEpCN,EAAKM,GAAGE,UAAW,GAGrBL,EAAQW,mBAAmB,YAAYZ,GACvCa,YAAW,WACLZ,EAAQa,aAAeb,EAAQc,eACjCd,EAAQe,UAAYf,EAAQa,aAC5Bb,EAAU,GACVD,EAAU,GAEd,GAAG,IACL,CAEA,SAASW,kBAAkBb,GACzB,MAAA,gBAAAmB,OAAuBnB,EAAKoB,SAAQ,0CAAAD,OACPnB,EAAKqB,QAAU,GAAK,SAAQ,WAAAF,OAAUnB,EAAKsB,SAAQ,4GAAAH,OAEpEI,gBAAgBvB,EAAKwB,OAAQ5B,UAAUI,EAAKyB,aAAe,IAAG,wBAAAN,OACxDO,WAAW1B,EAAK2B,OAAS,SAAQ,4DAAAR,OAEA,QAArBnB,EAAKS,YAAwBT,EAAKY,KAAOc,WAAW1B,EAAKY,MAAK,sBAE9F,CAEA,SAASW,gBAAgBK,EAASC,GAChC,OAAKD,EACL,uBAAAT,OAA8BU,EAAG,iCAAAV,OAAgCS,EAAO,WADnD,EAEvB,CAEA,SAASjB,cAAciB,EAASC,GAC9B,OAAKD,EACL,kCAAAT,OAAyCU,EAAG,mCAAAV,OAAkCO,WAAWE,GAAQ,iBAD5E,EAEvB,CAIA,SAASF,WAAWI,GAClB,OAAOA,aAAM,EAANA,EAAQC,QACb,2DACA,SAAAC,GAAC,MAAI,MAAQ,MAAQA,EAAEC,WAAW,IAAIC,OAAO,GAAK,GAAG,GAEzD","file":"../litewebchat_render.min.js","sourcesContent":["const TipsType = {\n tipsNormal: 'tips',\n tipsPrimary: 'tips-primary',\n tipsSuccess: 'tips-success',\n tipsInfo: 'tips-info',\n tipsWarning: 'tips-warning',\n tipsDanger: 'tips-danger',\n};\nconst TitleType = {\n admin: 'admin',\n owner: 'owner',\n};\n\nfunction beforeRenderingHTML(data, chatboxClass) {\n let htmlStr = '';\n let chatBox = document.querySelector(chatboxClass);\n for (let i = 0; i < data.length; i++) {\n if (data[i].isRender) {\n continue;\n }\n if (data[i].messageType.indexOf('tips') !== -1) {\n htmlStr += renderTipHtml(data[i].html, TipsType[data[i].messageType] || 'tips');\n } else {\n htmlStr += renderMessageHtml(data[i]);\n }\n data[i].isRender = true;\n }\n\n chatBox.insertAdjacentHTML('beforeend',htmlStr);\n setTimeout(() => {\n if (chatBox.scrollHeight > chatBox.clientHeight) {\n chatBox.scrollTop = chatBox.scrollHeight;\n chatBox = '';\n htmlStr = '';\n }\n }, 300);\n}\n\nfunction renderMessageHtml(data) {\n return `
\n \n \n ${renderTitleHtml(data.htitle, TitleType[data.htitleType] || '')}\n ${escapeHtml(data.name) || ' '}\n \n ${data.messageType === 'raw' ? data.html : escapeHtml(data.html)}\n
`;\n}\n\nfunction renderTitleHtml(content, css) {\n if (!content) return '';\n return `${content}`;\n}\n\nfunction renderTipHtml(content, css) {\n if (!content) return '';\n return `
${escapeHtml(content)}
`;\n}\n\n// 转义 C0 Controls and Basic Latin 中非数字和字母,C1 Controls and Latin-1 Supplement 全部\n// https://www.w3schools.com/charsets/ref_html_utf8.asp\nfunction escapeHtml(unsafe) {\n return unsafe?.replace(\n /[\\u0000-\\u002F\\u003A-\\u0040\\u005B-\\u0060\\u007B-\\u00FF]/g,\n c => '&#' + ('000' + c.charCodeAt(0)).slice(-4) + ';'\n )\n}\n"]} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { src, dest, parallel, series } = require('gulp'), 4 | rename = require("gulp-rename"), 5 | 6 | sass = require('gulp-sass')(require('sass')), 7 | autoprefixer = require('gulp-autoprefixer'), 8 | sourcemaps = require('gulp-sourcemaps'), 9 | cleanCSS = require('gulp-clean-css'), 10 | header = require('gulp-header'), 11 | pkg = require('./package.json'), 12 | banner = ` 13 | /*! 14 | * LiteWebChat_Frame ${pkg.version} (${pkg.homepage}) 15 | * MorFans Lab(c) 2017-${new Date().getFullYear()} 16 | * Licensed under ${pkg.license} 17 | */ 18 | `.trim(), 19 | 20 | pug = require('gulp-pug'), 21 | pangu = require('gulp-pangu'), 22 | 23 | babel = require('gulp-babel'), 24 | terser = require('gulp-terser'), 25 | 26 | clean = require('gulp-clean'), 27 | imagemin = require('gulp-imagemin'); 28 | 29 | const paths = { 30 | src_css: "./src/css", 31 | src_js: "./src/js", 32 | src_pug: "./src/pug", 33 | src_images: "./src/images/**/*", 34 | 35 | dist_images: "./dist/images", 36 | dist_html: "./dist/html", 37 | dist_css: "./dist/css", 38 | dist_js: "./dist/js", 39 | } 40 | 41 | function css(path, newName) { 42 | return src(path) 43 | .pipe(sourcemaps.init()) 44 | .pipe(sass({ includePaths: ['node_modules'] }).on('error', sass.logError)) 45 | .pipe(header(banner)) 46 | .pipe(autoprefixer()) 47 | .pipe(rename({ 48 | basename: newName, 49 | extname: ".css" 50 | })) 51 | .pipe(sourcemaps.write(`./map`)) 52 | .pipe(dest(paths.dist_css)) 53 | } 54 | 55 | function cssMin(path, newName) { 56 | return src(path) 57 | .pipe(sourcemaps.init()) 58 | .pipe(sass({ includePaths: ['node_modules'] }).on('error', sass.logError)) 59 | .pipe(header(banner)) 60 | .pipe(autoprefixer()) 61 | .pipe(cleanCSS({ compatibility: 'ie11' })) 62 | .pipe(rename({ 63 | basename: newName, 64 | extname: ".min.css" 65 | })) 66 | .pipe(sourcemaps.write('./map')) 67 | .pipe(dest(paths.dist_css)) 68 | } 69 | 70 | function js(path, newName) { 71 | return src(path) 72 | .pipe(sourcemaps.init()) 73 | .pipe(babel({ 74 | presets: ['@babel/env'] 75 | })) 76 | .pipe(header(banner)) 77 | .pipe(rename({ 78 | basename: newName, 79 | extname: ".js" 80 | })) 81 | .pipe(sourcemaps.write('./map')) 82 | .pipe(dest(paths.dist_js)) 83 | } 84 | 85 | function jsMin(path, newName) { 86 | return src(path) 87 | .pipe(sourcemaps.init()) 88 | .pipe(babel({ 89 | presets: ['@babel/env'] 90 | })) 91 | .pipe(terser()) 92 | .pipe(header(banner)) 93 | .pipe(rename({ 94 | basename: newName, 95 | extname: ".min.js" 96 | })) 97 | .pipe(sourcemaps.write('./map')) 98 | .pipe(dest(paths.dist_js)) 99 | } 100 | 101 | const buildLiteChat = (callback) => { 102 | css(paths.src_css + '/index.scss', 'litewebchat'); 103 | cssMin(paths.src_css + '/index.scss', 'litewebchat'); 104 | callback(); 105 | }, 106 | 107 | buildLiteChatInput = (cb) => { 108 | css(paths.src_css + '/chatinput.scss', 'litewebchat_input'); 109 | cssMin(paths.src_css + '/chatinput.scss', 'litewebchat_input'); 110 | cb(); 111 | }, 112 | 113 | buildHtml = (cb) => { 114 | // 这里不压缩 html, 防止其他使用者不能接受激进的 html 编写方式,但又需要方便的查看代码 115 | src(paths.src_pug + '/*.pug') 116 | .pipe(pug({ 117 | locals: {}, 118 | // pretty: true, 119 | })) 120 | .pipe(pangu()) 121 | .pipe(dest(paths.dist_html)); 122 | cb(); 123 | }, 124 | 125 | buildRenderJs = (cb) => { 126 | js(paths.src_js + '/render.js', 'litewebchat_render'); 127 | jsMin(paths.src_js + '/render.js', 'litewebchat_render'); 128 | cb(); 129 | }, 130 | 131 | buildInputJs = (cb) => { 132 | js(paths.src_js + '/input.js', 'litewebchat_input'); 133 | jsMin(paths.src_js + '/input.js', 'litewebchat_input'); 134 | cb(); 135 | }, 136 | 137 | minImage = (cb) => { 138 | src(paths.src_images) 139 | .pipe(imagemin()) 140 | .pipe(dest(paths.dist_images)); 141 | cb(); 142 | } 143 | 144 | 145 | ; 146 | 147 | function cleanFiles() { 148 | return src('./dist', { read: false }) 149 | .pipe(clean({ force: true })); 150 | } 151 | 152 | /** 153 | * build css 154 | */ 155 | exports.buildLiteChat = buildLiteChat; 156 | exports.buildLiteChatInput = buildLiteChatInput; 157 | 158 | /** 159 | * build html 160 | */ 161 | exports.buildHtml = buildHtml; 162 | 163 | /** 164 | * build js 165 | */ 166 | exports.buildRenderJs = buildRenderJs; 167 | exports.buildInputJs = buildInputJs; 168 | 169 | /** 170 | * build all 171 | */ 172 | exports.build = series( 173 | parallel(buildLiteChat, buildLiteChatInput), 174 | parallel(buildRenderJs, buildInputJs), 175 | parallel(minImage, buildHtml), 176 | ); 177 | 178 | exports.rebuild = series( 179 | cleanFiles, 180 | parallel(buildLiteChat, buildLiteChatInput), 181 | parallel(buildRenderJs, buildInputJs), 182 | parallel(minImage, buildHtml), 183 | ); 184 | 185 | exports.default = exports.build; 186 | -------------------------------------------------------------------------------- /lite-chatbox.min.js: -------------------------------------------------------------------------------- 1 | const TipsType={tipsNormal:"tips",tipsPrimary:"tips-primary",tipsSuccess:"tips-success",tipsInfo:"tips-info",tipsWarning:"tips-warning",tipsDanger:"tips-danger"},TitleType={admin:"admin",owner:"owner"};function beforeRenderingHTML(e,s){let t="",n=document.querySelector(s);for(let i=0;i{n.scrollHeight>n.clientHeight&&(n.scrollTop=n.scrollHeight,n="",t="")},300)}function renderMessageHtml(e){return`
2 | 3 | 4 | ${renderTitleHtml(e.htitle,TitleType[e.htitleType]||"")} 5 | ${escapeHtml(e.name)||" "} 6 | 7 | ${"raw"===e.messageType?e.html:escapeHtml(e.html)} 8 |
`}function renderTitleHtml(e,s){return e?`${e}`:""}function renderTipHtml(e,s){return e?`
${escapeHtml(e)}
`:""}function escapeHtml(e){return e.replace(/[\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00FF]/g,e=>"&#"+("000"+e.charCodeAt(0)).slice(-4)+";")} -------------------------------------------------------------------------------- /litewebchat.min.css: -------------------------------------------------------------------------------- 1 | /*! LiteWebChat_Frame v2.1.1 | MorFans Lab(c) 2017, BY:SuperPaxxs & Haswikr | https://lab.morfans.cn / Released under the LGPL License */ 2 | .lite-chatbox{font-family:Helvetica,"PingFang SC","Microsoft YaHei",sans-serif;padding:0;font-size:18px;width:100%;position:relative;overflow-y:auto;overflow-x:hidden}.lite-chatbox .cmsg{position:relative;margin:4px 7px;min-height:50px;border:0}.lite-chatbox .cright{text-align:right;margin-left:64px}.lite-chatbox .cleft{text-align:left;margin-right:64px}.lite-chatbox img.headIcon{width:34px;height:34px;top:9px;position:absolute;border:1px solid #c5d4c4}.lite-chatbox .name{color:#8b8b8b;font-size:12px;display:block;line-height:18px}.lite-chatbox .name>span{vertical-align:middle}.lite-chatbox .name .htitle{display:inline-block;padding:0 3px;background-color:#ccc;color:#fff;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;margin-right:4px;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;max-width:50px}.lite-chatbox .content{word-break:break-all;word-wrap:break-word;text-align:left;position:relative;display:inline-block;font-size:15px;padding:10px 15px;line-height:20px;white-space:pre-wrap;min-width:9px;min-height:18px}.lite-chatbox .content img{width:100%;height:auto}.lite-chatbox .content a{color:#0072c1;margin:0 5px;cursor:hand}.lite-chatbox .tips{margin:12px;text-align:center;font-size:12px}.lite-chatbox .tips span{display:inline-block;padding:4px;background-color:#ccc;color:#fff;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px}.lite-chatbox img.radius{-moz-border-radius:100%;-webkit-border-radius:100%;border-radius:100%}.lite-chatbox .cright img.headIcon{right:0}.lite-chatbox .cleft img.headIcon{left:0}.lite-chatbox .cright .name{margin:0 48px 2px 0}.lite-chatbox .cleft .name{margin:0 0 2px 48px}.lite-chatbox .cright .content{margin:0 48px 0 0;-webkit-border-radius:20px 0 20px 20px;border-radius:20px 0 20px 20px;color:#fff;background:-webkit-linear-gradient(70deg,#3fd1e1 0,#44d7cd 100%);background:linear-gradient(20deg,#3f8fe1cc 0,#44d7c9 100%);-webkit-box-shadow:5px 5px 15px 0 rgba(102,102,102,.15);box-shadow:5px 5px 15px 0 rgba(102,102,102,.15)}.lite-chatbox .cleft .content{margin:0 0 0 48px;-webkit-border-radius:0 20px 20px 20px;border-radius:0 20px 20px;color:#666;border:1px solid rgba(0,0,0,.05);background:#fff;-webkit-box-shadow:5px 5px 15px 0 rgba(102,102,102,.1);box-shadow:5px 5px 15px 0 rgba(102,102,102,.1)}.lite-chatbox .cright .content:after{right:-12px;top:8px}.lite-chatbox .cleft .content:after{left:-12px;top:8px}.lite-chatbox .tips .tips-primary{background-color:#3986c8}.lite-chatbox .tips .tips-success{background-color:#49b649}.lite-chatbox .tips .tips-info{background-color:#5bb6d1}.lite-chatbox .tips .tips-warning{background-color:#eea948}.lite-chatbox .tips .tips-danger{background-color:#e24d48}.lite-chatbox .name .admin{background-color:#72d6a0}.lite-chatbox .name .owner{background-color:#f2bf25} -------------------------------------------------------------------------------- /litewebchatinput.min.css: -------------------------------------------------------------------------------- 1 | .lite-chatbox{height:calc(100% - 150px)}.lite-chatbox>div:last-child{margin-bottom:20px}.lite-chatinput img{max-width:150px;max-height:150px;object-fit:contain}.lite-chatinput{width:100%;height:150px;position:relative;bottom:0;background-color:#fff}.lite-chatinput .boundary{cursor:s-resize;margin:0 auto;border-width:1px 0 0 0;border-color:rgba(0,0,0,.2);height:5px;background:#fff}.lite-chatinput>.chatinput{position:relative;overflow-y:scroll;width:calc(100% - 6px);margin:auto;height:calc(100% - 75px);border:none;outline:0;resize:none;font-size:20px;word-break:break-all;overflow-wrap:break-word;padding:5px;outline:0}.lite-chatinput .send{float:right;padding:4px 20px 4px 20px;margin-right:40px;color:#fff;background:-webkit-linear-gradient(70deg,#3fd1e1 0,#44d7cd 100%);background:linear-gradient(20deg,#3f8fe1cc 0,#44d7c9 100%);-webkit-box-shadow:5px 5px 15px 0 rgba(102,102,102,.1);box-shadow:5px 5px 15px 0 rgba(102,102,102,.1);border:none;border-radius:6px;-moz-border-radius:6px;-webkit-border-radius:6px}.lite-chatinput .send:hover{background:-webkit-linear-gradient(70deg,#3fd1e1 0,#44d7cd 60%);background:linear-gradient(20deg,#3f8fe1cc 0,#44d7c9 60%)}.lite-chatinput .send:active{background:-webkit-linear-gradient(70deg,#3fd1e1 0,#44d7cd 120%);background:linear-gradient(20deg,#3f8fe1cc 0,#44d7c9 120%)}.lite-chatinput .tool-button{padding:0 3px 0 3px;background:0 0;border:none;margin:5px;margin-bottom:0}.lite-chatinput .tool-button:hover{background:#f1f1f1}.lite-chatinput .tool-button:active{background:#e6e6e6}.lite-chatinput .tool-button path{fill:#8b8799}.lite-chatinput .tool-button svg{width:18px}.lite-chatbox-tool{position:absolute;margin-left:3px;z-index:3}#toolMusk{position:absolute;width:100vw;height:100vh;top:0;left:0;z-index:2}.float-left{float:left}.float-right{float:right}.lite-chatbox,.lite-chatinput>.chatinput,.scroll{scrollbar-width:thin;scrollbar-color:rgba(144,147,153,.3) rgba(144,147,153,.05)}::-webkit-scrollbar{width:10px;height:1px}::-webkit-scrollbar-thumb{border-radius:10px;background-color:rgba(144,147,153,.3);border:0}::-webkit-scrollbar-track{background:#fff;min-height:50%;min-height:20px;border-radius:8px}::-webkit-scrollbar-corner{background-color:transparent} -------------------------------------------------------------------------------- /litewebchatinput.min.js: -------------------------------------------------------------------------------- 1 | function insertAtCursor(e,t){var n=e,i=t;if(n.focus(),window.getSelection){var l=window.getSelection();if(l.getRangeAt&&l.rangeCount){var o=l.getRangeAt(0);o.deleteContents();var a,d,c=document.createElement("div");c.innerHTML=i;for(var r=document.createDocumentFragment();a=c.firstChild;)d=r.appendChild(a);o.insertNode(r),d&&(o=o.cloneRange(),o.setStartAfter(d),o.collapse(!0),l.removeAllRanges(),l.addRange(o))}}else if(document.selection&&"Control"!=document.selection.type){n.focus();o=document.selection.createRange();o.pasteHTML(i),n.focus()}}function addImage(e){new Promise((t,n)=>{var i=new FileReader;i.onload=function(e){var t=e.target.result,n=new Image;n.src=t;var i=n.outerHTML;insertAtCursor(chatInput,i)},i.readAsDataURL(e)})}function inputFile(e){console.log(e),null!=e.maxImageSize?maxImageSize=e.maxImageSize:maxImageSize=-1,null!=e.maxImageNumber?maxImageNumber=e.maxImageNumber:maxImageNumber=-1,e.enable?(imageBtn.onclick=function(){var e=document.createElement("input");e.type="file",e.accept="image/*",e.multiple=!0,e.style.display="none",e.onchange=function(){for(var e=chatInput.getElementsByTagName("img").length,t=0;t.chatinput"),pickerOptions={locale:"zh",onEmojiSelect:function(e){emojiMart.style.display="none",toolMusk.style.display="none",insertAtCursor(chatInput,e.native)}},picker=new EmojiMart.Picker(pickerOptions);emojiMart.appendChild(picker),oLine.onmousedown=function(e){oLine.style.backgroundColor="#1E90FF";var t=e||event,n=t.clientY,i=upperChild.offsetHeight,l=downChild.offsetHeight;return document.onmousemove=function(e){var t=e||event,o=t.clientY-n;100div:last-child { 12 | margin-bottom: 20px; 13 | } 14 | } 15 | 16 | // 输入框 17 | .lite-chatinput { 18 | width: 100%; 19 | height: 150px; 20 | position: relative; 21 | bottom: 0px; 22 | @include theme('background-color', $chat-bg-color-input); 23 | 24 | // 缩小输入框内的图片,方便编辑 25 | img { 26 | max-width: 150px; 27 | max-height: 150px; 28 | object-fit: contain; 29 | } 30 | 31 | // 聊天区域和输入框的分界线 32 | .boundary { 33 | cursor: s-resize; 34 | margin: 0 auto; 35 | border-width: 1px 0px 0px 0px; 36 | border-color: rgba(0, 0, 0, 0.2); 37 | height: 5px; 38 | @include theme('background', $chat-bg-color-input); 39 | } 40 | 41 | // 输入框 42 | >.chatinput { 43 | position: relative; 44 | overflow-y: scroll; 45 | /* margin: 0px 3px 0px 3px; */ 46 | width: calc(100% - 6px); 47 | margin: auto; 48 | /* width: 100%; */ 49 | height: calc(100% - 75px); 50 | /* height: 100%; */ 51 | border: none; 52 | outline: none; 53 | resize: none; 54 | font-size: 18px; 55 | @include theme('color', $chat-color-input); 56 | word-break: break-all; 57 | overflow-wrap: break-word; 58 | padding: 5px; 59 | outline: none; 60 | } 61 | 62 | // 发送按钮 63 | .send { 64 | float: right; 65 | padding: 4px 20px 4px 20px; 66 | 67 | margin: { 68 | right: 12px; 69 | top: -2px; 70 | } 71 | 72 | color: white; 73 | @include theme('background', $chat-message-bg-color-me); 74 | box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1); 75 | border: none; 76 | border-radius: 4px; 77 | @include push-animate; 78 | } 79 | 80 | // 输入框上方的输入表情等功能按钮 81 | .tool-button { 82 | padding: 0px 3px 0px 3px; 83 | background: none; 84 | border: none; 85 | margin: 5px; 86 | margin-bottom: 0px; 87 | @include push-animate; 88 | 89 | path { 90 | fill: rgb(139, 135, 153); 91 | } 92 | 93 | svg { 94 | width: 18px; 95 | } 96 | } 97 | 98 | // end of.tool-button 99 | } 100 | 101 | /* 由功能按钮唤起的功能页面 */ 102 | .lite-chatbox-tool { 103 | /* border: 5px solid red; */ 104 | position: absolute; 105 | /* bottom: 20px; */ 106 | margin-left: 3px; 107 | z-index: 3; 108 | } 109 | 110 | /* 部分功能页面需要用到的遮罩 */ 111 | #toolMusk { 112 | /* border: 3px solid red; */ 113 | position: absolute; 114 | width: 100vw; 115 | height: 100vh; 116 | top: 0; 117 | left: 0; 118 | z-index: 2; 119 | } 120 | 121 | .float-left { 122 | float: left; 123 | } 124 | 125 | .float-right { 126 | float: right; 127 | } 128 | -------------------------------------------------------------------------------- /src/css/components/color-htitle/_index.scss: -------------------------------------------------------------------------------- 1 | @import '../../variable/color/htitle'; 2 | 3 | $htitle-color-map: ( 4 | admin: $chat-message-bg-color-htitle-admin, 5 | owner: $chat-message-bg-color-htitle-owner 6 | ); 7 | 8 | 9 | .htitle { 10 | @each $type in map-keys($htitle-color-map) { 11 | &.#{$type} { 12 | @include theme('background-color', map-get($htitle-color-map, $type)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/css/components/color-scrollbar/_index.scss: -------------------------------------------------------------------------------- 1 | // 非 FF 浏览器配色 2 | $scrollbar-color: ( 3 | light:rgb(144 147 153 / 50%), 4 | dark:rgb(84 91 95 / 50%) 5 | ); 6 | $scrollbar-bg-color: ( 7 | light:#fff, 8 | dark:rgb(24, 26, 27) 9 | ); 10 | 11 | * { 12 | // 默认暗色 13 | scrollbar-color: #5c6163 #383b3c08; 14 | } 15 | 16 | /* else broswer */ 17 | ::-webkit-scrollbar { 18 | /* 滚动条整体样式 */ 19 | width: 7px; 20 | /* 高宽分别对应横竖滚动条的尺寸 */ 21 | height: 1px; 22 | } 23 | 24 | ::-webkit-scrollbar-thumb { 25 | /*滚动条里面小方块*/ 26 | border-radius: 10px; 27 | // background-color: ; 28 | @include theme('background-color', $scrollbar-color); 29 | border: 0; 30 | } 31 | 32 | ::-webkit-scrollbar-track { 33 | /*滚动条里面轨道*/ 34 | @include theme('background', $scrollbar-bg-color); 35 | min-height: 50%; 36 | min-height: 20px; 37 | } 38 | 39 | ::-webkit-scrollbar-corner { 40 | background-color: transparent; 41 | } 42 | 43 | ::selection { 44 | background-color: #1963bd !important; 45 | color: #f8f6f3 !important; 46 | } 47 | -------------------------------------------------------------------------------- /src/css/components/color-tips/_index.scss: -------------------------------------------------------------------------------- 1 | // 提示条颜色 2 | @import '../../variable/color/tips'; 3 | 4 | $tips-color-map: ( 5 | primary: $chat-message-bg-color-tips-primary, 6 | success: $chat-message-bg-color-tips-success, 7 | info: $chat-message-bg-color-tips-info, 8 | warning: $chat-message-bg-color-tips-warning, 9 | danger: $chat-message-bg-color-tips-danger 10 | ); 11 | 12 | .tips { 13 | @each $type in map-keys($tips-color-map) { 14 | .tips-#{$type} { 15 | @include theme('background-color', map-get($tips-color-map, $type)); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/css/components/htitle/_index.scss: -------------------------------------------------------------------------------- 1 | @import '../../variable/color/htitle'; 2 | 3 | $chat-message-bg-color-htitle: ( 4 | light:#cccccc, 5 | dark:rgb(76, 80, 82) 6 | ); 7 | 8 | // 名称与头衔对齐 9 | >span { 10 | vertical-align: middle; 11 | } 12 | 13 | // 头衔 14 | .htitle { 15 | display: inline-block; 16 | padding: 0 3px 0 3px; 17 | @include theme('background-color', $chat-message-bg-color-htitle); 18 | color: #ffffff; 19 | border-radius: 4px; 20 | margin-right: 4px; 21 | font-size: 11px; 22 | overflow: hidden; 23 | text-overflow: ellipsis; 24 | white-space: nowrap; 25 | vertical-align: middle; 26 | max-width: 50px; 27 | } 28 | -------------------------------------------------------------------------------- /src/css/components/tips/_index.scss: -------------------------------------------------------------------------------- 1 | @import '../../variable/color/tips'; 2 | 3 | // 聊天 tips 默认配色 4 | $chat-message-bg-color-tips: ( 5 | light:#ccc, 6 | dark:rgba(0, 0, 0, 0.3) 7 | ); 8 | 9 | $chat-message-color-tips: ( 10 | light:#fff, 11 | dark:#bec5cc 12 | ); 13 | 14 | // 聊天提示条 15 | .tips { 16 | margin: 12px; 17 | text-align: center; 18 | font-size: 12px; 19 | 20 | span { 21 | display: inline-block; 22 | padding: 4px; 23 | @include theme('background-color', $chat-message-bg-color-tips); 24 | @include theme('color', $chat-message-color-tips); 25 | border-radius: 6px; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/css/index.scss: -------------------------------------------------------------------------------- 1 | @import "normalize.css/normalize"; 2 | 3 | @import './mixin/theme'; 4 | 5 | @import './variable'; 6 | 7 | // 滚动条着色 8 | @import './components/color-scrollbar'; 9 | 10 | body { 11 | font-family: Helvetica, "PingFang SC", "Microsoft YaHei", sans-serif; 12 | } 13 | 14 | .lite-chatbox { 15 | // 聊天提示 16 | @import './components/tips'; 17 | @import './components/color-tips'; 18 | 19 | scroll-behavior: smooth; 20 | 21 | padding: 0px; 22 | width: 100%; 23 | position: relative; 24 | font-size: 18px; 25 | 26 | @include theme('background-color', $chat-content-bg-color); 27 | 28 | overflow: { 29 | y: auto; 30 | x: hidden; 31 | } 32 | 33 | .cmsg { 34 | position: relative; 35 | margin: 4px 7px; 36 | min-height: 50px; 37 | border: 0; 38 | } 39 | 40 | .cright { 41 | text-align: right; 42 | margin-left: 64px; 43 | 44 | img.headIcon { 45 | right: 0; 46 | } 47 | 48 | .name { 49 | margin: 0 48px 2px 0; 50 | } 51 | 52 | .content { 53 | margin: 0 48px 0 0; 54 | border-radius: 20px 0 20px 20px; 55 | color: white; 56 | @include theme('background', $chat-message-bg-color-me); 57 | 58 | box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.15); 59 | 60 | &::after { 61 | left: -12px; 62 | top: 8px; 63 | } 64 | } 65 | } 66 | 67 | .cleft { 68 | text-align: left; 69 | margin-right: 64px; 70 | 71 | img.headIcon { 72 | left: 0; 73 | } 74 | 75 | .name { 76 | margin: 0 0 2px 48px; 77 | } 78 | 79 | .content { 80 | margin: 0 0 0 48px; 81 | border-radius: 0 20px 20px 20px; 82 | @include theme('background', $chat-message-bg-color); 83 | @include theme('color', $chat-message-color, ); 84 | 85 | border: 1px solid rgba(0, 0, 0, 0.05); 86 | box-shadow: 5px 5px 15px 0 rgba(102, 102, 102, 0.1); 87 | 88 | &::after { 89 | left: -12px; 90 | top: 8px; 91 | } 92 | } 93 | } 94 | 95 | // 头像 96 | img { 97 | &.headIcon { 98 | width: 34px; 99 | height: 34px; 100 | top: 9px; 101 | position: absolute; 102 | } 103 | 104 | // 圆形头像 105 | &.radius { 106 | border-radius: 50%; 107 | } 108 | 109 | // .cright & { 110 | // right: 0; 111 | // } 112 | 113 | // end of img 114 | } 115 | 116 | // 昵称 117 | .name { 118 | color: #8b8b8b; 119 | font-size: 12px; 120 | display: block; 121 | line-height: 18px; 122 | 123 | // 头衔 124 | @import './components/htitle'; 125 | @import './components/color-htitle'; 126 | // end of .name 127 | } 128 | 129 | .content { 130 | word-break: break-all; 131 | word-wrap: break-word; 132 | text-align: left; 133 | position: relative; 134 | display: inline-block; 135 | font-size: 15px; 136 | padding: 10px 15px; 137 | line-height: 20px; 138 | white-space: pre-wrap; 139 | // 用于撑开空白消息 140 | min-width: 9px; 141 | min-height: 18px; 142 | 143 | // 处理图片 144 | img { 145 | width: 100%; 146 | height: auto; 147 | } 148 | 149 | // 超链接 150 | a { 151 | @include theme('color', $chat-message-color-herf); 152 | margin: 0 5px; 153 | cursor: hand; 154 | } 155 | 156 | // end of .content 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/css/mixin/_helper.scss: -------------------------------------------------------------------------------- 1 | @use "sass:selector"; 2 | 3 | @mixin unify-parent($child) { 4 | @at-root #{selector.unify(&, $child)} { 5 | @content; 6 | } 7 | } 8 | 9 | @mixin push-animate($time: .2, $scaleHover: 1.1, $scalePush: 0.9) { 10 | transition: all #{$time}s; // 让按下有呼吸感 11 | 12 | &:hover { 13 | transform: scale($scaleHover); 14 | opacity: .7; 15 | } 16 | 17 | &:active { 18 | transform: scale($scalePush); 19 | opacity: 1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/css/mixin/_theme.scss: -------------------------------------------------------------------------------- 1 | @mixin theme($key, $map_key) { 2 | $theme_colors: light, 3 | dark; 4 | 5 | @each $theme in $theme_colors { 6 | 7 | @if $theme ==light { 8 | // default light 9 | #{$key}: map-get($map: $map_key, $key: $theme); 10 | } 11 | 12 | @else { 13 | 14 | // 生成其他 15 | [litewebchat-theme=#{$theme}] & { 16 | #{$key}: map-get($map: $map_key, $key: $theme); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/css/variable/_colors.scss: -------------------------------------------------------------------------------- 1 | // 聊天背景色 2 | $chat-content-bg-color: ( 3 | light: #f8f9fa, 4 | dark:#131415 5 | ); 6 | 7 | // 聊天消息类 8 | // 聊天气泡双方背景 9 | $chat-message-bg-color: ( 10 | light:#fff, 11 | dark:#22242a 12 | ); 13 | 14 | $chat-message-bg-color-me: ( 15 | light:linear-gradient(20deg, #3f8fe1cc 0%, #44d7c9 100%), 16 | dark:linear-gradient(20deg, rgba(25, 91, 159, 0.8) 0px, rgb(33, 154, 146) 100%) 17 | ); 18 | 19 | // 聊天气泡对方前景 20 | $chat-message-color: ( 21 | light:#373737, 22 | dark:#d4d4d4 23 | ); 24 | 25 | $chat-message-color-herf: ( 26 | light: #0072C1, 27 | dark: #00c3ff 28 | ); 29 | 30 | // 输入框背景 31 | $chat-bg-color-input: ( 32 | light: #fff, 33 | dark: #202223 34 | ); 35 | 36 | // 输入框前景 37 | $chat-color-input: $chat-message-color; 38 | 39 | // 输入框按钮 40 | $chat-bg-color-button: $chat-message-bg-color-me; 41 | -------------------------------------------------------------------------------- /src/css/variable/color/_htitle.scss: -------------------------------------------------------------------------------- 1 | // 头衔增添配色 2 | $chat-message-bg-color-htitle-admin: ( 3 | light:#72D6A0, 4 | dark:rgb(60, 145, 110) 5 | ); 6 | $chat-message-bg-color-htitle-owner: ( 7 | light:#F2BF25, 8 | dark:rgb(154, 124, 33) 9 | ); 10 | -------------------------------------------------------------------------------- /src/css/variable/color/_tips.scss: -------------------------------------------------------------------------------- 1 | $chat-message-bg-color-tips-primary: ( 2 | light:#3986c8, 3 | dark:rgb(68, 127, 178) 4 | ); 5 | $chat-message-bg-color-tips-success: ( 6 | light:#49b649, 7 | dark:rgb(102, 166, 81) 8 | ); 9 | $chat-message-bg-color-tips-info: ( 10 | light:#5bb6d1, 11 | dark:rgb(63, 136, 158) 12 | ); 13 | $chat-message-bg-color-tips-warning: ( 14 | light:#eea948, 15 | dark:rgb(175, 119, 40) 16 | ); 17 | $chat-message-bg-color-tips-danger: ( 18 | light:#e24d48, 19 | dark:rgb(173, 53, 49) 20 | ); 21 | -------------------------------------------------------------------------------- /src/images/A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/src/images/A.jpg -------------------------------------------------------------------------------- /src/images/B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/src/images/B.jpg -------------------------------------------------------------------------------- /src/images/H.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/src/images/H.jpg -------------------------------------------------------------------------------- /src/images/O.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/src/images/O.jpg -------------------------------------------------------------------------------- /src/images/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/src/images/img.png -------------------------------------------------------------------------------- /src/images/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorFansLab/LiteWebChat_Frame/97e4d38097f2a7ce1345ff9c7be9d4c9c85c3848/src/images/img2.png -------------------------------------------------------------------------------- /src/js/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env"] 3 | } 4 | -------------------------------------------------------------------------------- /src/js/input.js: -------------------------------------------------------------------------------- 1 | // !参考资料来源: 2 | // !https://blog.csdn.net/weixin_40629244/article/details/104642683 3 | // !https://github.com/jrainlau/chat-input-box 4 | // !https://www.zhihu.com/question/20893119/answer/19452676 5 | // !致谢:感谢@jrainlau提供的思路和代码,我在他的富文本编辑器基础上进行了修改,使其能够在聊天输入框中使用 6 | // ————YubaC 2023.1.23 7 | 8 | // -------------------------------- 9 | // 上半部分的聊天区域 10 | let upperChild = document.querySelector('.lite-chatbox'); 11 | // 分界线 12 | let oLine = document.querySelector('.lite-chatinput hr'); 13 | // 下半部分的输入框区域 14 | let downChild = document.querySelector('.lite-chatinput'); 15 | 16 | var downHeight = downChild.clientHeight; 17 | var upperHeight = upperChild.clientHeight; 18 | 19 | // 以下为输入框区域的按钮 20 | var emojiBtn = document.getElementById("emojiBtn"); // 表情按钮 21 | var imageBtn = document.getElementById("imageBtn"); // 图片按钮 22 | var fileBtn = document.getElementById("fileBtn"); // 文件按钮 23 | var editFullScreen = document.getElementById("editFullScreen"); // 全屏按钮 24 | var exitFullScreen = document.getElementById("exitFullScreen"); // 退出全屏按钮 25 | var emojiMart = document.getElementById("emojiMart"); // 表情面板 26 | var toolMusk = document.getElementById("toolMusk"); // 表情面板遮罩 27 | var sendBtn = document.getElementById("sendBtn"); // 发送按钮 28 | var chatInput = document.querySelector('.lite-chatinput>.chatinput'); // 输入框 29 | // -------------------------------- 30 | 31 | // Emoji Mart(表情面板)设置及唤起 32 | var pickerOptions = { 33 | "locale": "zh", 34 | onEmojiSelect: function (e) { 35 | // console.log(e.native); 36 | emojiMart.style.display = "none"; 37 | toolMusk.style.display = "none"; 38 | insertAtCursor(chatInput, e.native); 39 | // insertEmoji(e.native); 40 | } 41 | } 42 | var picker = new EmojiMart.Picker(pickerOptions); 43 | emojiMart.appendChild(picker); 44 | 45 | // 负责在光标处插入文字的函数 46 | function insertAtCursor(myField, myValue) { 47 | var editor = myField; 48 | var html = myValue; 49 | editor.focus(); 50 | 51 | if (window.getSelection) { 52 | var selection = window.getSelection(); 53 | if (selection.getRangeAt && selection.rangeCount) { 54 | var range = selection.getRangeAt(0); 55 | range.deleteContents(); 56 | var element = document.createElement('div'); 57 | element.innerHTML = html; 58 | 59 | var node; 60 | var lastNode; 61 | var fragment = document.createDocumentFragment(); 62 | 63 | while ((node = element.firstChild)) { 64 | lastNode = fragment.appendChild(node); 65 | }; 66 | 67 | range.insertNode(fragment); 68 | if (lastNode) { 69 | range = range.cloneRange(); 70 | range.setStartAfter(lastNode); 71 | range.collapse(true); 72 | selection.removeAllRanges(); 73 | selection.addRange(range); 74 | }; 75 | } 76 | 77 | } else if (document.selection && document.selection.type != 'Control') { 78 | editor.focus(); 79 | var range = document.selection.createRange(); 80 | range.pasteHTML(html); 81 | editor.focus(); 82 | } 83 | } 84 | 85 | // 调整聊天区域和输入框区域比例的函数 86 | oLine.onmousedown = function (ev) { 87 | // 更改oLine颜色为蓝色,方便查看分界线 88 | const olineOriBgColor = oLine.style.backgroundColor; 89 | oLine.style.backgroundColor = "#1E90FF"; 90 | var iEvent = ev || event; 91 | var dy = iEvent.clientY; //当你第一次单击的时候,存储y轴的坐标。//相对于浏览器窗口 92 | upperHeight = upperChild.offsetHeight; 93 | downHeight = downChild.offsetHeight; 94 | document.onmousemove = function (ev) { 95 | var iEvent = ev || event; 96 | var diff = iEvent.clientY - dy; //移动的距离(向上滑时为负数,下滑时为正数) 97 | if (100 < (upperHeight + diff) && 100 < (downHeight - diff)) { 98 | //两个div的最小高度均为100px 99 | upperChild.style.height = `calc(100% - ${downHeight - diff}px)`; 100 | downChild.style.height = (downHeight - diff) + 'px'; 101 | } 102 | }; 103 | document.onmouseup = function () { 104 | // 更改oLine颜色为原色 105 | oLine.style.backgroundColor = olineOriBgColor; 106 | document.onmousedown = null; 107 | document.onmousemove = null; 108 | }; 109 | return false; 110 | } 111 | 112 | // 显示表情输入框 113 | emojiBtn.onclick = function () { 114 | emojiMart.style.display = "block"; 115 | toolMusk.style.display = "block"; 116 | 117 | let emojiHeight = emojiMart.offsetHeight; 118 | downHeight = downChild.clientHeight; 119 | upperHeight = upperChild.clientHeight; 120 | 121 | if (emojiHeight < upperHeight) { 122 | emojiMart.style.bottom = `${downHeight + 3}px` 123 | emojiMart.style.top = ''; 124 | } else { 125 | emojiMart.style.bottom = '' 126 | emojiMart.style.top = '10px'; 127 | } 128 | 129 | } 130 | 131 | // 全屏编辑文字 132 | editFullScreen.onclick = function () { 133 | downHeight = downChild.clientHeight; 134 | upperHeight = upperChild.clientHeight; 135 | downChild.style.height = `100%`; 136 | upperChild.style.height = "0px"; 137 | editFullScreen.style.display = "none"; 138 | exitFullScreen.style.display = "block"; 139 | oLine.style.display = "none"; 140 | } 141 | 142 | // 退出全屏编辑文字 143 | exitFullScreen.onclick = function () { 144 | // 防呆不防傻,用于避免上部聊天窗口被压到没有高度后出现异常 145 | if (upperHeight != 0) { 146 | downChild.style.height = `${downHeight}px`; 147 | upperChild.style.height = `calc(100% - ${downHeight}px)`; 148 | } else { 149 | upperChild.style.height = "calc(100% - 150px)"; 150 | downChild.style.height = "150px"; 151 | } 152 | 153 | exitFullScreen.style.display = "none"; 154 | editFullScreen.style.display = "block"; 155 | oLine.style.display = "block"; 156 | } 157 | 158 | // 隐藏musk和表情输入框 159 | toolMusk.onclick = function () { 160 | emojiMart.style.display = "none"; 161 | toolMusk.style.display = "none"; 162 | } 163 | 164 | // 将图片插入到输入框中 165 | function addImage(file) { 166 | new Promise((resolve, reject) => { 167 | // console.log(file); 168 | // 获取file的src 169 | var reader = new FileReader(); 170 | reader.onload = function (e) { 171 | var src = e.target.result; 172 | var img = new Image(); 173 | img.src = src; 174 | 175 | // *这里的方法已经转移到了css里,暂时弃用 176 | // // 为了防止图片在输入框内显示过大不好编辑 177 | // img.style.width = "100px"; 178 | // 将img从HEMLElement转化为字符串 179 | // 例如,转化结束后为'' 180 | var imgStr = img.outerHTML; 181 | // 将img字符串插入到输入框中 182 | insertAtCursor(chatInput, imgStr); 183 | } 184 | reader.readAsDataURL(file); 185 | }) 186 | } 187 | 188 | // 上传图片、文件 189 | function inputFile(settings) { 190 | console.log(settings); 191 | // -----------------设置最大图片大小及数量----------------- 192 | if (settings.maxImageSize != undefined) { 193 | var maxImageSize = settings.maxImageSize; 194 | } else { 195 | var maxImageSize = -1; 196 | } 197 | 198 | if (settings.maxImageNumber != undefined) { 199 | var maxImageNumber = settings.maxImageNumber; 200 | } else { 201 | var maxImageNumber = -1; 202 | } 203 | 204 | if (settings.enable) { 205 | // -----------------上传图片的按钮----------------- 206 | imageBtn.onclick = function () { 207 | var imageInput = document.createElement('input'); 208 | imageInput.type = 'file'; 209 | imageInput.accept = 'image/*'; 210 | imageInput.multiple = true; 211 | imageInput.style.display = 'none'; 212 | imageInput.onchange = function () { 213 | // 获取输入框内图片数量 214 | // 获取文件 215 | var imgNum = chatInput.getElementsByTagName('img').length; 216 | for (var i = 0; i < this.files.length; i++) { 217 | if (maxImageNumber == -1 || imgNum < maxImageNumber) { 218 | // 如果大小超过限制,改用文件上传 219 | if ((maxImageSize == -1 || this.files[i].size <= maxImageSize)) { 220 | imgNum++; 221 | addImage(this.files[i]); 222 | } else { 223 | sendFile(this.files[i]); 224 | } 225 | } 226 | } 227 | } 228 | // 触发点击事件 229 | imageInput.click(); 230 | } 231 | // -----------------上传文件的按钮----------------- 232 | let sendFile = settings.sendFileFunc; 233 | // 上传文件按钮 234 | fileBtn.onclick = function () { 235 | // 创建一个隐藏的上传文件的input,再借助点击这个input来上传文件 236 | var fileInput = document.createElement('input'); 237 | fileInput.type = 'file'; 238 | fileInput.multiple = true; 239 | fileInput.style.display = 'none'; 240 | fileInput.onchange = function () { 241 | // 获取文件 242 | for (var i = 0; i < this.files.length; i++) { 243 | var file = this.files[i]; 244 | sendFile(file); 245 | } 246 | } 247 | // 触发点击事件 248 | fileInput.click(); 249 | } 250 | 251 | // -----------------拖拽上传----------------- 252 | if (settings.enableDrop) { 253 | // 当downChild有文件被拖入时,也调用上传文件的函数 254 | downChild.ondrop = function (e) { 255 | e.preventDefault(); 256 | // 阻止火狐浏览器默认打开文件的行为 257 | e.stopPropagation(); 258 | downChild.style.border = "none"; 259 | // 获取被拖拽的文件并上传 260 | var imgNum = chatInput.getElementsByTagName('img').length; 261 | for (var i = 0; i < e.dataTransfer.files.length; i++) { 262 | var file = e.dataTransfer.files[i]; 263 | // 如果是图片,直接插入到输入框中 264 | if (file.type.indexOf("image") == 0) { 265 | if (maxImageNumber == -1 || imgNum < maxImageNumber) { 266 | // 如果大小超过限制,改用文件上传 267 | if ((maxImageSize == -1 || file.size <= maxImageSize)) { 268 | addImage(file); 269 | imgNum++; 270 | } else { 271 | sendFile(file); 272 | } 273 | } 274 | } else { 275 | sendFile(file); 276 | } 277 | } 278 | } 279 | 280 | // 当downChild有文件被拖入时,改变downChild的边框颜色 281 | downChild.ondragover = function (e) { 282 | e.preventDefault(); 283 | downChild.style.border = "3px solid #1E90FF"; 284 | } 285 | 286 | // 当downChild有文件被拖入后离开时,改回downChild的边框颜色 287 | downChild.ondragleave = function (e) { 288 | e.preventDefault(); 289 | downChild.style.border = "none"; 290 | } 291 | } 292 | } else { 293 | // 如果不允许上传,那么删除事件 294 | imageBtn.onclick = null; 295 | fileBtn.onclick = null; 296 | // 删除拖拽事件 297 | downChild.ondrop = null; 298 | downChild.ondragover = null; 299 | downChild.ondragleave = null; 300 | } 301 | } 302 | 303 | // TODO:可能富文本输入框的粘贴部分需要对Chrome浏览器做部分额外适配,以优化体验 304 | // 无格式粘贴 305 | chatInput.addEventListener('paste', function (e) { 306 | onPaste(e); 307 | }) 308 | 309 | //格式化粘贴文本方法 310 | function onPaste(event) { 311 | // 如果粘贴的是文本,就清除格式后粘贴 312 | if (event.clipboardData && event.clipboardData.getData) { 313 | var text = event.clipboardData.getData('text/plain'); 314 | if (text) { 315 | event.preventDefault(); 316 | document.execCommand('insertText', false, text); 317 | } 318 | } 319 | } 320 | 321 | window.addEventListener('DOMContentLoaded', function () { 322 | chatInput.focus(); 323 | }); 324 | -------------------------------------------------------------------------------- /src/js/render.js: -------------------------------------------------------------------------------- 1 | const TipsType = { 2 | tipsNormal: 'tips', 3 | tipsPrimary: 'tips-primary', 4 | tipsSuccess: 'tips-success', 5 | tipsInfo: 'tips-info', 6 | tipsWarning: 'tips-warning', 7 | tipsDanger: 'tips-danger', 8 | }; 9 | const TitleType = { 10 | admin: 'admin', 11 | owner: 'owner', 12 | }; 13 | 14 | function beforeRenderingHTML(data, chatboxClass) { 15 | let htmlStr = ''; 16 | let chatBox = document.querySelector(chatboxClass); 17 | for (let i = 0; i < data.length; i++) { 18 | if (data[i].isRender) { 19 | continue; 20 | } 21 | if (data[i].messageType.indexOf('tips') !== -1) { 22 | htmlStr += renderTipHtml(data[i].html, TipsType[data[i].messageType] || 'tips'); 23 | } else { 24 | htmlStr += renderMessageHtml(data[i]); 25 | } 26 | data[i].isRender = true; 27 | } 28 | 29 | chatBox.insertAdjacentHTML('beforeend',htmlStr); 30 | setTimeout(() => { 31 | if (chatBox.scrollHeight > chatBox.clientHeight) { 32 | chatBox.scrollTop = chatBox.scrollHeight; 33 | chatBox = ''; 34 | htmlStr = ''; 35 | } 36 | }, 300); 37 | } 38 | 39 | function renderMessageHtml(data) { 40 | return `
41 | 42 | 43 | ${renderTitleHtml(data.htitle, TitleType[data.htitleType] || '')} 44 | ${escapeHtml(data.name) || ' '} 45 | 46 | ${data.messageType === 'raw' ? data.html : escapeHtml(data.html)} 47 |
`; 48 | } 49 | 50 | function renderTitleHtml(content, css) { 51 | if (!content) return ''; 52 | return `${content}`; 53 | } 54 | 55 | function renderTipHtml(content, css) { 56 | if (!content) return ''; 57 | return `
${escapeHtml(content)}
`; 58 | } 59 | 60 | // 转义 C0 Controls and Basic Latin 中非数字和字母,C1 Controls and Latin-1 Supplement 全部 61 | // https://www.w3schools.com/charsets/ref_html_utf8.asp 62 | function escapeHtml(unsafe) { 63 | return unsafe?.replace( 64 | /[\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00FF]/g, 65 | c => '&#' + ('000' + c.charCodeAt(0)).slice(-4) + ';' 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /src/pug/chat_example.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | head 4 | meta(charset="UTF-8") 5 | meta(name="viewport", content="width=device-width, initial-scale=1.0") 6 | meta(http-equiv="X-UA-Compatible", content="ie=edge") 7 | title LiteChat_Frame(轻聊天气泡框架) 8 | link(rel="stylesheet", type="text/css", href="../css/litewebchat.min.css") 9 | style. 10 | html, 11 | body { 12 | height: 100%; 13 | margin: 0; 14 | padding: 0; 15 | } 16 | body 17 | // 主容器 18 | .lite-chatbox 19 | // cleft 左 20 | .cleft.cmsg 21 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 22 | span.name 23 | span chenjunyu19 24 | span.content 这是什么什么鬼? 25 | // cright 右 26 | .cright.cmsg 27 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 28 | span.name 29 | span SuperPaxxs 30 | span.content LiteChat_Frame(轻聊天气泡框架),一个贼简洁 31 | del (简单) 32 | | 、美观、易用的 HTML 聊天界面框架 33 | .cright.cmsg 34 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 35 | span.name 36 | span SuperPaxxs 37 | span.content 它简洁而不简单,能使你开发聊天界面更快速 38 | .cright.cmsg 39 | img.headIcon.radius(src="../images/B.jpg", ondragstart="return false;", oncontextmenu="return false;") 40 | span.name 41 | span.htitle.owner(style="margin: 0 4px 0 0;") NEW 42 | span SuperPaxxs 43 | span.content LiteChat_Frame 拥有暗色模式, 快来试试吧: 44 | br 45 | br 46 | style. 47 | .theme-switch{background: none;border: solid 1px;border-radius: 2em;font: inherit;cursor: pointer;color: #fff;} 48 | button.theme-switch 切换配色 49 | .cleft.cmsg 50 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 51 | span.name 52 | span chenjunyu19 53 | span.content 直接说,气泡是谁的? 54 | .cright.cmsg 55 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 56 | span.name 57 | span SuperPaxxs 58 | span.content 好吧,气泡css来自 Haswikr的 Blog 的机器人气泡 😝 59 | .cleft.cmsg 60 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/H.jpg") 61 | span.name 62 | span.htitle.admin admin 63 | span Haswikr 64 | span.content 当初调色煞费苦心 65 | .cleft.cmsg 66 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/O.jpg") 67 | span.name 68 | span.htitle.owner owner 69 | span Sonui 70 | span.content 这设计真棒 71 | .cleft.cmsg 72 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 73 | span.name 74 | span.htitle menber123456789789 75 | span chenjunyu19 76 | span.content 那咋用啊? 77 | .cright.cmsg 78 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 79 | span.name 80 | span SuperPaxxs 81 | span.content 诶哟少年你找对人了

如果只是使用,那非常简单。

使用指北


1. 引用 css: litechat.css

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.css" rel="stylesheet" />

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.min.css" rel="stylesheet" />

2. 创建一个 DIV ,用来容纳聊天对话,目的是不让 css 干扰页面其他内容:

<div class="lite-chatbox">
...
</div>

话说你就不会看下源码吗...楼下是特性演示 82 | .tips 83 | span Chenjunyu19 退出了聊天室并撩了你一把 84 | .cleft.cmsg 85 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 86 | span.name 87 | span 空消息测试1 88 | span.content 89 | .cright.cmsg 90 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 91 | span.name 92 | span 空消息测试2 93 | span.content   94 | .cleft.cmsg 95 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 96 | span.name 97 | span chenjunyu19 98 | span.content 注意,上面两条空消息的消息内容代码不一样 99 | .cright.cmsg 100 | img.headIcon(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 101 | span.name 102 | span SuperPaxxs 103 | span.content 头像换成方形请去掉 radius 104 | .cleft.cmsg 105 | img.headIcon(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 106 | span.name 107 | span chenjunyu19 108 | span.content 我是左边的方形头像 109 | .cright.cmsg 110 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 111 | span.name 112 | span 图片消息 113 | span.content 114 | img(src="../images/img2.png") 115 | .cleft.cmsg 116 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 117 | span.name 118 | span 图片消息2 119 | span.content 120 | img(src="../images/img.png") 121 |
122 | | 图片带文字是可以的#[del (废话)] 123 | .cright.cmsg 124 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 125 | span.name 126 | span 右边长消息 127 | span.content 我的消息真的超级长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长欸 128 | .cleft.cmsg 129 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 130 | span.name 131 | span 左边长消息 132 | span.content 这么巧鸭,我的也超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超级长的欸 133 | .tips 134 | span.tips-danger 系统消息:左/右边长消息被管理员批判一番…… 135 | .tips 136 | span 系统消息:normal 137 | .tips 138 | span.tips-primary 系统消息:primary 139 | .tips 140 | span.tips-success 系统消息:success 141 | .tips 142 | span.tips-info 系统消息:info 143 | .tips 144 | span.tips-warning 系统消息:warning 145 | .tips 146 | span.tips-danger 系统消息:danger 147 | .cright.cmsg 148 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 149 | span.name 150 | span 带有超链接的消息测试 151 | span.content 当然是可以有超链接的。例子在这里: 152 | br 153 | a(href="http://morfans.cn" target="_blank") 你敢点我吗 154 | | ← 戳这里 155 | .cleft.cmsg 156 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 157 | span.name 158 | span 全符号测试 159 | span.content 。,;?:!‘’“”@ˆ.,;?:!'"〝〞﹫ˇ 160 | .cleft.cmsg 161 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 162 | span.name 163 | span 全emoji测试 164 | span.content 😀😝🐂🍺 165 | .cright.cmsg 166 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 167 | span.name 168 | span   169 | span.content 当无昵时候需要 &nbsp; 填充 170 | .cright.cmsg 171 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/B.jpg") 172 | span.name 173 | span SuperPaxxs 174 | span.content 换行用 <br>,HTML 你懂的.. 175 | .cleft.cmsg 176 | img.headIcon.radius(ondragstart="return false;" oncontextmenu="return false;" src="../images/A.jpg") 177 | span.name 178 | span chenjunyu19 179 | span.content 以上就是全部的特性,以后有空再更 180 | script. 181 | const btns = document.querySelectorAll('.theme-switch'); 182 | const html = document.documentElement; 183 | const addEvent = btn => { 184 | btn.addEventListener('click', e => { 185 | let theme = html.getAttribute("litewebchat-theme"); 186 | if (theme === 'dark') { 187 | html.setAttribute("litewebchat-theme", 'light'); 188 | } else { 189 | html.setAttribute("litewebchat-theme", 'dark'); 190 | } 191 | }); 192 | }; 193 | btns.forEach(btn => { 194 | addEvent(btn); 195 | }); 196 | -------------------------------------------------------------------------------- /src/pug/chat_with_inputarea_module_example.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | head 4 | meta(charset="UTF-8") 5 | meta(name="viewport" content="height=device-height, initial-scale=1.0") 6 | meta(http-equiv="X-UA-Compatible" content="ie=edge") 7 | title LiteChat_Frame(轻聊天气泡框架) 8 | link(rel="stylesheet" type="text/css" href="../css/litewebchat.min.css") 9 | link(rel="stylesheet" type="text/css" href="../css/litewebchat_input.min.css") 10 | style. 11 | /* 全局 */ 12 | 13 | html, 14 | body { 15 | height: 100%; 16 | margin: 0; 17 | padding: 0; 18 | overflow: hidden; 19 | } 20 | 21 | .lite-chatmaster { 22 | height: 100%; 23 | width: 100%; 24 | } 25 | 26 | ::-webkit-scrollbar { 27 | /*滚动条整体样式*/ 28 | width: 3px; 29 | /*高宽分别对应横竖滚动条的尺寸*/ 30 | height: 1px; 31 | } 32 | body 33 | // 主容器 34 | .lite-chatmaster 35 | .lite-chatbox 36 | .lite-chattools 37 | #emojiMart.lite-chatbox-tool(style="display:none") 38 | #toolMusk(style="display:none") 39 | .lite-chatinput 40 | hr.boundary 41 | button#emojiBtn.tool-button.float-left(title="表情" type="button") 42 | svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24") 43 | path(d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10") 44 | path(d="M8 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 8 7M16 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 16 7M15.232 15c-.693 1.195-1.87 2-3.349 2-1.477 0-2.655-.805-3.347-2H15m3-2H6a6 6 0 1 0 12 0") 45 | button#imageBtn.tool-button.float-left(title="插入图片" type="button") 46 | svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512") 47 | // Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 48 | path(d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 336H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v276a6 6 0 0 1-6 6zM128 152c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zM96 352h320v-80l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L192 304l-39.515-39.515c-4.686-4.686-12.284-4.686-16.971 0L96 304v48z") 49 | button#fileBtn.tool-button.float-left(title="发送文件" type="button") 50 | svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512") 51 | // Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 52 | path(d="M527.9 224H480v-48c0-26.5-21.5-48-48-48H272l-64-64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h400c16.5 0 31.9-8.5 40.7-22.6l79.9-128c20-31.9-3-73.4-40.7-73.4zM48 118c0-3.3 2.7-6 6-6h134.1l64 64H426c3.3 0 6 2.7 6 6v42H152c-16.8 0-32.4 8.8-41.1 23.2L48 351.4zm400 282H72l77.2-128H528z") 53 | button#editFullScreen.tool-button.float-right(title="全屏编辑" type="button") 54 | svg(svg, xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024") 55 | path(d="M17.066667 2.844444C11.377778 2.844444 8.533333 5.688889 5.688889 8.533333 2.844444 11.377778 0 14.222222 0 19.911111v364.088889c0 2.844444 0 5.688889 2.844444 5.688889h5.688889l122.311111-122.311111 164.977778 164.977778c2.844444 2.844444 8.533333 5.688889 11.377778 5.688888 5.688889 0 8.533333-2.844444 11.377778-5.688888l110.933333-110.933334c2.844444-2.844444 5.688889-8.533333 5.688889-11.377778 0-5.688889-2.844444-8.533333-5.688889-11.377777l-159.288889-170.666667L389.688889 8.533333c2.844444-2.844444 2.844444-2.844444 0-5.688889 0-2.844444-2.844444-2.844444-2.844445-2.844444L17.066667 2.844444zM17.066667 1024c-5.688889 0-8.533333-2.844444-11.377778-5.688889-2.844444-2.844444-5.688889-8.533333-5.688889-11.377778V640c0-2.844444 0-5.688889 2.844444-5.688889h5.688889l122.311111 122.311111 164.977778-164.977778c2.844444-2.844444 8.533333-5.688889 11.377778-5.688888 5.688889 0 8.533333 2.844444 11.377778 5.688888l110.933333 110.933334c2.844444 2.844444 5.688889 8.533333 5.688889 11.377778s-2.844444 8.533333-5.688889 11.377777l-164.977778 164.977778 119.466667 119.466667c2.844444 2.844444 2.844444 2.844444 0 5.688889 0 2.844444-2.844444 2.844444-5.688889 2.844444L17.066667 1024zM1006.933333 2.844444c5.688889 0 8.533333 2.844444 11.377778 5.688889 2.844444 2.844444 5.688889 5.688889 5.688889 11.377778v364.088889c0 2.844444 0 5.688889-2.844444 5.688889h-5.688889l-122.311111-122.311111-164.977778 164.977778c-2.844444 2.844444-8.533333 5.688889-11.377778 5.688888-5.688889 0-8.533333-2.844444-11.377778-5.688888l-110.933333-110.933334c-2.844444-2.844444-5.688889-8.533333-5.688889-11.377778 0-5.688889 2.844444-8.533333 5.688889-11.377777l164.977778-164.977778L640 14.222222c-2.844444-2.844444-2.844444-2.844444 0-5.688889-5.688889-8.533333-2.844444-8.533333-2.844444-8.533333l369.777777 2.844444z m0 1021.155556c5.688889 0 8.533333-2.844444 11.377778-5.688889 2.844444-2.844444 5.688889-8.533333 5.688889-11.377778V640c0-2.844444 0-5.688889-2.844444-5.688889h-5.688889l-122.311111 122.311111-164.977778-164.977778c-2.844444-2.844444-8.533333-5.688889-11.377778-5.688888-5.688889 0-8.533333 2.844444-11.377778 5.688888l-110.933333 110.933334c-2.844444 2.844444-5.688889 8.533333-5.688889 11.377778s2.844444 8.533333 5.688889 11.377777l164.977778 164.977778-119.466667 119.466667c-2.844444 2.844444-2.844444 2.844444 0 5.688889 0 2.844444 2.844444 2.844444 5.688889 2.844444l361.244444 5.688889z") 56 | button#exitFullScreen.tool-button.float-right(style="display:none" title="退出" type="button") 57 | svg(svg, xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024") 58 | path(d="M422.648199 431.157895c5.67313 0 8.509695-2.836565 11.346261-5.67313 2.836565-2.836565 5.67313-8.509695 5.67313-11.346261V51.058172c0-2.836565 0-5.67313-2.836565-5.67313h-5.67313L306.34903 170.193906 141.828255 5.67313C138.99169 2.836565 133.31856 0 130.481994 0c-5.67313 0-11.34626 2.836565-14.182825 5.67313L5.67313 116.299169c-2.836565 2.836565-5.67313 8.509695-5.67313 11.34626 0 5.67313 2.836565 11.34626 5.67313 14.182826L170.193906 303.512465l-119.135734 119.135734c-2.836565 2.836565-2.836565 2.836565 0 5.673131 0 2.836565 2.836565 2.836565 5.67313 2.836565h365.916897z m0 156.01108c5.67313 0 8.509695 2.836565 11.346261 5.67313 2.836565 2.836565 5.67313 8.509695 5.67313 11.346261v365.916897c0 2.836565 0 5.67313-2.836565 5.67313h-5.67313L306.34903 850.969529 141.828255 1015.490305c-2.836565 2.836565-8.509695 5.67313-11.346261 5.67313-5.67313 0-8.509695-2.836565-11.34626-5.67313L8.509695 904.864266c-5.67313-2.836565-8.509695-8.509695-8.509695-11.34626s2.836565-8.509695 5.67313-11.346261L170.193906 717.65097l-119.135734-119.135735c-2.836565-2.836565-2.836565-2.836565 0-5.67313 0-2.836565 2.836565-2.836565 5.67313-2.836565l365.916897-2.836565z m175.867036-156.01108c-5.67313 0-8.509695-2.836565-11.34626-5.67313-2.836565-2.836565-5.67313-8.509695-5.67313-11.346261V51.058172c0-2.836565 0-5.67313 2.836565-5.67313h5.67313L714.814404 170.193906 879.33518 5.67313c2.836565-2.836565 8.509695-5.67313 11.34626-5.67313 5.67313 0 8.509695 2.836565 11.346261 5.67313l110.626039 110.626039c5.67313 2.836565 8.509695 8.509695 8.509695 11.34626 0 5.67313-2.836565 8.509695-5.67313 11.346261L850.969529 303.512465l119.135734 119.135734c2.836565 2.836565 2.836565 2.836565 0 5.673131 0 2.836565-2.836565 2.836565-5.67313 2.836565H598.515235z m0 156.01108c-5.67313 0-8.509695 2.836565-11.34626 5.67313-2.836565 2.836565-5.67313 8.509695-5.67313 11.346261v365.916897c0 2.836565 0 5.67313 2.836565 5.67313h5.67313l121.972299-121.972299 164.520776 164.520776c2.836565 2.836565 8.509695 5.67313 11.34626 5.67313 5.67313 0 8.509695-2.836565 11.346261-5.67313l110.626039-110.626039c2.836565-2.836565 5.67313-8.509695 5.67313-11.34626s-2.836565-8.509695-5.67313-11.346261L850.969529 717.65097l119.135734-119.135735c2.836565-2.836565 2.836565-2.836565 0-5.67313 0-2.836565-2.836565-2.836565-5.67313-2.836565l-365.916898-2.836565z") 59 | .editor.chatinput(aria-label="input area" contenteditable="true" ref="editor") 60 | button.send 发送 61 | // Emoji Mart 62 | script(src="https://cdn.jsdelivr.net/npm/emoji-mart@latest/dist/browser.js") 63 | script(src="../js/litewebchat_input.min.js") 64 | // 抽离的聊天信息组件 65 | script(src="../js/litewebchat_render.min.js") 66 | script. 67 | const htmls = [{ 68 | messageType: 'tipsDanger', 69 | html: '从我做过的类聊天需求来看,聊天消息要么是纯文本,要么是富文本。text 类型是纯文本, raw 类型是富文本。' 70 | }, { 71 | messageType: 'text', 72 | headIcon: '../images/A.jpg', 73 | name: 'chenjunyu19', 74 | position: 'left', 75 | html: '这是什么什么鬼?' 76 | }, { 77 | messageType: 'raw', 78 | headIcon: '../images/B.jpg', 79 | name: 'SuperPaxxs', 80 | position: 'right', 81 | html: 'LiteChat_Frame(轻聊天气泡框架),一个贼简洁 (简单) 、美观、易用的 HTML 聊天界面框架', 82 | }, { 83 | messageType: 'text', 84 | headIcon: '../images/B.jpg', 85 | name: 'SuperPaxxs', 86 | position: 'right', 87 | html: '它简洁而不简单,能使你开发聊天界面更快速' 88 | }, { 89 | messageType: 'text', 90 | headIcon: '../images/A.jpg', 91 | name: 'chenjunyu19', 92 | position: 'left', 93 | html: '直接说,气泡是谁的?' 94 | }, { 95 | messageType: 'text', 96 | headIcon: '../images/B.jpg', 97 | name: 'SuperPaxxs', 98 | position: 'right', 99 | htitleType: 'admin', 100 | htitle: 'admin', 101 | html: '好吧,气泡css来自 Haswikr的 Blog 的机器人气泡 😝', 102 | }, { 103 | messageType: 'text', 104 | headIcon: '../images/H.jpg', 105 | name: 'Haswikr', 106 | position: 'left', 107 | htitleType: 'admin', 108 | htitle: 'admin', 109 | html: '当初调色煞费苦心' 110 | }, { 111 | messageType: 'text', 112 | headIcon: '../images/O.jpg', 113 | name: 'Sonui', 114 | position: 'left', 115 | htitleType: 'owner', 116 | htitle: 'owner', 117 | html: '这设计真棒' 118 | }, { 119 | messageType: 'text', 120 | headIcon: '../images/A.jpg', 121 | name: 'chenjunyu19', 122 | position: 'left', 123 | htitle: 'menber123456789789', 124 | html: '那咋用啊?' 125 | }, { 126 | messageType: 'raw', 127 | headIcon: '../images/B.jpg', 128 | name: 'SuperPaxxs', 129 | position: 'right', 130 | html: `诶哟少年你找对人了

如果只是使用,那非常简单。

使用指北


1. 引用 css: litechat.css

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.css" rel="stylesheet" />

<link type="text/css" href="//lab.morfans.cn/LiteWebChat_Frame/litewebchat.min.css" rel="stylesheet" />

2. 创建一个 DIV ,用来容纳聊天对话,目的是不让 css 干扰页面其他内容:

<div class="lite-chatbox">
...
</div>

话说你就不会看下源码吗...楼下是特性演示` 131 | }, { 132 | messageType: 'tipsNormal', 133 | html: 'Chenjunyu19 退出了聊天室并撩了你一把' 134 | }, { 135 | messageType: 'text', 136 | headIcon: '../images/A.jpg', 137 | name: '空消息测试1', 138 | position: 'left', 139 | html: '' 140 | }, { 141 | messageType: 'raw', 142 | headIcon: '../images/B.jpg', 143 | name: '空消息测试2', 144 | position: 'right', 145 | html: ' ' 146 | }, { 147 | messageType: 'text', 148 | headIcon: '../images/A.jpg', 149 | name: 'chenjunyu19', 150 | position: 'left', 151 | html: '注意,上面两条空消息的消息内容代码不一样?' 152 | }, { 153 | messageType: 'text', 154 | headIcon: '../images/B.jpg', 155 | name: 'SuperPaxxs', 156 | position: 'right', 157 | html: '头像换成方形请去掉 radius ;我认为应该不会有方形的。so....自己动手丰衣足食吧(F12)' 158 | }, { 159 | messageType: 'text', 160 | headIcon: '../images/A.jpg', 161 | name: 'chenjunyu19', 162 | position: 'left', 163 | diamond: true, 164 | html: '我是左边的方形头像' 165 | }, { 166 | messageType: 'raw', 167 | headIcon: '../images/B.jpg', 168 | name: '图片消息', 169 | position: 'right', 170 | html: '', 171 | }, { 172 | messageType: 'raw', 173 | headIcon: '../images/A.jpg', 174 | name: '图片消息2', 175 | position: 'left', 176 | html: `
图片带文字是可以的 (废话)`, 177 | }, { 178 | messageType: 'text', 179 | headIcon: '../images/B.jpg', 180 | name: '右边长消息', 181 | position: 'right', 182 | html: '我的消息真的超级长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长欸' 183 | }, { 184 | messageType: 'text', 185 | headIcon: '../images/A.jpg', 186 | name: '左边长消息', 187 | position: 'left', 188 | html: '这么巧鸭,我的也超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超超级长的欸\n' 189 | }, { 190 | messageType: 'tipsDanger', 191 | html: '系统消息:左/右边长消息被管理员批判一番……' 192 | }, { 193 | messageType: 'tipsNormal', 194 | html: '系统消息:normal' 195 | }, { 196 | messageType: 'tipsPrimary', 197 | html: '系统消息:primary' 198 | }, { 199 | messageType: 'tipsSuccess', 200 | html: '系统消息:success' 201 | }, { 202 | messageType: 'tipsInfo', 203 | html: '系统消息:info' 204 | }, { 205 | messageType: 'tipsWarning', 206 | html: '系统消息:warning' 207 | }, { 208 | messageType: 'tipsDanger', 209 | html: '系统消息:danger' 210 | }, { 211 | messageType: 'raw', 212 | headIcon: '../images/B.jpg', 213 | name: '带有超链接的消息测试', 214 | position: 'right', 215 | html: `当然是可以有超链接的。例子在这里:
你敢点我吗 ← 戳这里`, 216 | }, { 217 | messageType: 'text', 218 | headIcon: '../images/A.jpg', 219 | name: '全符号测试', 220 | position: 'left', 221 | html: '。,;?:!‘’“”@ˆ.,;?:!\'"〝〞﹫ˇ' 222 | }, { 223 | messageType: 'text', 224 | headIcon: '../images/A.jpg', 225 | name: '全emoji测试', 226 | position: 'left', 227 | html: `😀😝🐂🍺` 228 | }, { 229 | messageType: 'text', 230 | headIcon: '../images/B.jpg', 231 | name: '', 232 | position: 'right', 233 | html: `当无昵时候, name 字段留空即可` 234 | }, { 235 | messageType: 'text', 236 | headIcon: '../images/B.jpg', 237 | name: 'SuperPaxxs', 238 | position: 'right', 239 | html: `换行用可以用
240 | 也可以直接换..` 241 | }, { 242 | messageType: 'text', 243 | headIcon: '../images/A.jpg', 244 | name: 'chenjunyu19', 245 | position: 'left', 246 | html: `以上就是全部的特性,以后有空再更` 247 | },{ 248 | messageType: 'raw', 249 | htitleType: 'owner', 250 | htitle: 'NEW', 251 | headIcon: '../images/B.jpg', 252 | name: 'SuperPaxxs', 253 | position: 'right', 254 | html: 'LiteChat_Frame 拥有暗色模式,快来试试吧: