2021-05-20

前端開發(fā)規(guī)范

[TOC]

<div STYLE="page-break-after: always;"></div>

一、概述

本規(guī)范旨在為前端程序的開發(fā)者提供規(guī)范化最新的指導(dǎo),可用于程序員個(gè)人編譯環(huán)境以及研發(fā)團(tuán)隊(duì)集成環(huán)境等場(chǎng)合的代碼規(guī)范化檢查。

不管有多少人共同參與同一項(xiàng)目,一定要確保每一行代碼都像是同一個(gè)人編寫的

二、方針

約束等級(jí) 約束效力 強(qiáng)制性
<font color=#f5222d>【強(qiáng)制】</font> 違反該項(xiàng)將被認(rèn)為代碼存在嚴(yán)重缺陷 前端程序團(tuán)隊(duì)必須遵守
<font color=#52c41a>【推薦】</font> 違反該項(xiàng)將被認(rèn)為代碼存在輕微缺陷 根據(jù)具體產(chǎn)品特性的不同,選擇性地遵守
<font color=#1890ff>【參考】</font> 違反該項(xiàng)可被認(rèn)為代碼存在優(yōu)化空間 從產(chǎn)品持續(xù)優(yōu)化及人員技能提升的角度,參考使用

三、環(huán)境要求

  1. <font color="#f5222d">【強(qiáng)制】</font>Node.js 8.9 或更高版本,你可以使用 nvmnvm-windows 在一臺(tái)電腦中管理多個(gè) Node 版本

  2. <font color=#f5222d>【強(qiáng)制】</font>使用 Visual Studio Code (VS Code) 進(jìn)行代碼編寫

  3. <font color=#f5222d>【強(qiáng)制】</font>代碼提交前使用 VS Code 進(jìn)行格式化(不要格式引入的外部文件)

  4. <font color=#f5222d>【強(qiáng)制】</font>規(guī)定 Tab 大小為 2 個(gè)空格,保證在所有環(huán)境下獲得一致展現(xiàn)

    // settings.json
    {
      "editor.tabSize": 2
      // ...
    }
    
  5. <font color=#f5222d>【強(qiáng)制】</font>安裝插件 Vetur( Vue開發(fā)擴(kuò)展及 Vue 文件代碼格式化)

  6. <font color=#f5222d>【強(qiáng)制】</font>安裝插件 Prettier - Code formatter( CSS / Less / JS 等其他文件代碼格式化;Vetur 的格式化基于此插件實(shí)現(xiàn),固可以在所有文件實(shí)現(xiàn)統(tǒng)一的格式化)

  1. <font color=#52c41a>【推薦】</font>使用 Chrome 瀏覽器并安裝 Vue.js devtools 進(jìn)行調(diào)試

四、編碼規(guī)范

4.1 HTML / Template 編碼規(guī)范

語法

  1. <font color=#f5222d>【強(qiáng)制】</font>縮進(jìn)使用兩個(gè)空格代替 Tab

    • 前端代碼層級(jí)較深,使用短縮進(jìn)有利于利用屏幕空間,提升效率
    • 使用兩個(gè)空格代替 Tab 可以保證在所有環(huán)境下獲得一致展現(xiàn)
    <!-- not good -->
    <div>
        <div>bar</div>
    </div>
    
    <!-- good -->
    <div>
      <div>bar</div>
    </div>
    
  2. <font color=#f5222d>【強(qiáng)制】</font>嵌套元素應(yīng)當(dāng)縮進(jìn)一次(即兩個(gè)空格),同層級(jí)縮進(jìn)應(yīng)保持一致

    <!-- not good -->
    <div>
    <div>bar</div>
      <div>bar</div>
    </div>
    
    <!-- good -->
    <div>
      <div>bar</div>
      <div>bar</div>
    </div>
    
  3. <font color=#f5222d>【強(qiáng)制】</font>對(duì)于屬性的定義,使用雙引號(hào),不要使用單引號(hào)

    <!-- not good -->
    <input class='a' type=text>
    
    <!-- good -->
    <input class="a" type="text">
    
  4. <font color=#f5222d>【強(qiáng)制】</font>不要省略可選的結(jié)束標(biāo)簽(closing tag)(如</li></body>

    省略可選的結(jié)束標(biāo)簽,雖不會(huì)違反 H5 規(guī)范;但可能會(huì)造成層級(jí)上的困擾,導(dǎo)致代碼出現(xiàn)無法預(yù)料的問題

    <!-- not good -->
    <h1>h1 text
      <h2>h2 text
    
    <!-- good -->
    <h1>h1 text</h1>
    <h2>h2 text</h2>
    
  5. <font color=#f5222d>【強(qiáng)制】</font>特殊符號(hào)使用 HTML 字符實(shí)體(實(shí)體名稱對(duì)大小寫敏感),常用如下:

    符號(hào) 實(shí)體編碼
    空格 &nbsp;
    ? &copy;
    &yen;
    ? &reg;
    > &gt;
    < &lt;
    & &amp;
  6. <font color=#f5222d>【強(qiáng)制】</font>td / th 要在 tr 里面,li 要在 ul / ol 里面

    <!-- not good -->
    <table>
      <td>test</td>
    </table>
    
    <!-- good -->
    <table>
      <tr>
        <td>test</td>
      </tr>
    </table>
    
  7. <font color=#f5222d>【強(qiáng)制】</font>ul / ol 的直接子元素只能是 li,不能包含其他元素

    <!-- not good -->
    <ul>
      <span>123</span>
      <li>a</li>
      <li>b</li>
    </ul>
    
  8. <font color=#f5222d>【強(qiáng)制】</font>行內(nèi)元素里面不可使用塊級(jí)元素

    a 標(biāo)簽是一個(gè)行內(nèi)元素,行內(nèi)元素里面套了一個(gè) div 的標(biāo)簽,這樣可能會(huì)導(dǎo)致 a 標(biāo)簽無法正常點(diǎn)擊

    <!-- not good -->
    <a href="../test">
      <div></div>
    </a>
    

    可以使用如下代碼進(jìn)行修復(fù):

    <a href="../test" style="display: block">
      <div></div>
    </a>
    
  9. <font color=#f5222d>【強(qiáng)制】</font>不使用自定義標(biāo)簽,會(huì)與Vue組件系統(tǒng)的自定義組件沖突

  10. <font color=#f5222d>【強(qiáng)制】</font>不使用重復(fù)屬性,重復(fù)的屬性只會(huì)取第一個(gè)

    <!-- error -->
    <input class="a" type="text" class="b">
       
    <!-- good -->
    <input class="a b" type="text">
    
  11. <font color=#f5222d>【強(qiáng)制】</font>不要在https的鏈接里寫http的圖片

    只要https的網(wǎng)頁請(qǐng)求了一張http的圖片,就會(huì)導(dǎo)致瀏覽器地址欄左邊的小鎖沒有了,一般不要寫死,寫成根據(jù)當(dāng)前域名的協(xié)議去加載,用//開頭:

    <img src="http://static.chimeroi.com/hello-world.jpg">
    
  12. <font color=#52c41a>【推薦】</font>不要在自閉合(self-closing)元素的尾部添加斜線( HTML5 規(guī)范中說明這是可選的)

    <!-- not good -->
    <img src="logo.png" alt />
       
    <!-- good -->
    <img src="logo.png" alt>
    
  13. <font color=#52c41a>【推薦】</font>不使用屬性設(shè)置樣式(img, table等元素)

    <!-- not good -->
    <img src="test.jpg" alt width="400" height="300">
    
    <!-- good -->
    <img src="test.jpg" style="width:400px;height:300px;">
    
  14. <font color=#1890ff>【參考】</font>自定義屬性要以data-開頭
    自己添加的非標(biāo)準(zhǔn)的屬性要以data-開頭,否則w3c validator會(huì)認(rèn)為是不規(guī)范的

    <!-- not good -->
    <div count="5"></div>
    
    <!-- good -->
    <div data-count="5"></div>
    

