Editor 過濾內容 - daniel-qa/Vue GitHub Wiki

過濾主要分三層:

貼上事件 pasteEvent
   ↓
normalizeSpacing(主要清洗)
   ↓
normalizeSafariSpaceSpans(空白修正)
   ↓
regex replace(Word / Office 污染清理)

👉 核心目標就三個:

1 .移除 Word / Office 垃圾 HTML

2 .修正空白(特別是 Safari + Word)

3 .保留乾淨結構 + 圖片



  • Apple-converted-space: (針對 apple 的處理)

Apple-converted-space 的由來

通常發生在從 Safari 瀏覽器、備忘錄 (Notes) 或 Pages 拷貝帶有格式的文字,再貼到網頁編輯器時。系統為了確保「你在 Apple 軟體上看到的間距」在 HTML 網頁上也能一模一樣,會自動把多餘的空格封裝成這個 class。

  • dom 寫法(現代)
function sanitizeHTML(html) {
  const doc = new DOMParser().parseFromString(html, 'text/html')

  // 1. 移除垃圾 tag
  doc.querySelectorAll('style, o\\:p, v\\:shape, v\\:imagedata')
    .forEach(el => el.remove())

  // 2. 清理 Safari 空白
  doc.querySelectorAll('span').forEach(el => {
    if (
      el.classList.contains('Apple-converted-space') ||
      /^\s+$/.test(el.textContent)
    ) {
      el.replaceWith(document.createTextNode(el.textContent))
    }
  })

  return doc.body.innerHTML
}

① 解析 HTML → 變成 DOM

const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')

💡 重點

👉 把這種字串:

👉 變成真正 DOM:

HTML → DOM Tree 🧠 為什麼這一步很重要?

因為你後面可以:

用 querySelectorAll 用 classList 不用 regex 猜結構

👉 這就是「現代寫法的核心優勢」

② 找出所有 span

doc.querySelectorAll('span')

👉 把所有 <span> 抓出來

🧠 為什麼不是直接抓 .Apple-converted-space?

因為你這段還多做了一件事:

/^\s+$/.test(el.textContent)

👉 👉 👉 這才是關鍵!

③ 判斷是不是「假空白」

const isAppleSpace =
  el.classList.contains('Apple-converted-space') ||
  /^\s+$/.test(el.textContent)

  • regex 寫法(舊)
/* 粘贴文本的解析和轻量化操作 */
normalizeSafariSpaceSpans(htmlString) {
	return htmlString.replace(/<span(?: class="Apple-converted-space"|)>(\s+)<\/span>/g, (fullMatch, spaces) => {
		return spaces.length === 1 ? ' ' : Array(spaces.length + 1).join('\u00A0 ').substr(0, spaces
			.length);
	});
},
⚠️ **GitHub.com Fallback** ⚠️