优化meditor
parent
4ddffd2585
commit
2457e14a86
|
@ -60,7 +60,8 @@
|
|||
min-width: 200px;
|
||||
min-height: 100px;
|
||||
// max-height: 360px;
|
||||
border-radius: 2px;
|
||||
border-radius: 3px;
|
||||
transition: box-shadow 0.15s linear;
|
||||
}
|
||||
|
||||
.meditor {
|
||||
|
@ -135,6 +136,7 @@
|
|||
background: none;
|
||||
outline: none;
|
||||
resize: none;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.preview {
|
||||
|
@ -336,6 +338,10 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:host(:focus-within) {
|
||||
box-shadow: 0 0 0 2px var(--color-plain-a);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
@ -360,6 +366,10 @@ export default class Meditor {
|
|||
preview: window.innerWidth > 768
|
||||
}
|
||||
|
||||
state = {
|
||||
toolbar: []
|
||||
}
|
||||
|
||||
__init__() {
|
||||
/* render */
|
||||
|
||||
|
@ -625,27 +635,24 @@ export default class Meditor {
|
|||
)
|
||||
}
|
||||
|
||||
// 往文本框中插入内容
|
||||
insert(val, isSelect) {
|
||||
/**
|
||||
* 往文本框中插入内容
|
||||
* @param {String} val [要插入的文本]
|
||||
* @param {Boolean} isSelect [插入之后是否要选中文本]
|
||||
* @param {Boolean} offset [选中文本时的偏移量]
|
||||
*/
|
||||
insert(val = '', isSelect = false, offset = 0) {
|
||||
var dom = this.__EDITOR__
|
||||
if (document.selection) {
|
||||
dom.focus()
|
||||
let range = document.selection.createRange()
|
||||
range.text = val
|
||||
dom.focus()
|
||||
range.moveStart('character', -1)
|
||||
} else if (dom.selectionStart || dom.selectionStart === 0) {
|
||||
let startPos = dom.selectionStart
|
||||
let endPos = dom.selectionEnd
|
||||
let scrollTop = dom.scrollTop
|
||||
var start = dom.selectionStart
|
||||
var end = dom.selectionEnd
|
||||
var scrollTop = dom.scrollTop
|
||||
|
||||
if (start || start === 0) {
|
||||
dom.value =
|
||||
dom.value.slice(0, startPos) +
|
||||
val +
|
||||
dom.value.slice(endPos, dom.value.length)
|
||||
dom.value.slice(0, start) + val + dom.value.slice(end, dom.value.length)
|
||||
|
||||
dom.selectionStart = isSelect ? startPos : startPos + val.length
|
||||
dom.selectionEnd = startPos + val.length
|
||||
dom.selectionStart = (isSelect ? start : start + val.length) + offset
|
||||
dom.selectionEnd = start + val.length - offset
|
||||
dom.scrollTop = scrollTop
|
||||
dom.focus()
|
||||
} else {
|
||||
|
@ -659,39 +666,70 @@ export default class Meditor {
|
|||
* @param {[type]} dom [要操作的元素]
|
||||
* @param {[type]} forceHoleLine [是否强制光标所在的整行文本]
|
||||
*/
|
||||
selection(forceHoleLine) {
|
||||
selection(forceHoleLine = false) {
|
||||
var dom = this.__EDITOR__
|
||||
if (document.selection) {
|
||||
return document.selection.createRange().text
|
||||
} else {
|
||||
let startPos = dom.selectionStart
|
||||
let endPos = dom.selectionEnd
|
||||
var start = dom.selectionStart
|
||||
var end = dom.selectionEnd
|
||||
|
||||
if (endPos) {
|
||||
if (end) {
|
||||
//强制选择整行
|
||||
if (forceHoleLine) {
|
||||
startPos = dom.value.slice(0, startPos).lastIndexOf('\n')
|
||||
start = dom.value.slice(0, start).lastIndexOf('\n')
|
||||
|
||||
let tmpEnd = dom.value.slice(endPos).indexOf('\n')
|
||||
tmpEnd = tmpEnd < 0 ? dom.value.slice(endPos).length : tmpEnd
|
||||
let tmpEnd = dom.value.slice(end).indexOf('\n')
|
||||
tmpEnd = tmpEnd < 0 ? dom.value.slice(end).length : tmpEnd
|
||||
|
||||
startPos += 1 // 把\n加上
|
||||
endPos += tmpEnd
|
||||
start += 1 // 把\n加上
|
||||
end += tmpEnd
|
||||
|
||||
dom.selectionStart = startPos
|
||||
dom.selectionEnd = endPos
|
||||
dom.selectionStart = start
|
||||
dom.selectionEnd = end
|
||||
}
|
||||
} else {
|
||||
//强制选择整行
|
||||
if (forceHoleLine) {
|
||||
endPos = dom.value.indexOf('\n')
|
||||
endPos = endPos < 0 ? dom.value.length : endPos
|
||||
dom.selectionEnd = endPos
|
||||
end = dom.value.indexOf('\n')
|
||||
end = end < 0 ? dom.value.length : end
|
||||
dom.selectionEnd = end
|
||||
}
|
||||
}
|
||||
dom.focus()
|
||||
return dom.value.slice(startPos, endPos)
|
||||
return dom.value.slice(start, end)
|
||||
}
|
||||
|
||||
select(start = 0, end = 0) {
|
||||
var dom = this.__EDITOR__
|
||||
dom.selectionStart = start
|
||||
dom.selectionEnd = end
|
||||
}
|
||||
|
||||
cursor(step) {
|
||||
var pos = this.__EDITOR__.selectionStart || 0
|
||||
pos += step
|
||||
|
||||
if (step === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
pos = 0
|
||||
}
|
||||
this.select(pos, pos)
|
||||
}
|
||||
|
||||
_getCursorText(n) {
|
||||
var dom = this.__EDITOR__
|
||||
var start = dom.selectionStart
|
||||
var end = dom.selectionEnd
|
||||
var pos = end
|
||||
|
||||
if (n < 0) {
|
||||
pos = start - 1
|
||||
if (pos < 0) {
|
||||
pos = 0
|
||||
}
|
||||
}
|
||||
return this.value[pos] || ''
|
||||
}
|
||||
|
||||
get value() {
|
||||
|
@ -701,7 +739,28 @@ export default class Meditor {
|
|||
set value(val) {
|
||||
this.__EDITOR__.value = val
|
||||
if (this.props.preview) {
|
||||
this.__VIEW__.textContent = val
|
||||
this.__VIEW__.value = val
|
||||
}
|
||||
}
|
||||
|
||||
get disabled() {
|
||||
return this.props.disabled
|
||||
}
|
||||
|
||||
set disabled(val) {
|
||||
var type = typeof val
|
||||
|
||||
if (val === this.props.disabled) {
|
||||
return
|
||||
}
|
||||
if ((type === 'boolean' && val) || type !== 'boolean') {
|
||||
this.props.disabled = true
|
||||
this.__EDITOR__.disabled = true
|
||||
this.setAttribute('disabled', '')
|
||||
} else {
|
||||
this.props.disabled = false
|
||||
this.__EDITOR__.disabled = false
|
||||
this.removeAttribute('disabled')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -717,7 +776,7 @@ export default class Meditor {
|
|||
if (this.props.preview) {
|
||||
var txt = this.__EDITOR__.value.trim()
|
||||
if (txt) {
|
||||
this.__VIEW__.textContent = txt
|
||||
this.__VIEW__.value = txt
|
||||
} else {
|
||||
this.__VIEW__.clear()
|
||||
}
|
||||
|
@ -727,8 +786,10 @@ export default class Meditor {
|
|||
$.bind(this.__EDITOR__, 'keydown', ev => {
|
||||
let wrap = this.selection() || ''
|
||||
let select = !!wrap
|
||||
|
||||
switch (ev.keyCode) {
|
||||
//tab键改为插入2个空格,阻止默认事件,防止焦点失去
|
||||
if (ev.keyCode === 9) {
|
||||
case 9:
|
||||
ev.preventDefault()
|
||||
wrap = wrap
|
||||
.split('\n')
|
||||
|
@ -737,14 +798,77 @@ export default class Meditor {
|
|||
})
|
||||
.join('\n')
|
||||
this.insert(wrap, select)
|
||||
}
|
||||
break
|
||||
|
||||
//修复按退格键删除选中文本时,选中的状态不更新的bug
|
||||
if (ev.keyCode === 8) {
|
||||
if (select) {
|
||||
ev.preventDefault()
|
||||
this.insert('', select)
|
||||
case 8:
|
||||
if (!select) {
|
||||
let pos = this.__EDITOR__.selectionStart
|
||||
let prev = this._getCursorText(-1)
|
||||
let next = this._getCursorText(1)
|
||||
|
||||
if (
|
||||
(prev === next && (prev === '"' || prev === "'")) ||
|
||||
(prev === '[' && next === ']') ||
|
||||
(prev === '{' && next === '}') ||
|
||||
(prev === '(' && next === ')')
|
||||
) {
|
||||
this.select(pos - 1, pos + 1)
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
// (
|
||||
case 57:
|
||||
if (ev.shiftKey) {
|
||||
ev.preventDefault()
|
||||
|
||||
this.insert('(' + wrap + ')', select, (select && 1) || 0)
|
||||
this.cursor(select ? 0 : -1)
|
||||
}
|
||||
break
|
||||
|
||||
case 219: // [ & {
|
||||
ev.preventDefault()
|
||||
this.insert(
|
||||
ev.shiftKey ? `{${wrap}}` : `[${wrap}]`,
|
||||
select,
|
||||
(select && 1) || 0
|
||||
)
|
||||
this.cursor(select ? 0 : -1)
|
||||
|
||||
break
|
||||
|
||||
// ' & "
|
||||
case 222:
|
||||
{
|
||||
ev.preventDefault()
|
||||
let val = "'"
|
||||
let prev = this._getCursorText(-1)
|
||||
let next = this._getCursorText(1)
|
||||
|
||||
if (select) {
|
||||
this.insert(val + wrap + val, true, 1)
|
||||
} else {
|
||||
if (ev.shiftKey) {
|
||||
val = '"'
|
||||
}
|
||||
if (prev === next && prev === val) {
|
||||
this.cursor(1)
|
||||
} else {
|
||||
if (prev === val || next === val) {
|
||||
this.insert(val)
|
||||
} else {
|
||||
this.insert(val.repeat(2))
|
||||
this.cursor(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
$.bind(this.__EDITOR__, 'paste', ev => {
|
||||
|
@ -807,13 +931,21 @@ export default class Meditor {
|
|||
this.value = val
|
||||
break
|
||||
|
||||
case 'preview':
|
||||
if (val === 'false') {
|
||||
this.props.preview = false
|
||||
} else {
|
||||
this.props.preview = window.innerWidth > 768
|
||||
}
|
||||
break
|
||||
|
||||
case 'readonly':
|
||||
case 'disabled':
|
||||
var k = name
|
||||
if (k === 'readonly') {
|
||||
k = 'readOnly'
|
||||
}
|
||||
this[k] = true
|
||||
this[k] = val !== null
|
||||
break
|
||||
|
||||
default:
|
||||
|
|
Reference in New Issue