HTML5 doctype

<font color=#f5222d>【強(qiáng)制】</font>為每個(gè) HTML 頁面添加標(biāo)準(zhǔn)模式(standard mode)的聲明,確保在每個(gè)瀏覽器中擁有一致的展現(xiàn)

<!DOCTYPE html>

<html>
  ...

語言屬性

<font color=#f5222d>【強(qiáng)制】</font>為每個(gè) HTML 頁面根元素添加 lang 屬性

根據(jù) HTML5 規(guī)范:

強(qiáng)烈建議為 html 根元素指定 lang 屬性,從而為文檔設(shè)置正確的語言。這將有助于語音合成工具確定其所應(yīng)該采用的發(fā)音,有助于翻譯工具確定其翻譯時(shí)所應(yīng)遵守的規(guī)則等等。

<html lang="zh-CN">
  <!-- ... -->
</html>

字符編碼

<font color=#f5222d>【強(qiáng)制】</font>通過聲明一個(gè)明確的字符編碼,讓瀏覽器輕松、快速的確定網(wǎng)頁內(nèi)容渲染方式,通常指定為'UTF-8'

<html>
  <head>
    <meta charset="UTF-8">
  </head>
  ...

引入 CSS 和 JavaScript 文件

<font color=#f5222d>【強(qiáng)制】</font>根據(jù) HTML5 規(guī)范,在引入 CSS 和 JavaScript 文件時(shí)不需要指定 type 屬性,因?yàn)?text/csstext/javascript 分別是它們的默認(rèn)值

<!-- External CSS -->
<link rel="stylesheet" href="code_guide.css">

<!-- In-document CSS -->
<style>
  ...
</style>

<!-- External JS -->
<script src="code_guide.js"></script>

<!-- In-document JS -->
<script>
  ...
</script>

減少標(biāo)簽的數(shù)量

<font color=#52c41a>【推薦】</font>編寫 HTML 代碼時(shí),盡量避免多余的層級(jí)

<!-- not good -->
<span class="avatar">
  <img src="...">
</span>

<!-- good -->
<img class="avatar" src="...">

屬性順序

<font color=#1890ff>【參考】</font>屬性應(yīng)該按照特定的順序出現(xiàn)以保證易讀性

  1. class
  2. id
  3. name
  4. data-*
  5. src, for, type, href, value , max-length, max, min, pattern
  6. placeholder, title, alt
  7. aria-*, role
  8. required, readonly, disabled

語義化

<font color=#1890ff>【參考】</font>盡量遵循 HTML 標(biāo)準(zhǔn)和語義,但是不要以犧牲實(shí)用性為代價(jià);任何時(shí)候都要盡量使用最少的標(biāo)簽并保持最小的復(fù)雜度。

4.2 CSS / Less 編碼規(guī)范

命名

  1. <font color=#f5222d>【強(qiáng)制】</font>類名使用小寫字母,以中劃線分隔

  2. <font color=#f5222d>【強(qiáng)制】</font>id 采用駝峰式命名

  3. <font color=#f5222d>【強(qiáng)制】</font>less 中的變量、函數(shù)、混合等采用駝峰式命名

    @mainFontColor: #444;
    
    #companyName,
    .company-name {
      color: @mainFontColor;
    }
    

