Jon*_*nny 6 html javascript css editor toggle
我有一个切换按钮,可以改变一些文本.我遇到的问题是,如果我有2个单词,并且我想要更改一个单词的文本,但是当我切换它时,样式将从两个跨度而不是所选文本的跨度中删除.
如何从选定的特定文本中删除范围并将范围保留在其他文本上?
function headuppercase(e) {
tags('span', 'sC');
}
function tags(tag, clas) {
var ele = document.createElement(tag);
ele.classList.add(clas);
wrap(ele);
}
function wrap(tags) {
var el = document.querySelector('span.sC');
sel = window.getSelection();
if (!el) {
if (sel.rangeCount && sel.getRangeAt) {
range = sel.getRangeAt(0);
}
document.designMode = "on";
if (range) {
sel.removeAllRanges();
sel.addRange(range);
}
range.surroundContents(tags);
} else {
var parent = el.parentNode;
while (el.firstChild) parent.insertBefore(el.firstChild, el);
parent.removeChild(el);
}
document.designMode = "off";
}Run Code Online (Sandbox Code Playgroud)
.ourbutton {
padding: 5px;
float: left;
font-variant: small-caps;
}
.container {
width: 200px;
height: 300px;
float: left;
}
.spanA {
width: 100px;
height: 80px;
max-width: 200px;
max-height: 300px;
float: left;
border: thin blue solid;
}
.sC {
font-variant: small-caps;
}Run Code Online (Sandbox Code Playgroud)
<button class="ourbutton" type="button" onclick="headuppercase();">Tt</button>
<div class="container">
<span class="spanA" contenteditable="true"></span>
</div>Run Code Online (Sandbox Code Playgroud)
请不要jQuery.谢谢!
如果没有库,这并不容易实现,因为您需要处理所有边缘情况。我将首先讨论一些边缘情况,然后给您一个关于如何实现它们的示例。
假设我们在文本节点中有以下字符串
“没有人想要太复杂的代码,因为它变得难以管理。”
考虑一个用户选择了“没人想要”一词并按下切换小型大写字母按钮。您最终应该得到如下所示的结果(其中粗体部分代表小型大写字母的文本):
“没有人想要太复杂的代码,因为它变得难以管理。”
这是一个简单的案例。只需将“ Nobody Want ”段包装在 a 中<span>并给它sC上课即可。对于尚未成为小盘股的所有其他细分市场也是如此。这里没什么太难的。
但是假设您处于以下状态(同样,粗体段代表小型大写字母的文本):
“没有人想要太复杂的代码,因为它变得难以管理。 ”
当用户选择并切换“变成”这个词时,事情就变得复杂了。你必须:
<span class="sC">从其包含元素中删除最后两个单词<span>具有 className 的a 中sC。<span class="sC">或者说您处于以下状态(同样,粗体段代表小型大写字母的文本):
“没有人想要太复杂的代码,因为它变得难以管理。 ”
当有人选择并切换该段“因为需要太复杂的代码”时会发生什么?有人可能会说:让这个片段中的每个角色
很容易看出您将再次需要大量拆分现有的跨度元素、创建新的文本节点等等。
假设您从嵌套列表开始
- A
- 乙
- C
- D
用户同时选择最后两项。然后您需要将每个项目单独包装到一个跨度中。
虽然您的问题尚不清楚应如何处理所有边缘情况,但这是解决方案的第一步。
const allCapsClass = 'sC'
function toggleCase() {
const selection = window.getSelection()
if (selection && selection.rangeCount>0) {
const spans = wrapInNonNestedSpanners(selection.getRangeAt(0))
for (const span of spans) {
const classes = span.classList
const action = classes.contains(allCapsClass) ? 'remove' : 'add'
classes[action](allCapsClass)
}
}
}
const spannerClassName = "non-nested-spanner"
const spannerQuerySelector = `.${spannerClassName}`
function wrapInNonNestedSpanners(range) {
const containingSpanner = getContainingSpanner(range)
const result = []
if (containingSpanner != null) { // Edge case 1
const endRange = document.createRange() // contents of the span after range
endRange.selectNode(containingSpanner)
endRange.setStart(range.endContainer, range.endOffset)
const endContents = endRange.cloneContents()
const wrappedSelectionContents = containingSpanner.cloneNode(false)
wrappedSelectionContents.appendChild(range.cloneContents())
endRange.deleteContents()
range.deleteContents()
const parent = containingSpanner.parentNode
const next = containingSpanner.nextSibling
parent.insertBefore(wrappedSelectionContents, next)
result.push(wrappedSelectionContents)
if (!isEmptySpanner(endContents.childNodes[0])) parent.insertBefore(endContents, next)
if (isEmptySpanner(containingSpanner)) parent.removeChild(containingSpanner)
const newSelection = document.createRange()
newSelection.selectNode(wrappedSelectionContents)
window.getSelection().removeAllRanges()
window.getSelection().addRange(newSelection)
} else { // Edge case 2
const contents = range.extractContents()
const spanners = contents.querySelectorAll(spannerQuerySelector)
let endRange = document.createRange() // range before the span
for (let index = spanners.length-1; index>=0; index--) {
const spanner = spanners[index]
endRange.selectNodeContents(contents)
endRange.setStartAfter(spanner)
if (!endRange.collapsed) {
const wrappedEndContents = createSpannerWrapping(endRange.extractContents())
range.insertNode(wrappedEndContents)
result.unshift(wrappedEndContents)
}
range.insertNode(spanner)
result.unshift(spanner)
}
const rest = createSpannerWrapping(contents)
if (!isEmptySpanner(rest)) {
range.insertNode(rest)
result.unshift(rest)
}
}
return result
}
function getContainingSpanner(range) {
let cursor = range.commonAncestorContainer
if (cursor.classList == undefined) cursor = cursor.parentElement
while (cursor.parentElement != null) {
if (cursor.classList.contains(spannerClassName)) return cursor
cursor = cursor.parentElement
}
return null
}
function createSpannerWrapping(childNode) {
const spanner = document.createElement('span')
spanner.classList.add(spannerClassName)
spanner.appendChild(childNode)
return spanner
}
function isEmptySpanner(spanner) {
if (spanner.childNodes.length == 0) return true
else if (spanner.childNodes.length == 1) {
const node = spanner.childNodes[0]
return node instanceof Text && node.length == 0
}
return false
}Run Code Online (Sandbox Code Playgroud)
.sC {
font-variant: small-caps;
}Run Code Online (Sandbox Code Playgroud)
<section contenteditable>
Hello world this is some text
</section>
<button onclick="toggleCase()">Toggle case</button>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
303 次 |
| 最近记录: |