电竞比分网-中国电竞赛事及体育赛事平台

分享

為什么 ContentEditable 很恐怖

 icecity1306 2014-11-25

英文原文:why-contenteditable-is-terrible

標(biāo)簽: <無(wú)>
55人收藏此文章, 我要收藏 楊維杰 推薦于 3周前 (共 11 段, 翻譯完成于 11-19) (22評(píng))

我第一次坐在Jacob(@fat)桌子對(duì)面時(shí),他直率的問(wèn):“你是怎么寫(xiě)一個(gè)文字編輯器的?”

我在白板上畫(huà)了一個(gè)樹(shù)結(jié)構(gòu),揮舞著手臂,說(shuō)“這個(gè)是如shit一般的編輯界面?!叭缓笪耶?huà)了一列方框,用箭頭指向數(shù)組,更多的揮舞手臂,說(shuō)”這個(gè)是一個(gè)好的編輯界面?!?/p>

Jacob揚(yáng)了一下眉。

這篇文章是我本應(yīng)該那時(shí)說(shuō)的,如果我有一年的時(shí)間去思考的話(huà)。

Ley
Ley
翻譯于 3周前

0人頂

 翻譯的不錯(cuò)哦!

為什么 ContentEditable 這么恐怖: 一個(gè)數(shù)學(xué)上的佐證

ContentEditable 是一種在web瀏覽器上進(jìn)行富文本編輯的本地原生組件. 它是那樣讓人…傷感.

我會(huì)用一些順手拈來(lái)的數(shù)學(xué)方法來(lái)想你證明,目前的ContentEditable的方法是不好的. 這并不是因?yàn)槲矣X(jué)得數(shù)學(xué)是解釋這個(gè)論點(diǎn)的一個(gè)有說(shuō)服力的方式。它實(shí)際上使得這個(gè)論點(diǎn)更加的異類(lèi)話(huà).

但是我真的覺(jué)得文本編輯器導(dǎo)致了太多的模棱兩可, 就像“所見(jiàn)即所得 (WYSIWYG) 是啥意思?”還有 “當(dāng)你選擇了這段文本并敲下了Enter會(huì)發(fā)生什么?”這樣不明確的問(wèn)題。公理化的數(shù)學(xué)是我所知道的能解決模棱兩可的問(wèn)題并對(duì)它們進(jìn)行明確的最佳工具.

LeoXu
LeoXu
翻譯于 2周前

0人頂

 翻譯的不錯(cuò)哦!

那么所見(jiàn)即所得是什么意思呢?一個(gè)好的所見(jiàn)即所得編輯器應(yīng)該滿(mǎn)足下面3個(gè)定理:

    1.DOM內(nèi)容和可視化(Visible)內(nèi)容能夠很好地進(jìn)行映射。
    2.DOM選擇和可視化(Visible)選擇能夠很好地進(jìn)行映射。
    3.所有的可視化編輯都能夠映射到一個(gè)從代數(shù)上來(lái)說(shuō)封閉的和完整的可視化內(nèi)容集合上面。

首先,我會(huì)解釋這3個(gè)定理所表達(dá)的意思,并且一個(gè)好的編輯器為什么要遵守這些規(guī)則。但是我們首先要明白:他們是定理。他們最弱的部分是缺少證明。但是我們假設(shè)他們是沒(méi)問(wèn)題的除非我們能拿出明顯的證據(jù)來(lái)。

其次,我會(huì)證明ContentEditable不滿(mǎn)足這3個(gè)定理。

最后,我會(huì)討論瀏覽器新的特性和庫(kù)是怎樣針對(duì)這些問(wèn)題的,以及我們?cè)鯓釉谄胀ǖ木庉嬈髦刑幚硭麄兊摹?

DOM空間是我們能在HTML中表述的所有網(wǎng)頁(yè)頁(yè)面的集合。所有頁(yè)面都能夠被表示成一個(gè)元素樹(shù),而這些樹(shù)把文本節(jié)點(diǎn)作為葉子。

可視化空間(“所見(jiàn)即所得”)是所有可視化頁(yè)面的集合 —?也就是我們?cè)谄聊簧峡吹降臑g覽器渲染的一個(gè)頁(yè)面。我們常常會(huì)把看起來(lái)一樣的兩個(gè)頁(yè)面的可視化空間認(rèn)為是一樣的。