語法

  1. <font color=#f5222d>【強(qiáng)制】</font>所有聲明語句都應(yīng)當(dāng)以分號(hào)結(jié)尾
    最后一條聲明語句后面的分號(hào)是可選的,但是,如果省略這個(gè)分號(hào),你的代碼可能更易出錯(cuò)

    /* error */
    .selector {
     font-size: 15px
      color: red
    }
    
    /* not good */
    .selector {
     font-size: 15px;
      color: red
    }
    
    /* good */
    .selector {
     font-size: 15px;
      color: red;
    }
    
  2. <font color=#f5222d>【強(qiáng)制】</font>避免為 0 值指定單位,例如,用 margin: 0; 代替 margin: 0px;

  3. <font color=#f5222d>【強(qiáng)制】</font>為選擇器中的屬性添加雙引號(hào),例如,input[type="text"]
    某些情況下是可選的,但是,為了代碼的一致性,建議都加上雙引號(hào)

    /* not good */
    .selector[type=text] {
      /* ... */
    }
    
    /* good */
    .selector[type="text"] {
      /* ... */
    }
    
  4. <font color=#f5222d>【強(qiáng)制】</font>十六進(jìn)制值應(yīng)該全部小寫,例如,#f3f6fa

  5. <font color=#f5222d>【強(qiáng)制】</font>不出現(xiàn)空的規(guī)則(聲明塊中沒有聲明語句)

  6. <font color=#f5222d>【強(qiáng)制】</font>不要設(shè)置太大的z-index(一個(gè)正常的系統(tǒng)的層級(jí)關(guān)系在 10 以內(nèi)就能完成)

  7. <font color=#f5222d>【強(qiáng)制】</font>多寫注釋,且多使用句子進(jìn)行描述而不是詞語

    /* 為了去除輸入框和表單點(diǎn)擊時(shí)的灰色背景 */
    input, 
    form {
        -webkit-tap-highlight-color:  rgba(255, 255, 255, 0);
    }
    
  8. <font color=#52c41a>【推薦】</font>不要使用*選擇器

  9. <font color=#52c41a>【推薦】</font>適當(dāng)使用:before:after來畫頁面的一些視覺上的輔助性元素,如三角形、短的分隔線、短豎線等,可以減少頁面上沒有用的標(biāo)簽

  10. <font color=#52c41a>【推薦】</font>選擇器不要超過4層(在 Less 中避免嵌套超過 4 層)

  11. <font color=#52c41a>【推薦】</font>用 border: 0; 代替 border: none;

  12. <font color=#52c41a>【推薦】</font>使用簡(jiǎn)寫形式的十六進(jìn)制值,例如,用 #fff 代替 #ffffff

  13. <font color=#52c41a>【推薦】</font>對(duì)于屬性值或顏色參數(shù),省略小于 1 的小數(shù)前面的 0 (例如,.5 代替 0.5;-.5px 代替 -0.5px

代碼風(fēng)格

此處大部分工作將由代碼格式化工具完成(參見環(huán)境要求),一般無需考慮

  1. <font color=#f5222d>【強(qiáng)制】</font>縮進(jìn)使用兩個(gè)空格代替 Tab

  2. <font color=#f5222d>【強(qiáng)制】</font>為選擇器分組時(shí),將單獨(dú)的選擇器單獨(dú)放在一行

    /* not good */
    .selector, .selector-secondary, .selector[type=text] {
      /* ... */
    }
    
    /* good */
    .selector,
    .selector-secondary,
    .selector[type="text"] {
      /* ... */ 
    }
    
  3. <font color=#f5222d>【強(qiáng)制】</font>聲明塊的左花括號(hào)前添加一個(gè)空格

  4. <font color=#f5222d>【強(qiáng)制】</font>聲明塊的右花括號(hào)應(yīng)當(dāng)單獨(dú)成行

  5. <font color=#f5222d>【強(qiáng)制】</font>每條聲明語句的 : 后應(yīng)該插入一個(gè)空格

  6. <font color=#f5222d>【強(qiáng)制】</font>每條樣式聲明應(yīng)該獨(dú)占一行

    /* not good */
    .selector {
     font-size: 15px; color: red;
    }
    
    /* good */
    .selector {
     font-size: 15px;
      color: red;
    }
    
  7. <font color=#f5222d>【強(qiáng)制】</font>對(duì)于以逗號(hào)分隔的屬性值,每個(gè)逗號(hào)后面都應(yīng)該插入一個(gè)空格(例如,box-shadow,transition

    /* not good */
    .selector {
      transition: border .2s,color .3s,padding .4s;
    }
    
    /* good */
    .selector {
      transition: border .2s, color .3s, padding .4s;
    }
    
  8. <font color=#f5222d>【強(qiáng)制】</font>!important前插入一個(gè)空格

  9. <font color=#f5222d>【強(qiáng)制】</font>注釋://后插入一個(gè)空格,/*后插入一個(gè)空格,*/前插入一個(gè)空格

  10. <font color=#f5222d>【強(qiáng)制】</font>Less 的操作符,在圓括號(hào)中的數(shù)學(xué)計(jì)算表達(dá)式的數(shù)值、變量和操作符之間均添加一個(gè)空格

  11. <font color=#52c41a>【推薦】</font>注釋統(tǒng)一用/* */( Less 中也不要用//

樣式兼容性

  1. <font color=#f5222d>【強(qiáng)制】</font>當(dāng)使用一些較新的 CSS3 語法時(shí),應(yīng)注意添加瀏覽器前綴( FAIS 2 打包工具包含 CSS 預(yù)處理,固無需考慮此條)

  2. <font color=#52c41a>【推薦】</font>不要使用 input 的 line-height 來做垂直居中
    設(shè)置 line-height 為一個(gè)很高的值會(huì)導(dǎo)致 Safari 瀏覽器的輸入光標(biāo)變得巨大 (與 line-height 等高)

    /* not good */
    input {
      height: 40px;
      line-height: 40px;
    }
    
    /* good */
    input {
      height: 20px;
      line-height: 20px;
      padding: 10px 0;
    }
    

選擇器權(quán)重(樣式覆蓋)

權(quán)重的基本規(guī)則:

  1. 相同的權(quán)重:以后面出現(xiàn)的選擇器為最后規(guī)則
  2. 不同的權(quán)重,權(quán)重值高則生效

詳細(xì)了解權(quán)重計(jì)算方法

  1. <font color=#f5222d>【強(qiáng)制】</font>非通用樣式使用嵌套方式進(jìn)行編寫,避免影響其他自己不了解樣式,造成樣式覆蓋
  2. <font color=#52c41a>【推薦】</font>Vue 中樣式謹(jǐn)慎使用 scoped,會(huì)影響樣式選擇器性能,請(qǐng)使用第一點(diǎn)進(jìn)行特有樣式編寫
  3. <font color=#52c41a>【推薦】</font>樣式需要修改時(shí),盡量找到原樣式聲明進(jìn)行修改
  4. <font color=#f5222d>【強(qiáng)制】</font>無法修改原樣式聲明時(shí),應(yīng)通過權(quán)重關(guān)系,編寫權(quán)重更高的樣式進(jìn)行覆蓋
  5. <font color=#f5222d>【強(qiáng)制】</font>不使用!important,除非原樣式使用內(nèi)聯(lián)樣式或!important且無法直接修改

