Skip to content

Commit a582348

Browse files
committed
revert(textarea): contenteditable 存在 bug 所以回滚到以前的评论框
1 parent db309a2 commit a582348

File tree

1 file changed

+75
-76
lines changed

1 file changed

+75
-76
lines changed

src/client/view/submit.svelte

Lines changed: 75 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
2-
import { onMount, afterUpdate, createEventDispatcher } from 'svelte'
2+
import { onMount, afterUpdate, createEventDispatcher, tick } from 'svelte'
33
import { options, msg, lazy } from '../lib/stores'
44
import request from '../lib/request'
55
import emotFn from '../lib/emot'
@@ -46,6 +46,8 @@
4646
let emotIndex = 0
4747
let emotMaps = {}
4848
let emotAll = {}
49+
let textareaDOM
50+
let isPreview = false
4951
let isSend = false
5052
let isLegal = false
5153
const inputs = [
@@ -71,22 +73,23 @@
7173
site: { value: '', is: true },
7274
content: { value: '', is: false }
7375
}
74-
76+
let contentHTML = ''
7577
let wordLimitContent = wordLimit.content
7678
let limitContentLen
7779
$: {
7880
wordLimitContent = wordLimit.content
79-
const dom = new DOMParser().parseFromString(metas.content.value, 'text/html')
81+
const dom = new DOMParser().parseFromString(contentHTML, 'text/html')
8082
limitContentLen = dom.body.textContent.length + dom.body.querySelectorAll('img').length
8183
}
8284
8385
onMount(() => {
8486
initInfo()
8587
getEmot()
88+
onInput()
8689
})
8790
8891
afterUpdate(() => {
89-
MetasChange()
92+
metasChange()
9093
$lazy()
9194
})
9295
@@ -126,81 +129,72 @@
126129
console.log(error)
127130
}
128131
}
132+
function parseEmot() {
133+
let content = metas.content.value
134+
const emots = []
135+
content.replace(/\[(.*?)\]/g, ($0, $1) => {
136+
emots.push($1)
137+
})
138+
139+
for (const emot of emots) {
140+
const link = emotAll[emot]
141+
if (!link) continue
142+
const img = `<img class='D-comment-emot' src='${link}' alt='${emot}'/>`
143+
content = content.replace(`[${emot}]`, img)
144+
}
145+
contentHTML = content
146+
}
129147
130-
function SaveInfo() {
148+
function saveInfo() {
131149
for (const [k, v] of Object.entries(metas)) {
132150
storage[k] = v.value.trim()
133151
}
134152
localStorage.discuss = JSON.stringify(storage)
153+
// 重新解析表情
154+
parseEmot()
135155
}
136156
137-
function onInput() {
138-
SaveInfo()
139-
MetasChange()
157+
function onPreview() {
158+
isPreview = !isPreview
140159
}
141160
142-
let lastEditRange
143-
function getCursor() {
144-
const sel = window.getSelection()
145-
if (sel.rangeCount < 0) {
146-
lastEditRange = document.createRange()
147-
return
148-
}
149-
150-
lastEditRange = sel.getRangeAt(0)
161+
function onInput() {
162+
saveInfo()
163+
metasChange()
151164
}
152-
153165
/**
154166
* @param {String} key 表情名(描述)
155167
* @param {String} value 表情值(内容或地址)
156168
* @param {String} type 表情类型(text or image)
157169
*/
158-
let textareaDOM
159-
// eslint-disable-next-line max-statements
160170
function onClickEmot(key, value, type) {
161-
textareaDOM.focus()
162-
const sel = window.getSelection()
163-
if (lastEditRange) {
164-
// 清除所有光标并添加最后光标编辑的状态
165-
sel.removeAllRanges()
166-
sel.addRange(lastEditRange)
167-
}
171+
const content = metas.content.value
168172
169-
let emojiEl
173+
// 获取输入框光标位置
174+
let cursorStart = textareaDOM.selectionStart
175+
let cursorEnd = textareaDOM.selectionEnd
176+
const Start = content.substring(0, cursorStart)
177+
const Ent = content.substring(cursorEnd)
170178
179+
let range
180+
textareaDOM.focus()
171181
if (type === textStr) {
172-
emojiEl = document.createTextNode(value)
182+
metas.content.value = `${Start}${value}${Ent}`
183+
range = (Start + value).length
173184
} else {
174-
emojiEl = document.createElement('img')
175-
emojiEl.src = emotAll[key]
176-
emojiEl.className = 'D-comment-emot'
177-
emojiEl.alt = key
185+
metas.content.value = `${Start}[${key}]${Ent}`
186+
range = (Start + key).length + 2
178187
}
188+
// 重新保存
189+
saveInfo()
179190
180-
// 不存在光标,则获取光标,并将光标移动至最后
181-
if (!lastEditRange) {
182-
getCursor()
183-
lastEditRange.selectNodeContents(textareaDOM)
184-
lastEditRange.collapse(false)
185-
sel.removeAllRanges()
186-
sel.addRange(lastEditRange)
187-
}
188-
189-
// 如果光标没有重叠,则代表光标选择了一部分内容,需要删除光标再插入表情
190-
if (!lastEditRange.collapsed) lastEditRange.deleteContents()
191-
192-
lastEditRange.insertNode(emojiEl)
193-
194-
// 让光标保持在插入表情的后面, true 表示保持在前面
195-
lastEditRange.collapse(false)
196-
197-
metas.content.value = textareaDOM.innerHTML
198-
// 保存
199-
SaveInfo()
191+
tick().then(() => {
192+
textareaDOM.setSelectionRange(range, range)
193+
})
200194
}
201195
202196
// eslint-disable-next-line max-statements
203-
function MetasChange() {
197+
function metasChange() {
204198
try {
205199
const { nick, mail, site, content } = metas
206200
const { nick: nickWord, mail: mailWord, site: siteWord, content: contentWord } = wordLimit
@@ -224,14 +218,14 @@
224218
}
225219
226220
// 网站
227-
if (siteLen === 0 || siteLen <= siteWord && isUrl(site.value)) {
221+
if (siteLen === 0 || (siteLen <= siteWord && isUrl(site.value))) {
228222
metas.site.is = true
229223
} else if (siteLen !== 0) {
230224
metas.site.is = false
231225
}
232226
233227
// 内容
234-
const dom = new DOMParser().parseFromString(content.value, 'text/html')
228+
const dom = new DOMParser().parseFromString(contentHTML, 'text/html')
235229
const textContent = dom.body.textContent.length
236230
if (contentLen > 1 && textContent <= contentWord) {
237231
metas.content.is = true
@@ -255,7 +249,7 @@
255249
nick: metas.nick.value,
256250
mail: metas.mail.value,
257251
site: metas.site.value,
258-
content: metas.content.value,
252+
content: contentHTML,
259253
path: D.path,
260254
pid,
261255
rid
@@ -278,7 +272,8 @@
278272
279273
dispatch('submitComment', { comment: result.data, pid })
280274
metas.content.value = ''
281-
SaveInfo()
275+
saveInfo()
276+
isPreview = false
282277
}
283278
} catch (error) {
284279
// eslint-disable-next-line no-console
@@ -302,21 +297,14 @@
302297
on:input={onInput}
303298
/>
304299
{/each}
305-
<div
300+
<textarea
306301
name={contentStr}
307302
class="D-input-content {metas.content.is ? '' : 'D-error'}"
303+
bind:value={metas.content.value}
308304
placeholder={D.ph}
309-
on:input={function () {
310-
metas.content.value = this.innerHTML
311-
onInput()
312-
}}
313-
on:click={getCursor}
314-
on:keyup={getCursor}
305+
on:input={onInput}
315306
bind:this={textareaDOM}
316-
bind:innerHTML={metas.content.value}
317-
contenteditable
318307
/>
319-
320308
{#if wordLimitContent}
321309
<span class="D-text-number">
322310
{limitContentLen}
@@ -345,7 +333,11 @@
345333
>
346334
{/if}
347335

348-
<button class="D-send D-btn D-btn-main" on:click={onSend} disabled={isSend || !isLegal}>
336+
<button
337+
on:click={onPreview}
338+
class="D-cancel D-btn D-btn-main {/* 没有内容则禁用预览按钮 */ !metas.content.value.length && 'D-disabled'}"
339+
>{translate('preview')}</button
340+
><button class="D-send D-btn D-btn-main" on:click={onSend} disabled={isSend || !isLegal}>
349341
{#if isSend && isLegal}
350342
<Loading />
351343
{:else}
@@ -354,6 +346,9 @@
354346
</button>
355347
</div>
356348
</div>
349+
{#if isPreview}
350+
<div class="D-preview">{@html contentHTML}</div>
351+
{/if}
357352
{#if isEmot}
358353
<div class="D-emot">
359354
{#each Object.entries(emotMaps) as [emotKey, emotValue], index}
@@ -426,22 +421,15 @@
426421
transition: all 0.5s;
427422
}
428423
429-
.D-input-content:empty::before {
430-
content: attr(placeholder);
431-
color: #666;
432-
}
433424
.D-input-content {
434425
margin: 10px 0 0;
435-
padding: 6px;
436426
resize: vertical;
437427
width: 100%;
438428
min-height: 140px;
439429
max-height: 400px;
440430
outline: none;
441431
font-family: inherit;
442432
transition: none;
443-
overflow-y: auto;
444-
letter-spacing: 1px;
445433
}
446434
447435
.D-text-number {
@@ -572,6 +560,17 @@
572560
background: var(--D-Low-Color);
573561
}
574562
563+
/* preview */
564+
565+
.D-preview {
566+
padding: 10px;
567+
overflow-x: auto;
568+
min-height: 1.375rem /* 22/16 */;
569+
margin: 10px 0;
570+
border: 1px solid #dcdfe6;
571+
border-radius: 4px;
572+
}
573+
575574
@media screen and (max-width: 500px) {
576575
.D-input {
577576
display: flex;

0 commit comments

Comments
 (0)