瀏覽器渲染引擎是一個(gè)把DOM空間映射到可視化空間的一個(gè)映射?!坝成洹笔侵笇?duì)某個(gè)DOM樹(shù) x 進(jìn)行 Render(x)操作產(chǎn)生所有的可視化頁(yè)面。
junker
junker
翻譯于 3周前

0人頂

 翻譯的不錯(cuò)哦!

當(dāng)我們說(shuō)一個(gè)映射在編輯器中表現(xiàn)良好時(shí),我們的意思是這個(gè)映射保留了所有的編輯操作(見(jiàn)注1)。更準(zhǔn)確的說(shuō),如果渲染的定義是明確的話(huà),那么

1
2
3
for all edit operations E, and DOM pages x and y
Render(x) = Render(y) 
implies Render(E(x)) = Render(E(y))

這是一種在“你看到的是什么”之后確定“你得到了什么”的方式。如果兩個(gè)部分看起來(lái)是一樣的,而我們對(duì)它們進(jìn)行了相同的編輯,那么兩種結(jié)果應(yīng)該看起來(lái)是一樣的. (請(qǐng)?jiān)倏纯吹?1 條)

我已經(jīng)很驚奇的看到網(wǎng)絡(luò)上那么多的 “WYSIWYG” 編輯器都打破了這個(gè)規(guī)則. 這聽(tīng)起來(lái)應(yīng)該是一個(gè)理所當(dāng)然的規(guī)則。但是它會(huì)導(dǎo)致你陷入有關(guān)“相同”是什么意思這個(gè)有點(diǎn)怪異的問(wèn)題,而對(duì)這個(gè)問(wèn)題的問(wèn)題的最好探討就是示例了.

LeoXu
LeoXu
翻譯于 2周前

1人頂

 翻譯的不錯(cuò)哦!

行為良好的內(nèi)容

看看下面這個(gè)例句:

1
The hobbit was a very well-to-do hobbit, and his name was Baggins.

編輯器里面呈現(xiàn)這句話(huà),大致上如下所示.

1
The <a href=”http://en./wiki/The_Hobbit">hobbit</a> was a very well-to-do hobbit, and his name was <strong><em>Baggins</em></strong>.

有許多許多的方式可以用來(lái)對(duì)最后一個(gè)詞—— Baggins —— 進(jìn)行編碼. (見(jiàn)注2)

1
2
3
4
<strong><em>Baggins</em></strong>
<em><strong>Baggins</strong></em>
<em><strong>Bagg</strong><strong>ins</strong></em>
<em><strong>Bagg</strong></em><strong><em>ins</em></strong>

編輯器應(yīng)該明智的認(rèn)為這些形式是等價(jià)的。你對(duì)這篇文章所進(jìn)行的任何編輯都應(yīng)該對(duì)所有這種形式同等對(duì)待。編寫(xiě)一個(gè)編輯動(dòng)作來(lái)了解所有這些不同的DOM形式是需要令人極其驚訝的技巧.

LeoXu
LeoXu
翻譯于 2周前

0人頂

 翻譯的不錯(cuò)哦!

對(duì)于網(wǎng)上大量的可編輯內(nèi)容的實(shí)現(xiàn),一些不顯眼的字符或者空的span標(biāo)簽可能會(huì)進(jìn)入到HTML中,因此兩個(gè)可編輯內(nèi)容的元素的表現(xiàn)完全不同(即使看起來(lái)是一樣的)。這樣的體驗(yàn)會(huì)激怒用戶(hù),而工程師也很難去調(diào)試。

即使我們知道如何編寫(xiě)一個(gè)表現(xiàn)良好的編輯動(dòng)作,但我們?cè)趺礄z查它呢?如果我們把HTML限制到一些簡(jiǎn)單的標(biāo)簽,證明兩個(gè)表單視覺(jué)上是相等的將。。。非常復(fù)雜。你最好能夠在每個(gè)字符上迭代,分配一個(gè)樣式,并比較結(jié)果。

在理想世界里,我們對(duì)于DOM的“可視編輯”會(huì)有一些高級(jí)的API。每個(gè)操作將保證它的有效性,對(duì)于所有視覺(jué)上相等的頁(yè)面做“相同”的操作。這樣,只要你的編輯器僅僅使用這些API,你就能保證它的有效性。