聲明簡(jiǎn)寫

  1. <font color=#52c41a>【推薦】</font>當(dāng)你不確定自己寫的屬性會(huì)否影響到其他屬性時(shí),應(yīng)避免使用簡(jiǎn)寫

    /* error */
    .element {
      margin: 0 0 10px;
      background: red;
      background: url("image.jpg");
      border-radius: 3px 3px 0 0;
    }
    
    /* good */
    .element {
      margin-bottom: 10px;
      background-color: red;
      background-image: url("image.jpg");
      border-top-left-radius: 3px;
      border-top-right-radius: 3px;
    }
    
  2. <font color=#52c41a>【推薦】</font>當(dāng)你確定自己的聲明不會(huì)影響到其他屬性時(shí),請(qǐng)使用簡(jiǎn)寫提升代碼簡(jiǎn)潔性

    /* not good */
    .element {
      padding-top: 10px;
      padding-right: 20px;
      padding-bottom: 15px;
      padding-left: 20px;
    }
    
    /* good */
    .element {
      padding: 10px 20px 15px;
    }
    

CSS動(dòng)畫

  1. <font color=#52c41a>【推薦】</font>不要使用all屬性做動(dòng)畫

使用transition做動(dòng)畫的時(shí)候不要使用all所有屬性,在有一些瀏覽器上面可能會(huì)有一些問題,如下:

transition: all 2s linear;

在Safari上面可能會(huì)有一些奇怪的抖動(dòng),正確的做法是要用哪個(gè)屬性做動(dòng)畫就寫哪個(gè),如果有多個(gè)就用隔開,如下代碼所示:

transition: transform 2s linear, opacity 2s linear;
  1. <font color=#52c41a>【推薦】</font>位移動(dòng)畫使用 transform 替代 position (提升動(dòng)畫性能)
  2. <font color=#52c41a>【推薦】</font>使用 CSS 動(dòng)畫替代 JS 動(dòng)畫

聲明順序

<font color=#1890ff>【參考】</font>相關(guān)的屬性聲明按以下順序做分組處理,組之間需要有一個(gè)空行

  1. Positioning(影響其他元素和自身位置相關(guān)聲明)

  2. Box model(自身盒模型相關(guān)聲明)

  3. Typographic(文本相關(guān)聲明)

  4. Visual(自身樣式)

  5. Misc(其他聲明)

    .declaration-order {
      /* Positioning */
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 100;
    
      /* Box-model */
      display: block;
      float: right;
      width: 100px;
      height: 100px;
    
      /* Typography */
      font: normal 13px "Helvetica Neue", sans-serif;
      line-height: 1.5;
      color: #333;
      text-align: center;
    
      /* Visual */
      background-color: #f5f5f5;
      border: 1px solid #e5e5e5;
      border-radius: 3px;
    
      /* Misc */
      opacity: 1;
    }
    

4.3 JavaScript 編碼規(guī)范

命名

  1. <font color=#f5222d>【強(qiáng)制】</font>標(biāo)準(zhǔn)變量采用駝峰式命名(考慮與后臺(tái)交換數(shù)據(jù)的情況,對(duì)象屬性可靈活命名)

  2. <font color=#f5222d>【強(qiáng)制】</font>常量全大寫,用下劃線連接

  3. <font color=#f5222d>【強(qiáng)制】</font>變量名不應(yīng)過短,要能準(zhǔn)確完整地描述該變量所表述的事物

    不好的變量名 好的變量名
    inp input, priceInput
    day1, day2, param1 today, tomorrow
    id userId, orderId
    obj orderData, houseInfos
    tId removeMsgTimerId
    handler submitHandler, searchHandler
  4. <font color=#f5222d>【強(qiáng)制】</font>變量名不要使用計(jì)算機(jī)術(shù)語,如 texareaData,應(yīng)該取和業(yè)務(wù)相關(guān)的名字,如 leaveMsg

  5. <font color=#f5222d>【強(qiáng)制】</font>變量名的對(duì)仗要明確,如 up/down、begin/end、opened/closed、visible/invisible、scource/target

  6. <font color=#f5222d>【強(qiáng)制】</font>變量名使用正確的語法

    不要使用中文拼音,如 shijianchuo 應(yīng)改成 timestamp ;
    如果是復(fù)數(shù)的話加 s,或者加上 List,如 orderList、menuItems;
    而過去式的加上 ed,如 updated/found 等;
    如果正在進(jìn)行的加上 ing,如 calling;

  7. <font color=#52c41a>【推薦】</font>使用臨時(shí)變量時(shí)請(qǐng)結(jié)合實(shí)際需要進(jìn)行變量命名

    有些喜歡取temp和obj之類的變量,如果這種臨時(shí)變量在兩行代碼內(nèi)就用完了,接下來的代碼就不會(huì)再用了,還是可以接受的,如交換數(shù)組的兩個(gè)元素。但是有些人取了個(gè)temp,接下來十幾行代碼都用到了這個(gè)temp,這個(gè)就讓人很困惑了。所以應(yīng)該盡量少用temp類的變量

    // not good
    let temp = 10;
    let leftPosition = currentPosition + temp,
        topPosition = currentPosition - temp;
    
    // good
    let adjustSpace = 10;
    let leftPosition = currentPosition + adjustSpace,
         topPosition = currentPosition - adjustSpace;
    
  8. <font color=#52c41a>【推薦】</font>波爾變量可以結(jié)合實(shí)際語境使用 done/found/successs/ok/available/complete 等修飾詞

    // good
    let ajaxDone = true,
        fileFound = false,
        resourceUpdated = true;
    
  9. <font color=#52c41a>【推薦】</font>波爾變量名應(yīng)使用肯定的布爾變量名,不要使用否定的名詞,如 notOk、notReady,因?yàn)榉穸ǖ脑~取反的時(shí)候就會(huì)比較奇怪,如 if (!notOk)

語法

  1. <font color=#f5222d>【強(qiáng)制】</font>變量不要先使用后聲明

  2. <font color=#f5222d>【強(qiáng)制】</font>不要聲明了變量卻不使用

  3. <font color=#f5222d>【強(qiáng)制】</font>不要在同個(gè)作用域下聲明同名變量

  4. <font color=#f5222d>【強(qiáng)制】</font>一個(gè)函數(shù)作用域中所有的變量聲明盡量提到函數(shù)首部,可根據(jù)代碼進(jìn)行分組,但不允許出現(xiàn)兩個(gè)連續(xù)的變量聲明

    // not good
    let registerForm = null;
    let question = "";
    let calculateResult = 0;
    
    // good
    let registerForm = null,
        question = "",
        calculateResult = 0;
    
  5. <font color=#f5222d>【強(qiáng)制】</font>為了快速知曉變量類型,聲明變量時(shí)要賦值

    // not good
    let registerForm,
        question,
        calculateResult;
    
    // good
    let registerForm = null,
        question = "",
        calculateResult = 0;
    
  6. <font color=#f5222d>【強(qiáng)制】</font>單一函數(shù)的返回值類型要確定(如下無法確定該函數(shù)的最終返回類型)

    // not good
    function calculatePrice(seatCount){
      if (seatCount <= 0) {
         return "";
      } else {
         return seatCount * 79;
      }
    }
    
  7. <font color=#f5222d>【強(qiáng)制】</font>debugger不要出現(xiàn)在提交的代碼里

  8. <font color=#52c41a>【推薦】</font>使用===代替==,!==代替!===會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換,可能會(huì)出現(xiàn)奇怪的結(jié)果)

    null == undefined          //true
    '' == '0'                  //false
    0  == ''                   //true
    0  == '0'                  //true
    ' \t\r\n ' == 0            //true
    new String("abc") == "abc" //true
    new Boolean(true) == true  //true
    true == 1                  //true
    
  9. <font color=#52c41a>【推薦】</font>使用三目運(yùn)算代替簡(jiǎn)單的 if-else

    // not good
    let seatDiscount = 100;
    if (seat < 5) {
      seatDiscount = 90;
    } else if(seat < 10) {
      seatDiscount = 80;
    } else {
      seatDiscount = 70;
    }
    
    // good
    let seatDiscount = seat < 5 ? 90 : seat < 10 ? 80 : 70;
    
  10. <font color=#52c41a>【推薦】</font>使用let定義變量,const定義常量

  11. <font color=#52c41a>【推薦】</font>使用箭頭函數(shù)取代簡(jiǎn)單的函數(shù)

    // not good
    let _this = this;
    setTimeout(function() {
      _this.foo = "bar";
    }, 2000);
    
    // good
    setTimeout(() => this.foo = "bar", 2000);
    
  12. <font color=#52c41a>【推薦】</font>在必要的地方添加非空判斷以提高代碼的穩(wěn)健性

  13. <font color=#52c41a>【推薦】</font>將復(fù)雜的函數(shù)分解成多個(gè)子函數(shù),方便維護(hù)和復(fù)用

代碼風(fēng)格

此處大部分工作將由代碼格式化工具完成(參見環(huán)境要求),一般無需考慮

  1. <font color=#f5222d>【強(qiáng)制】</font>縮進(jìn)使用兩個(gè)空格代替 Tab
  2. <font color=#f5222d>【強(qiáng)制】</font>統(tǒng)一使用雙引號(hào)""(與 Prettier 默認(rèn)格式化配置持一致)
  3. <font color=#f5222d>【強(qiáng)制】</font>以下幾種情況后需加分號(hào);
    • 變量聲明

    • 表達(dá)式

    • return

    • throw

    • break

    • continue

    • do-while

  4. <font color=#f5222d>【強(qiáng)制】</font>以下幾種情況不需要空格:
    • 對(duì)象的屬性名后
    • 前綴一元運(yùn)算符后
    • 后綴一元運(yùn)算符前
    • 函數(shù)調(diào)用括號(hào)前
    • 無論是函數(shù)聲明還是函數(shù)表達(dá)式,'('前不要空格
    • 數(shù)組的'['后和']'前
    • 對(duì)象的'{'后和'}'前
    • 運(yùn)算符'('后和')'前
  5. <font color=#f5222d>【強(qiáng)制】</font>以下幾種情況需要空格:
    • 二元運(yùn)算符前后
    • 三元運(yùn)算符'?:'前后
    • 代碼塊'{'前
    • 下列關(guān)鍵字前:else, while, catch, finally
    • 下列關(guān)鍵字后:if, else, for, while, do, switch, case, try,catch, finally, with, return, typeof
    • 單行注釋'//'后(若單行注釋和代碼同行,則'//'前也需要),多行注釋'*'后
    • 對(duì)象的屬性值前
    • for循環(huán),分號(hào)后留有一個(gè)空格,前置條件如果有多個(gè),逗號(hào)后留一個(gè)空格
    • 無論是函數(shù)聲明還是函數(shù)表達(dá)式,'{'前一定要有空格
    • 函數(shù)的參數(shù)之間

數(shù)組、對(duì)象

  1. <font color=#f5222d>【強(qiáng)制】</font>對(duì)象屬性名不需要加引號(hào)

  2. <font color=#f5222d>【強(qiáng)制】</font>對(duì)象以縮進(jìn)的形式書寫,不要寫在一行

  3. <font color=#f5222d>【強(qiáng)制】</font>數(shù)組中不要存在空元素

  4. <font color=#f5222d>【強(qiáng)制】</font>不要用for in循環(huán)數(shù)組

  5. <font color=#52c41a>【推薦】</font>數(shù)組、對(duì)象最后不要有逗號(hào)

    // not good
    let a = {
      'b': 1
    };
    
    let a = { b: 1 };
    
    let a = {
      b: 1,
      c: 2,
    };
    
    // good
    let a = {
      b: 1,
      c: 2
    };
    

使用 null

<font color=#f5222d>【強(qiáng)制】</font>正確使用 null

適用場(chǎng)景:

  • 初始化一個(gè)將來可能被賦值為對(duì)象的變量
  • 與已經(jīng)初始化的變量做比較
  • 作為一個(gè)參數(shù)為對(duì)象的函數(shù)的調(diào)用傳參
  • 作為一個(gè)返回對(duì)象的函數(shù)的返回值
  1. 不要用null來判斷函數(shù)調(diào)用時(shí)有無傳參

  2. 不要與未初始化的變量做比較

    // not good
    function test(a, b) {
      if (b === null) {
        // not mean b is not supply
        // ...
      }
    }
    
    let a;
    
    if (a === null) {
      // ...
    }
    
    // good
    let a = null;
    
    if (a === null) {
      // ...
    }
    

使用 undefined