有效性選擇

DOM和可見(jiàn)內(nèi)容的映射是很丑陋的,但至少是多對(duì)一的關(guān)系。一個(gè)DOM表示有一個(gè)準(zhǔn)確的可見(jiàn)表示。

選擇更加丑陋,因?yàn)橛成涫嵌鄬?duì)多的關(guān)系。

你可以很輕松的看到一個(gè)可見(jiàn)的選擇可以有很多的DOM表示。如果你有HTML,

1
his name was <strong><em>Baggins</em></strong>

那么“Baggins”之前的指針可以在三個(gè)DOM位置之一:在 strong開(kāi)始標(biāo)簽前,在 strong開(kāi)始標(biāo)簽和 em開(kāi)始標(biāo)簽中間,以及在 em開(kāi)始標(biāo)簽之后。如果你把指針?lè)旁凇癇aggins”之前開(kāi)始輸入,你的字符會(huì)是粗體,斜體,或者都不是?

Ley
Ley
翻譯于 2周前

0人頂

 翻譯的不錯(cuò)哦!

更微妙地,一個(gè)DOM選擇可以有多種可視化表示。比如下面這種情況,“well-to-do”在“to-”之后換行,如上圖所展示的。光標(biāo)在第一行的末尾和在第二行開(kāi)頭擁有同樣的DOM位置,但是卻擁有不同的可視化位置。就我所知,我們沒(méi)有辦法讓瀏覽器去優(yōu)先選擇哪一個(gè)可視化位置。當(dāng)我們?cè)O(shè)計(jì)編輯器命令的時(shí)候,我們會(huì)讓選擇操作表現(xiàn)的和看起來(lái)是一樣的。但是那太痛苦了,因?yàn)檫@種映射太混亂了。

junker
junker
翻譯于 2周前

0人頂

 翻譯的不錯(cuò)哦!

封閉并且完整的編輯操作

幾年前的某一天, 我的朋友Julie在Gchat上給我發(fā)了一個(gè)消息:

We can remove Apple Style Span…Oh happy day!

Ryosuke Niwa 在WebKit的博客上發(fā)表了一個(gè)友好的帖子 ,這篇帖子請(qǐng)求移除蘋(píng)果風(fēng)格的span(apple-style-span)。如果你之前讀過(guò)這篇文章的話(huà),那么他提出的許多問(wèn)題聽(tīng)上去很耳熟。WebKit的ContentEditable 編輯器增加許多“bookkeeping”HTML標(biāo)簽,這種標(biāo)簽不會(huì)改變?nèi)魏蔚目梢暬Ч瑑H僅是使編輯器表現(xiàn)的不同。

他也指出WebKit的ContentEditable的實(shí)現(xiàn)必須能夠處理由其他任何的CMS或其他任何的瀏覽器的ContentEditable 的實(shí)現(xiàn)創(chuàng)建的HTML。我們的編輯器在這種生態(tài)環(huán)境下應(yīng)該是一個(gè)好的公民。這意味著我們應(yīng)該制作易讀易懂的HTML。但另一面,我們要意識(shí)到我們的編輯器必須處理那些我們不能在編輯器中創(chuàng)建的拷貝內(nèi)容。

junker
junker
翻譯于 2周前

0人頂

 翻譯的不錯(cuò)哦!

我見(jiàn)過(guò)許多種問(wèn)題,復(fù)現(xiàn)這種問(wèn)題的唯一方式是在Firefox中寫(xiě)文本,然后切換到Chrome中做編輯操作,再然后切回到Firefox中。這對(duì)開(kāi)發(fā)者和用戶(hù)來(lái)說(shuō)是非常令人沮喪的。

一個(gè)好的所見(jiàn)即所得編輯器框架

一個(gè)最基本的 ContentEditable 元素是一個(gè)非常差的編輯器, 因?yàn)樗蚱屏饲懊嫣岬降乃卸ɡ?。那么我們?cè)鯓訕?gòu)建一個(gè)好的所見(jiàn)即所得的編輯器呢?