<font color=#f5222d>【強(qiáng)制】</font>正確使用 undefined

  1. 不要給變量賦值 undefined(undefined 本身就表示一個(gè)變量未定義)

  2. 不要直接使用 undefined 進(jìn)行變量判斷

  3. 使用typeof和字符串 'undefined' 對(duì)變量進(jìn)行判斷

    // not good
    if (person === undefined) {
      // ...
    }
    
    // good
    if (typeof person === 'undefined') {
      // ...
    }
    

文檔注釋

<font color=#1890ff>【參考】</font>各類標(biāo)簽 @param, @method 等請(qǐng)參考 usejsdoc JSDoc Guide;

建議在以下情況下使用:

  • 所有常量
  • 所有函數(shù)
  • 所有類
/**
 * @func
 * @desc 一個(gè)帶參數(shù)的函數(shù)
 * @param {string} a - 參數(shù)a
 * @param {number} b=1 - 參數(shù)b默認(rèn)值為1
 * @param {string} c=1 - 參數(shù)c有兩種支持的取值</br>1—表示x</br>2—表示xx
 * @param {object} d - 參數(shù)d為一個(gè)對(duì)象
 * @param {string} d.e - 參數(shù)d的e屬性
 * @param {string} d.f - 參數(shù)d的f屬性
 * @param {object[]} g - 參數(shù)g為一個(gè)對(duì)象數(shù)組
 * @param {string} g.h - 參數(shù)g數(shù)組中一項(xiàng)的h屬性
 * @param {string} g.i - 參數(shù)g數(shù)組中一項(xiàng)的i屬性
 * @param {string} [j] - 參數(shù)j是一個(gè)可選參數(shù)
 */
function foo(a, b, c, d, g, j) {
  // ...
}

4.4 Vue 組件編碼規(guī)范

命名

  1. <font color=#f5222d>【強(qiáng)制】</font>組件名應(yīng)該始終是多個(gè)單詞的,根組件 App 除外

    // not good
    Vue.component('todo', {
      // ...
    })
    export default {
      name: 'Todo',
      // ...
    }
    
    // good
    Vue.component('todo-item', {
      // ...
    })
    export default {
      name: 'TodoItem',
      // ...
    }
    
  2. <font color=#f5222d>【強(qiáng)制】</font>單文件組件的文件名應(yīng)該要么始終是單詞大寫開頭( PascalCase ),要么始終是橫線連接( kebab-case )

    // not good
    components/
    |- mycomponent.vue
    
    components/
    |- myComponent.vue
    
    // good
    components/
    |- MyComponent.vue
    
    components/
    |- my-component.vue
    
  3. <font color=#52c41a>【推薦】</font>應(yīng)用特定樣式和約定的基礎(chǔ)組件 (也就是展示類的、無邏輯的或無狀態(tài)的組件) 應(yīng)該全部以一個(gè)特定的前綴開頭,比如 Base、App 或 V

    // not good
    components/
    |- MyButton.vue
    |- VueTable.vue
    |- Icon.vue
    
    // good
    components/
    |- BaseButton.vue
    |- BaseTable.vue
    |- BaseIcon.vue
    
    components/
    |- AppButton.vue
    |- AppTable.vue
    |- AppIcon.vue
    
    components/
    |- VButton.vue
    |- VTable.vue
    |- VIcon.vue
    
  4. <font color=#52c41a>【推薦】</font>只應(yīng)該擁有單個(gè)活躍實(shí)例的單例組件應(yīng)該以 The 前綴命名,以示其唯一性

    單例組件不意味著組件只可用于一個(gè)單頁面,而是每個(gè)頁面只使用一次。這些組件永遠(yuǎn)不接受任何 prop,因?yàn)樗鼈兪菫槟愕膽?yīng)用定制的,而不是它們?cè)谀愕膽?yīng)用中的上下文。如果你發(fā)現(xiàn)有必要添加 prop,那就表明這實(shí)際上是一個(gè)可復(fù)用的組件,只是目前在每個(gè)頁面里只使用一次

    // not good
    components/
    |- Heading.vue
    |- MySidebar.vue
    
    // good
    components/
    |- TheHeading.vue
    |- TheSidebar.vue
    
  5. <font color=#f5222d>【強(qiáng)制】</font>和父組件緊密耦合的子組件應(yīng)該以父組件名作為前綴命名

    如果一個(gè)組件只在某個(gè)父組件的場(chǎng)景下有意義,這層關(guān)系應(yīng)該體現(xiàn)在其名字上。因?yàn)榫庉嬈魍ǔ?huì)按字母順序組織文件,所以這樣做可以把相關(guān)聯(lián)的文件排在一起

    // not good
    components/
    |- TodoList.vue
    |- TodoItem.vue
    |- TodoButton.vue
    components/
    |- SearchSidebar.vue
    |- NavigationForSearchSidebar.vue
    
    //good
    components/
    |- TodoList.vue
    |- TodoListItem.vue
    |- TodoListItemButton.vue
    components/
    |- SearchSidebar.vue
    |- SearchSidebarNavigation.vue
    
  6. <font color=#f5222d>【強(qiáng)制】</font>組件名應(yīng)該以高級(jí)別的 (通常是一般化描述的) 單詞開頭,以描述性的修飾詞結(jié)尾

    // not good
    components/
    |- ClearSearchButton.vue
    |- ExcludeFromSearchInput.vue
    |- LaunchOnStartupCheckbox.vue
    |- RunSearchButton.vue
    |- SearchInput.vue
    |- TermsCheckbox.vue
    
    // good
    components/
    |- SearchButtonClear.vue
    |- SearchButtonRun.vue
    |- SearchInputQuery.vue
    |- SearchInputExcludeGlob.vue
    |- SettingsCheckboxTerms.vue
    |- SettingsCheckboxLaunchOnStartup.vue
    
  7. <font color=#52c41a>【推薦】</font>組件名應(yīng)該傾向于完整單詞而不是縮寫

    // not good
    components/
    |- SdSettings.vue
    |- UProfOpts.vue
    
    // good
    components/
    |- StudentDashboardSettings.vue
    |- UserProfileOptions.vue
    

語法

  1. <font color=#f5222d>【強(qiáng)制】</font>組件的 data 必須是一個(gè)函數(shù)(除了 new Vue 外的任何地方)

    // not good
    export default {
      data: {
        foo: 'bar'
      }
    }
    
    // good
    export default {
      data () {
        return {
          foo: 'bar'
        }
      }
    }
    
  2. <font color=#f5222d>【強(qiáng)制】</font>prop 的定義應(yīng)該盡量詳細(xì),至少需要指定其類型

    // not good
    // 這樣做只有開發(fā)原型系統(tǒng)時(shí)可以接受
    props: ['status']
    
    // good
    props: {
      status: String
    }
    
    // better
    props: {
      status: {
        type: String,
        required: true,
        validator: function (value) {
          return [
            'syncing',
            'synced',
            'version-conflict',
            'error'
          ].indexOf(value) !== -1
        }
      }
    }
    
  3. <font color=#f5222d>【強(qiáng)制】</font>為 v-for 設(shè)置鍵值;在組件上總是必須用 key 配合 v-for,以便維護(hù)內(nèi)部組件及其子樹的狀態(tài)

    在組件上總是必須用 key 配合 v-for,以便維護(hù)內(nèi)部組件及其子樹的狀態(tài)

  4. <font color=#f5222d>【強(qiáng)制】</font>不要把 v-ifv-for 同時(shí)用在同一個(gè)元素上(大部分時(shí)候你可以使用計(jì)算屬性實(shí)現(xiàn))

    <!-- not good -->
    <ul>
      <li
        v-for="user in users"
        v-if="user.isActive"
        :key="user.id"
      >
        {{ user.name }}
      </li>
    </ul>
    
    <!-- good -->
    <ul>
      <li
        v-for="user in activeUsers"
        :key="user.id"
      >
        {{ user.name }}
      </li>
    </ul>
    
  5. <font color=#f5222d>【強(qiáng)制】</font>自閉合組件在單文件組件、字符串模板和 JSX 中沒有內(nèi)容的組件應(yīng)該是自閉合的;但在 DOM 模板里不要這樣做

    <!-- not good -->
    <!-- 在單文件組件、字符串模板和 JSX 中 -->
    <MyComponent></MyComponent>
    <!-- 在 DOM 模板中 -->
    <my-component/>
    
    <!-- good -->
    <!-- 在單文件組件、字符串模板和 JSX 中 -->
    <MyComponent/>
    <!-- 在 DOM 模板中 -->
    <my-component></my-component>
    
  6. <font color=#f5222d>【強(qiáng)制】</font>模版中的組件名大小寫在單文件組件和字符串模板中組件名應(yīng)該總是 PascalCase 的;但是在 DOM 模板中總是 kebab-case 的

    <!-- not good -->
    <!-- 在單文件組件和字符串模板中 -->
    <mycomponent/>
    <!-- 在單文件組件和字符串模板中 -->
    <myComponent/>
    <!-- 在 DOM 模板中 -->
    <MyComponent></MyComponent>
    
    <!-- good -->
    <!-- 在單文件組件和字符串模板中 -->
    <MyComponent/>
    <!-- 在 DOM 模板中 -->
    <my-component></my-component>
    

    亦或者

    <!-- 在所有地方 -->
    <my-component></my-component>
    
  7. <font color=#f5222d>【強(qiáng)制】</font>JS/JSX 中的組件名應(yīng)該始終是 PascalCase 的

    // not good
    Vue.component('myComponent', {
      // ...
    })
    import myComponent from './MyComponent.vue'
    export default {
      name: 'myComponent',
      // ...
    }
    export default {
      name: 'my-component',
      // ...
    }
    
    // good
    Vue.component('MyComponent', {
      // ...
    })
    import MyComponent from './MyComponent.vue'
    export default {
      name: 'MyComponent',
      // ...
    }
    
  8. <font color=#52c41a>【推薦】</font>Prop 名大小寫,在聲明 prop 的時(shí)候,其命名應(yīng)該始終使用 camelCase,而在模板和 JSX 中應(yīng)該始終使用 kebab-case

    // not good
    props: {
      'greeting-text': String
    }
    <WelcomeMessage greetingText="hi"/>
    
    // good
    props: {
      greetingText: String
    }
    <WelcomeMessage greeting-text="hi"/>
    
  9. <font color=#52c41a>【推薦】</font>多個(gè)特性的元素應(yīng)該分多行撰寫,每個(gè)特性一行(此項(xiàng) Vetur 插件會(huì)自動(dòng)根據(jù)行寬閾值進(jìn)行自動(dòng)折行處理,一般無需考慮)

    <!-- not good -->
    <img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
    <MyComponent foo="a" bar="b" baz="c"/>
    
    <!-- good -->
    <img
      src="https://vuejs.org/images/logo.png"
      alt="Vue Logo"
    >
    <MyComponent
      foo="a"
      bar="b"
      baz="c"
    />
    
  10. <font color=#f5222d>【強(qiáng)制】</font>組件模板應(yīng)該只包含簡(jiǎn)單的表達(dá)式,復(fù)雜的表達(dá)式則應(yīng)該重構(gòu)為計(jì)算屬性或方法

    // not good
    {{
      fullName.split(' ').map(function (word) {
        return word[0].toUpperCase() + word.slice(1)
      }).join(' ')
    }}
    
    // good
    // 在模板中
    {{ normalizedFullName }}
    // 復(fù)雜表達(dá)式已經(jīng)移入一個(gè)計(jì)算屬性
    computed: {
      normalizedFullName: function () {
        return this.fullName.split(' ').map(function (word) {
          return word[0].toUpperCase() + word.slice(1)
        }).join(' ')
      }
    }
    
  11. <font color=#52c41a>【推薦】</font>應(yīng)該把復(fù)雜計(jì)算屬性分割為盡可能多的更簡(jiǎn)單的屬性

    // not good
    computed: {
      finalPrice: function () {
        var basePrice = this.manufactureCost / (1 - this.profitMargin)
        return (
          basePrice -
          basePrice * (this.discountPercent || 0)
        )
      }
    }
    
    // good
    computed: {
      basePrice: function () {
        return this.manufactureCost / (1 - this.profitMargin)
      },
      discount: function () {
        return this.basePrice * (this.discountPercent || 0)
      },
      finalPrice: function () {
        return this.basePrice - this.discount
      }
    }
    
  12. <font color=#f5222d>【強(qiáng)制】</font>非空 HTML 特性值應(yīng)該始終帶引號(hào)

    <!-- not good -->
    <input type=text>
    <AppSidebar :style={width:sidebarWidth+'px'}>
    
    <!-- good -->
    <input type="text">
    <AppSidebar :style="{ width: sidebarWidth + 'px' }">
    
  13. <font color=#f5222d>【強(qiáng)制】</font>可簡(jiǎn)寫指令需要縮寫 (用 : 表示 v-bind: 和用 @ 表示 v-on:)