對(duì)一個(gè)編輯器來(lái)說(shuō),有4個(gè)關(guān)鍵點(diǎn)。

  1. 創(chuàng)建一個(gè)文檔模型,并且能夠用一種簡(jiǎn)單的方式去區(qū)分兩個(gè)模型是否在視覺(jué)上相等

  2. 創(chuàng)建一個(gè)在DOM與我們的模型之間的映射

  3. 在這種模型上能夠定義表現(xiàn)良好的編輯操作

  4. 能夠把所有的按鍵操作和鼠標(biāo)點(diǎn)擊轉(zhuǎn)換成相應(yīng)操作的序列

我會(huì)簡(jiǎn)要的介紹每個(gè)關(guān)鍵點(diǎn)以及我們?cè)鯓訉?duì)他們做出改變。最后,我會(huì)討論瀏覽器工程師怎樣才能把ContentEditable 做的更好,并且去掉這些組件中不好的部分

編輯器模型

編輯器模型有兩個(gè)領(lǐng)域:一連串的段落以及一連串的區(qū)域。

每一個(gè)段落包括下面這些內(nèi)容

  • 文本,一個(gè)普通文本的字符串

  • 標(biāo)記,一連串格式化好的文本范圍,比如“對(duì)位置1到5的字符進(jìn)行加粗”

  • 圖像或嵌入的元數(shù)據(jù)

  • 布局,一種我們?cè)鯓臃胖枚温涞拿枋?

一個(gè)區(qū)域描述一個(gè)子列表段落的背景。

在編輯器中的任何選擇操作都會(huì)被表述成兩個(gè)點(diǎn)。每個(gè)點(diǎn)代表的是一個(gè)段落的索引和那么段落的文本偏移,以及一個(gè)類(lèi)別。大多數(shù)選擇操作都是文本類(lèi)型的選擇。我們也有媒介類(lèi)型的選擇(當(dāng)提示信息顯示在圖片上時(shí))和區(qū)域類(lèi)型的選擇(當(dāng)提示信息顯示在區(qū)域背景上面)。

這種模型的優(yōu)點(diǎn)是如果僅當(dāng)這兩種模型相等時(shí)他們會(huì)有同樣的可視化渲染效果。對(duì)模型的任何改變都能轉(zhuǎn)換到一個(gè)定義很好的可視化改變上來(lái)。

編輯器映射

下面我會(huì)定義DOM空間到這種模型空間的映射。我們把這種映射分成兩種:“室內(nèi)”映射和“室外”映射。

室內(nèi)映射是指我們從編輯器中取出內(nèi)容并且來(lái)回的在DOM空間和這種模型空間進(jìn)行映射。我們希望室內(nèi)映射是一對(duì)一的。

室外映射是指我們從編輯器外獲取HTML,就像用戶(hù)從Word中拷貝HTML到一篇帖子中一樣。我們需要把它轉(zhuǎn)換到我們的段落和區(qū)域模型中。我們希望室外映射是有損的。我們優(yōu)先處理普通文本,然后加粗/傾斜/超鏈接標(biāo)簽,然后圖片以及其他各種各樣的格式。

junker
junker
翻譯于 2周前

0人頂

 翻譯的不錯(cuò)哦!

我們的模型映射到DOM樹(shù)后,看起來(lái)像下面這樣:

1
2
3
4
5
6
<div<!-- root -->
  <section<!-- section -->
    <!-- section-inner -->
    <div class="section-inner layout-column">
      <p>  <!-- paragraph -->
        <strong><em>Baggins</em></strong<!-- text -->

這個(gè)區(qū)域(section)節(jié)點(diǎn)是從區(qū)域模型中產(chǎn)生的,并且會(huì)將背景圖片和顏色應(yīng)用到一連串的段落中。

這個(gè)區(qū)域內(nèi)(section-inner)節(jié)點(diǎn)是根據(jù)段落排版屬性而產(chǎn)生的,并且決定了主列的寬度。對(duì)于大部分段落來(lái)說(shuō),它是狹窄并且居中的。對(duì)于全寬的圖片段落來(lái)說(shuō),它是100%寬的。對(duì)于上面的網(wǎng)格來(lái)說(shuō),它是原始的一般。

下一個(gè)節(jié)點(diǎn)是段落的語(yǔ)義類(lèi)別: P, H2, H3, PRE, FIGURE, BLOCKQUOTE, OL-LI (有序列表項(xiàng)), 和 UL-LI (無(wú)序列表項(xiàng)).

當(dāng)我們把標(biāo)簽類(lèi)別轉(zhuǎn)換到DOM節(jié)點(diǎn)的時(shí)候,我們會(huì)按照類(lèi)別排序它們:A,然后 STRONG,再然后 EM。我們永遠(yuǎn)不會(huì)打印一個(gè)包含錨定的STRONG標(biāo)簽。我們會(huì)拆散它而讓錨定包含STRONG標(biāo)簽。

編輯操作

編輯器主要包括6個(gè)編輯操作:插入段落,移除段落,更新段落,插入?yún)^(qū)域,移除區(qū)域,以及更新區(qū)域。

這些操作表現(xiàn)的會(huì)和描述的那樣。段落操作會(huì)接受一個(gè)段落模型和一個(gè)索引。區(qū)域操作會(huì)接受一個(gè)區(qū)域模型和一個(gè)索引。

所有可能的編輯器內(nèi)容都能夠被一系列的這些操作所表述,并且構(gòu)造這樣一個(gè)序列通常是比較簡(jiǎn)單的。

顯而易見(jiàn),內(nèi)容在這些編輯操作下能夠表現(xiàn)的很好。這些操作是直接應(yīng)用于我們的模型上面的,而不是DOM上面,并且這個(gè)模型能夠更容易地區(qū)分兩件東西在視覺(jué)上是否是相等的。

捕獲編輯操作

當(dāng)你和編輯器交互的時(shí)候,我們必須將你的按鍵操作和鼠標(biāo)點(diǎn)擊操作轉(zhuǎn)換成那6個(gè)操作的一個(gè)序列。

這是最復(fù)雜的部分。我們不會(huì)對(duì)那么多的每種可能按鍵的序列履行職責(zé)。這對(duì)于一個(gè)以英語(yǔ)為語(yǔ)言的用戶(hù)來(lái)說(shuō)是一個(gè)非常巨大的列表,永遠(yuǎn)不考慮非拉丁字符和鍵盤(pán)。

通過(guò)觀(guān)察,我們能夠用常規(guī)的ContentEditable鍵盤(pán)操作枚舉所有對(duì)段落插入和移除的操作方式。他們是:回車(chē)(enter,ctrl-m,等。),刪除(delete,backspace,等。),懸浮輸入(type-over)(在一段選擇的文本上輸入),以及拷貝。所以我們能夠捕獲,取消,以及手動(dòng)將這些鍵盤(pán)事件轉(zhuǎn)換到我們的編輯器內(nèi)部操作上來(lái)。

對(duì)于所有其他鍵盤(pán)事件,我們讓原有的ContentEditable 行為生效。在鍵盤(pán)事件結(jié)束之后,我們把段落的DOM映射回到段落的模型中來(lái),并且和我們之前的模型進(jìn)行比較。如果DOM改變了,我們會(huì)創(chuàng)建一個(gè)新的更新段落操作并且通過(guò)編輯器管線(xiàn)應(yīng)用它,保持DOM和模型同步。

快速捕獲編輯操作

如果我們有無(wú)限計(jì)算的能力,那么直接應(yīng)用這些編輯操作就可以了。我們應(yīng)用這些操作到模型上,重新渲染的整個(gè)頁(yè)面,最后結(jié)束操作。

但是在現(xiàn)實(shí)生活中,對(duì)每個(gè)按鍵操作都重新渲染整個(gè)頁(yè)面是非常慢的。并且你會(huì)看到許多丑陋的閃爍現(xiàn)象,因?yàn)閮?nèi)嵌框架(iframes)和圖片會(huì)一直處于加載中。相反,我們會(huì)對(duì)模型的改變事件進(jìn)行監(jiān)聽(tīng),并且盡最大可能減少對(duì)DOM的改變。

當(dāng)我在寫(xiě)篇文章時(shí),我可以看到Chrome拼寫(xiě)檢查程序在“keypress”單詞下面所加的紅色下劃線(xiàn)在閃爍。這是因?yàn)榫庉嬈髡谕瑫r(shí)對(duì)整個(gè)段落進(jìn)行改變,而不是僅僅改變這個(gè)段落的一小塊。如果我們僅僅對(duì)DOM進(jìn)行相對(duì)很小的改變,那么閃爍就會(huì)消失,但是這樣的代碼會(huì)相對(duì)的更復(fù)雜。

期待將來(lái)有一個(gè)更智能的文本編輯操作