代碼風(fēng)格

此處大部分工作將由代碼格式化工具完成(參見環(huán)境要求),一般無需考慮

具體要求見 4.1 ,4.2,4.3 中代碼風(fēng)格部分

組件/實(shí)例的選項(xiàng)的順序

<font color=#1890ff>【參考】</font>組件/實(shí)例的選項(xiàng)應(yīng)該有統(tǒng)一的順序,這是我們推薦的組件選項(xiàng)默認(rèn)順序:

  1. 副作用 (觸發(fā)組件外的影響)
    • el
  2. 全局感知 (要求組件以外的知識(shí))
    • name
    • parent
  3. 組件類型 (更改組件的類型)
    • functional
  4. 模板修改器 (改變模板的編譯方式)
    • delimiters
    • comments
  5. 模板依賴 (模板內(nèi)使用的資源)
    • components
    • directives
    • filters
  6. 組合 (向選項(xiàng)里合并屬性)
    • extends
    • mixins
  7. 接口 (組件的接口)
    • inheritAttrs
    • model
    • props/propsData
  8. 本地狀態(tài) (本地的響應(yīng)式屬性)
    • data
    • computed
  9. 事件 (通過響應(yīng)式事件觸發(fā)的回調(diào))
    • watch
    • 生命周期鉤子 (按照它們被調(diào)用的順序)
      • beforeCreate
      • created
      • beforeMount
      • mounted
      • beforeUpdate
      • updated
      • activated
      • deactivated
      • beforeDestroy
      • destroyed
  10. 非響應(yīng)式的屬性 (不依賴響應(yīng)系統(tǒng)的實(shí)例屬性)
    • methods
  11. 渲染 (組件輸出的聲明式描述)
    • template/render
    • renderError

元素特性的順序

<font color=#1890ff>【參考】</font>元素 (包括組件) 的特性應(yīng)該有統(tǒng)一的順序,這是我們?yōu)樵靥匦酝扑]的默認(rèn)順序:

  1. 定義 (提供組件的選項(xiàng))
    • is
  2. 列表渲染 (創(chuàng)建多個(gè)變化的相同元素)
    • v-for
  3. 條件渲染 (元素是否渲染/顯示)
    • v-if
    • v-else-if
    • v-else
    • v-show
    • v-cloak
  4. 渲染方式 (改變?cè)氐匿秩痉绞?
    • v-pre
    • v-once
  5. 全局感知 (需要超越組件的知識(shí))
    • id
  6. 唯一的特性 (需要唯一值的特性)
    • ref
    • key
    • slot
  7. 雙向綁定 (把綁定和事件結(jié)合起來)
    • v-model
  8. 其它特性 (所有普通的綁定或未綁定的特性)
  9. 事件 (組件事件監(jiān)聽器)
    • v-on
  10. 內(nèi)容 (覆寫元素的內(nèi)容)
    • v-html
    • v-text

單文件組件的頂級(jí)元素的順序

<font color=#f5222d>【強(qiáng)制】</font>單文件組件應(yīng)該總是按照 <template><script><style> 的標(biāo)簽順序

<!-- good -->
<!-- ComponentA.vue -->
<template>...</template>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

隱性的父子組件通信

<font color=#f5222d>【強(qiáng)制】</font>應(yīng)該優(yōu)先通過 prop 和事件進(jìn)行父子組件之間的通信,而不是 this.$parent 或改變 prop。

一個(gè)理想的 Vue 應(yīng)用是 prop 向下傳遞,事件向上傳遞的。遵循這一約定會(huì)讓你的組件更易于理解。然而,在一些邊界情況下 prop 的變更或 this.$parent 能夠簡(jiǎn)化兩個(gè)深度耦合的組件。

問題在于,這種做法在很多簡(jiǎn)單的場(chǎng)景下可能會(huì)更方便。但請(qǐng)當(dāng)心,不要為了一時(shí)方便 (少寫代碼) 而犧牲數(shù)據(jù)流向的簡(jiǎn)潔性 (易于理解)。

非 Flux 的全局狀態(tài)管理

<font color=#f5222d>【強(qiáng)制】</font>應(yīng)該優(yōu)先通過 Vuex 管理全局狀態(tài),而不是通過 this.$root 或一個(gè)全局事件總線。

通過 this.$root 和/或全局事件總線管理狀態(tài)在很多簡(jiǎn)單的情況下都是很方便的,但是并不適用于絕大多數(shù)的應(yīng)用。Vuex 提供的不僅是一個(gè)管理狀態(tài)的中心區(qū)域,還是組織、追蹤和調(diào)試狀態(tài)變更的好工具。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 自定義屬性目的: 是為了保存并使用數(shù)據(jù)。有些數(shù)據(jù)可以保存到頁面中而不用保存到數(shù)據(jù)庫中 設(shè)置自定義屬性 elemen...
    黑云閱讀 384評(píng)論 0 1
  • 1.內(nèi)存中棧、堆和方法區(qū)的用法。 棧:基本數(shù)據(jù)類型變量、對(duì)象的引用、函數(shù)調(diào)用的現(xiàn)場(chǎng)保存;堆:new關(guān)鍵字和構(gòu)造器創(chuàng)...
    不要夜空霓虹的繁榮閱讀 232評(píng)論 0 0
  • 1. HTML 1. 必考:你是如何理解 HTML 語義化的? 荒野階段:最開始是 PHP 后端寫 HTML,不會(huì)...
    Qingelin閱讀 763評(píng)論 0 0
  • (一)命名規(guī)范 1.1.1項(xiàng)目命名 全部采用小寫方式,以中劃線分隔。 正例:mall-management-sys...
    良辰_147f閱讀 493評(píng)論 0 1
  • 彩排完,天已黑
    劉凱書法閱讀 4,497評(píng)論 1 3

友情鏈接更多精彩內(nèi)容