最近有一些來(lái)自Chromium貢獻(xiàn)者 (Levi Weintraub, Julie Parent, and Jelte Liebrand) 的流言說(shuō)這些貢獻(xiàn)者想去基于聚合元素(Polymer Elements)和Shadow DOM特性重做ContentEditable。這個(gè)方案也會(huì)像編輯器一樣去嘗試解決許多同樣高級(jí)架構(gòu)方面的問(wèn)題。

  1. 創(chuàng)建一個(gè)由自定義 聚合元素(Polymer elements)構(gòu)成的編輯器模型

  2. 定義編輯器模型與真實(shí)的具有 Shadow DOM特性的DOM之間的映射

  3. 所有在ContentEditable中的按鍵操作和鼠標(biāo)點(diǎn)擊操作都會(huì)被轉(zhuǎn)換成一種抽象的編輯含義,被表示成像{editIntent: ‘delete’}這樣的JSON對(duì)象。

  4. 聚合元素(Polymer Elements)對(duì)這樣的編輯含義操作定義相應(yīng)的處理方法

如果編輯器能夠獲取某種編輯含義的API,那么我們就能夠拋棄許多轉(zhuǎn)換按鍵操作到抽象編輯操作的自定義代碼了。將我們的段落模型當(dāng)作聚合(Polymer)/ ShadowDOM元素是一件很有趣的嘗試。

ContentEditable是什么

不管我什么時(shí)候向那些從事于文本編輯器工作的人解釋的時(shí)候,他們都認(rèn)為我在玩花招。

“當(dāng)然編輯器要比ContentEditable更棒一些。你錯(cuò)了。ContentEditable努力的去成為一個(gè)通用的所見(jiàn)即所得HTML編輯器。而一般的編輯器放棄了'通用目的'的需求,所以你能夠挑選你想去處理的任何HTML結(jié)構(gòu)?!?

這是事實(shí)。但是確是誤導(dǎo)的。

一個(gè)好的所見(jiàn)即所得編輯器和一個(gè)好的具有通用目的HTML編輯器在理論上是不一致的。不可能把ContentEditable 構(gòu)建成那樣的,因?yàn)樗鼈冊(cè)谛枨笊鲜菦_突的。

junker
junker
翻譯于 1周前

0人頂

 翻譯的不錯(cuò)哦!

Steve Yegge的那篇“The Nonesuch Beast”文章影響了我的想法。 設(shè)計(jì)和UX(用戶(hù)體驗(yàn))問(wèn)題與big-O算法問(wèn)題一樣地棘手。一個(gè)好的WYSIWYG任意HTML編輯器與halting問(wèn)題一樣不可能。

ContentEditable可以挽救。 但它的使命必須改變。 豐富的DOM API像Shadow DOM一樣,ContentEditable可能成為一個(gè)平臺(tái)用來(lái)構(gòu)建新一代的網(wǎng)絡(luò)編輯器。但我們必須把它作為一個(gè)編輯平臺(tái)和API,相對(duì)于獨(dú)立的組件總比什么都自己做要好。

腳注:

  1. 如果你學(xué)過(guò)本科的高等數(shù)學(xué), 一個(gè)良態(tài)的映射是一個(gè)態(tài)射。 那個(gè)單詞感覺(jué)是費(fèi)解的, 還帶來(lái)了額外的包袱,在這里它不能幫助我們。 所以這次我們使用了良態(tài)。

  2. CSS復(fù)雜化這個(gè)討論,和復(fù)雜的編輯算法,它的瀏覽器算法已經(jīng)被實(shí)現(xiàn)。但是它不是一個(gè)徹底的證據(jù)證明,可以用來(lái)證明為什么ContentEditable是可怕的。 一般來(lái)說(shuō),我們忽視CSS, 也會(huì)限制我們對(duì)簡(jiǎn)單HTML的分析。

無(wú)若
無(wú)若
翻譯于 6天前

0人頂

 翻譯的不錯(cuò)哦!

本文中的所有譯文僅用于學(xué)習(xí)和交流目的,轉(zhuǎn)載請(qǐng)務(wù)必注明文章譯者、出處、和本文鏈接
我們的翻譯工作遵照 CC 協(xié)議,如果我們的工作有侵犯到您的權(quán)益,請(qǐng)及時(shí)聯(lián)系我們

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多